Skip to content

[WIP][Python] Unify maps used for numpy to cpp conversion #19321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,42 +56,33 @@
\endpythondoc
"""

import sys

import cppyy

from . import pythonization

Check failure on line 63 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_rvec.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_rvec.py:59:1: I001 Import block is un-sorted or un-formatted

_array_interface_dtype_map = {
"Long64_t": "i",
"ULong64_t": "u",
"double": "f",
"float": "f",
"int": "i",
"long": "i",
"unsigned char": "b",
"unsigned int": "u",
"unsigned long": "u",

_numpy_dtype_typeinfo_map = {
"i1": {"typedef": "Char_t", "cpp": "char"},
"u1": {"typedef": "UChar_t", "cpp": "unsigned char"},
"i2": {"typedef": "Short_t", "cpp": "short"},
"u2": {"typedef": "UShort_t", "cpp": "unsigned short"},
"i4": {"typedef": "Int_t", "cpp": "int"},
"u4": {"typedef": "UInt_t", "cpp": "unsigned int"},
"i8": {"typedef": "Long64_t", "cpp": "long long"},
"u8": {"typedef": "ULong64_t", "cpp": "unsigned long long"},
"f4": {"typedef": "Float_t", "cpp": "float"},
"f8": {"typedef": "Double_t", "cpp": "double"},
"b1": {"typedef": "Bool_t", "cpp": "bool"}
}


def _get_cpp_type_from_numpy_type(dtype):
cpptypes = {
"i2": "Short_t",
"u2": "UShort_t",
"i4": "int",
"u4": "unsigned int",
"i8": "Long64_t",
"u8": "ULong64_t",
"f4": "float",
"f8": "double",
"b1": "bool",
}

if dtype not in cpptypes:
if dtype not in _numpy_dtype_typeinfo_map:
raise RuntimeError("Object not convertible: Python object has unknown data-type '" + dtype + "'.")

return cpptypes[dtype]
return _numpy_dtype_typeinfo_map[dtype]['cpp']


def _AsRVec(arr):
Expand Down Expand Up @@ -160,10 +151,11 @@

def get_array_interface(self):
cppname = type(self).__cpp_name__
for dtype in _array_interface_dtype_map:
if cppname.endswith("<{}>".format(dtype)):
dtype_numpy = _array_interface_dtype_map[dtype]
dtype_size = cppyy.sizeof(dtype)
for np_dtype, type_info in _numpy_dtype_typeinfo_map.items():
root_typedef = type_info["typedef"]
cpp_type = type_info["cpp"]
if cppname.endswith("<{}>".format(root_typedef)) or cppname.endswith("<{}>".format(cpp_type)):
dtype_numpy = np_dtype
endianness = "<" if sys.byteorder == "little" else ">"
size = self.size()
# Numpy breaks for data pointer of 0 even though the array is empty.
Expand All @@ -174,14 +166,17 @@
pointer = cppyy.ll.addressof(self.data())
return {
"shape": (size,),
"typestr": "{}{}{}".format(endianness, dtype_numpy, dtype_size),
"typestr": "{}{}".format(endianness, dtype_numpy),
"version": 3,
"data": (pointer, False),
}


def add_array_interface_property(klass, name):
if True in [name.endswith("<{}>".format(dtype)) for dtype in _array_interface_dtype_map]:
if any(
name.endswith(f"<{type_info['typedef']}>") or name.endswith(f"<{type_info['cpp']}>")
for type_info in _numpy_dtype_typeinfo_map.values()
):
klass.__array_interface__ = property(get_array_interface)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
# For the licensing terms see $ROOTSYS/LICENSE. #
# For the list of contributors see $ROOTSYS/README/CREDITS. #
################################################################################
from .. import pythonization
from .._rvec import _array_interface_dtype_map, _get_cpp_type_from_numpy_type
from .._rvec import _numpy_dtype_typeinfo_map, _get_cpp_type_from_numpy_type
import cppyy
import sys

Check failure on line 13 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:10:1: I001 Import block is un-sorted or un-formatted


def _AsRTensor(arr):
Expand All @@ -24,9 +24,9 @@
PyObject. The RTensor takes the data pointer and the shape from the array
interface dictionary.
"""
import ROOT
import math
import platform

Check failure on line 29 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F401)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:29:12: F401 `platform` imported but unused

Check failure on line 29 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:27:5: I001 Import block is un-sorted or un-formatted

# Get array interface of object
interface = arr.__array_interface__
Expand All @@ -36,7 +36,7 @@

# Get the size of the contiguous memory
shape = interface["shape"]
size = math.prod(shape) if len(shape) > 0 else 0

Check failure on line 39 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (F841)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:39:5: F841 Local variable `size` is assigned to but never used

# Get the typestring and properties thereof
typestr = interface["typestr"]
Expand Down Expand Up @@ -85,8 +85,15 @@
idx1 = cppname.find("RTensor<")
idx2 = cppname.find(",", idx1)
dtype = cppname[idx1 + 8 : idx2]
dtype_numpy = _array_interface_dtype_map[dtype]
dtype_size = cppyy.sizeof(dtype)
for numpy_dtype, type_info in _numpy_dtype_typeinfo_map.items():
if dtype == type_info["cpp"] or dtype == type_info["typedef"]:
dtype_numpy = numpy_dtype
dtype_size = cppyy.sizeof(dtype)
break

if dtype_numpy:
raise RuntimeError(f"Unsupported dtype '{dtype}' found in RTensor.")

endianness = "<" if sys.byteorder == "little" else ">"
shape = self.GetShape()
strides = self.GetStrides()
Expand All @@ -98,7 +105,7 @@
return {
"shape": tuple(s for s in shape),
"strides": tuple(s * dtype_size for s in strides),
"typestr": "{}{}{}".format(endianness, dtype_numpy, dtype_size),
"typestr": "{}{}".format(endianness, dtype_numpy),
"version": 3,
"data": (pointer, False),
}
Expand All @@ -113,7 +120,10 @@
klass: class to be pythonized
name: string containing the name of the class
"""
if True in [name.find("RTensor<{},".format(dtype)) != -1 for dtype in _array_interface_dtype_map]:
if any(
("RTensor<{},".format(type_info["cpp"]) in name) or ("RTensor<{},".format(type_info["typedef"]) in name)
for type_info in _numpy_dtype_typeinfo_map.values()
):
klass.__array_interface__ = property(get_array_interface)


Expand All @@ -140,13 +150,13 @@
# Convert negative indices and Nones
isSlice = False
for i, x in enumerate(idx):
if type(x) == slice:

Check failure on line 153 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E721)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:153:12: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
isSlice = True
start = 0 if x.start is None else x.start
stop = shape[i] if x.stop is None else x.stop
if stop < 0:
stop += shape[i]
if x.step != None:

Check failure on line 159 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E711)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:159:26: E711 Comparison to `None` should be `cond is not None`
raise Exception("RTensor does not support slices with step size unequal 1.")
idx[i] = slice(start, stop, None)
else:
Expand All @@ -158,7 +168,7 @@
idxVec = cppyy.gbl.std.vector("vector<size_t>")(len(idx))
for i, x in enumerate(idx):
idxVec[i].resize(2)
if type(x) == slice:

Check failure on line 171 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (E721)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_tmva/_rtensor.py:171:16: E721 Use `is` and `is not` for type comparisons, or `isinstance()` for isinstance checks
idxVec[i][0] = x.start
idxVec[i][1] = x.stop
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@
\endpythondoc
"""

from ROOT.libROOTPythonizations import GetBranchAttr, BranchPyz
from ._rvec import _array_interface_dtype_map, _get_cpp_type_from_numpy_type
from ._rvec import _get_cpp_type_from_numpy_type
from . import pythonization
from ROOT._pythonization._memory_utils import _should_give_up_ownership, _constructor_releasing_ownership, _SetDirectory_SetOwnership

Check failure on line 165 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_ttree.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_ttree.py:162:1: I001 Import block is un-sorted or un-formatted

# TTree iterator
def _TTree__iter__(self):
Expand All @@ -181,8 +181,8 @@
"""Helper for the SetBranchAddress pythonization, extracting the relevant
address from a Python object if possible.
"""
import cppyy
import ctypes

Check failure on line 185 in bindings/pyroot/pythonizations/python/ROOT/_pythonization/_ttree.py

View workflow job for this annotation

GitHub Actions / ruff

Ruff (I001)

bindings/pyroot/pythonizations/python/ROOT/_pythonization/_ttree.py:184:5: I001 Import block is un-sorted or un-formatted

is_leaf_list = branch.IsA() is cppyy.gbl.TBranch.Class()

Expand Down
Loading