numbox 0.2.6__py3-none-any.whl → 0.2.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of numbox might be problematic. Click here for more details.

numbox/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.2.6'
1
+ __version__ = '0.2.7'
@@ -7,20 +7,13 @@ from numba.extending import intrinsic # noqa: F401
7
7
  from types import FunctionType as PyFunctionType
8
8
  from typing import List, Optional, Tuple
9
9
 
10
+ from numbox.utils.standard import make_params_strings
11
+
10
12
 
11
13
  def make_proxy_name(name):
12
14
  return f'__{name}'
13
15
 
14
16
 
15
- def make_params_strings(func):
16
- func_params = inspect.signature(func).parameters
17
- func_params_str = ', '.join(
18
- [k if v.default == inspect._empty else f'{k}={v.default}' for k, v in func_params.items()]
19
- )
20
- func_names_params_str = ', '.join(func_params.keys())
21
- return func_params_str, func_names_params_str
22
-
23
-
24
17
  def proxy(sig, jit_options: Optional[dict] = None):
25
18
  """ Create a proxy for the decorated function `func` with the given signature(s) `sig`.
26
19
 
@@ -1,5 +1,5 @@
1
1
  from collections import namedtuple
2
- from hashlib import md5
2
+ from hashlib import sha256
3
3
  from inspect import getfile, getmodule, getsource
4
4
  from io import StringIO
5
5
  from itertools import chain
@@ -102,7 +102,7 @@ def _derived_line(
102
102
  sources_ = sources_ + ", " if "," not in sources_ else sources_
103
103
  ty_ = get_ty(derived_)
104
104
  derive_func = derived_.derive
105
- derive_hashes.append(md5(getsource(derive_func).encode("utf-8")).hexdigest())
105
+ derive_hashes.append(sha256(getsource(derive_func).encode("utf-8")).hexdigest())
106
106
  derive_ = _derived_cres(ty_, derived_.sources, derive_func, jit_options)
107
107
  derive_name = f"{name_}_derive"
108
108
  init_name = f"{name_}_init"
@@ -115,7 +115,7 @@ def _derived_line(
115
115
 
116
116
  def code_block_hash(code_txt: str):
117
117
  """ Re-compile and re-save cache when source code has changed. """
118
- return md5(code_txt.encode("utf-8")).hexdigest()
118
+ return sha256(code_txt.encode("utf-8")).hexdigest()
119
119
 
120
120
 
121
121
  def _infer_end_and_derived_nodes(spec: SpecTy, all_inputs_: Dict[str, Type], all_derived_: Dict[str, Type]):
numbox/utils/highlevel.py CHANGED
@@ -1,4 +1,7 @@
1
1
  import hashlib
2
+ import re
3
+ from inspect import getfile, getmodule, getsource
4
+ from io import StringIO
2
5
  from numba import njit
3
6
  from numba.core.itanium_mangler import mangle_type_or_value
4
7
  from numba.core.types import Type
@@ -6,6 +9,17 @@ from numba.core.types.functions import Dispatcher
6
9
  from numba.core.types.function_type import CompileResultWAP
7
10
  from numba.core.typing.templates import Signature
8
11
  from numba.experimental.function_type import FunctionType
12
+ from numba.experimental.structref import define_boxing, new, StructRefProxy
13
+ from numba.extending import overload, overload_method
14
+ from textwrap import dedent, indent
15
+ from typing import Callable, Dict, Iterable, Optional
16
+
17
+ from numbox.core.configurations import default_jit_options
18
+ from numbox.utils.standard import make_params_strings
19
+
20
+
21
+ def _file_anchor():
22
+ raise NotImplementedError
9
23
 
10
24
 
11
25
  def cres(sig, **kwargs):
@@ -32,7 +46,164 @@ def determine_field_index(struct_ty, field_name):
32
46
 
33
47
  def hash_type(ty: Type):
34
48
  mangled_ty = mangle_type_or_value(ty)
35
- return hashlib.sha256(mangled_ty.encode('utf-8')).hexdigest()
49
+ return hashlib.sha256(mangled_ty.encode("utf-8")).hexdigest()
50
+
51
+
52
+ def make_structref_code_txt(
53
+ struct_name: str,
54
+ struct_fields: Iterable[str] | Dict[str, Type],
55
+ struct_type_class: type | Type,
56
+ struct_methods: Optional[Dict[str, Callable]] = None,
57
+ jit_options: Optional[dict] = None
58
+ ):
59
+ if isinstance(struct_fields, dict):
60
+ struct_fields, fields_types = list(struct_fields.keys()), list(struct_fields.values())
61
+ else:
62
+ assert isinstance(struct_fields, (list, tuple)), struct_fields
63
+ fields_types = None
64
+ struct_fields_str = ", ".join([field for field in struct_fields])
65
+ make_name = f"make_{struct_name.lower()}"
66
+ new_returns = f"{make_name}({struct_fields_str})"
67
+ repr_str = f"f'{struct_name}(" + ", ".join([f"{field}={{self.{field}}}" for field in struct_fields]) + ")'"
68
+ code_txt = StringIO()
69
+ code_txt.write(f"""
70
+ class {struct_name}(StructRefProxy):
71
+ def __new__(cls, {struct_fields_str}):
72
+ return {new_returns}
73
+
74
+ def __repr__(self):
75
+ return {repr_str}
76
+ """)
77
+ for field in struct_fields:
78
+ code_txt.write(f"""
79
+ @property
80
+ @njit(**jit_options)
81
+ def {field}(self):
82
+ return self.{field}
83
+ """)
84
+ methods_code_txt = StringIO()
85
+ if struct_methods is not None:
86
+ assert isinstance(struct_methods, dict), f"""
87
+ Expected dictionary of methods names to callable, got {struct_methods}"""
88
+ for method_name, method in struct_methods.items():
89
+ params_str, names_params_str = make_params_strings(method)
90
+ names_params_lst = names_params_str.split(", ")
91
+ self_name = names_params_lst[0]
92
+ names_params_str_wo_self = ", ".join(names_params_lst[1:])
93
+ method_source = dedent(getsource(method))
94
+ method_hash = hashlib.sha256(method_source.encode("utf-8")).hexdigest()
95
+ code_txt.write(f"""
96
+ def {method_name}({params_str}):
97
+ return {self_name}.{method_name}_{method_hash}({names_params_str_wo_self})
98
+
99
+ @njit(**jit_options)
100
+ def {method_name}_{method_hash}({params_str}):
101
+ return {self_name}.{method_name}({names_params_str_wo_self})
102
+ """)
103
+ method_header = re.findall(r"^\s*def\s+([a-zA-Z_]\w*)\s*\(([^)]*)\)\s*:[^\n]*", method_source, re.MULTILINE)
104
+ assert len(method_header) == 1, method_header
105
+ method_name, params_str_ = method_header[0]
106
+ assert params_str == params_str_, (params_str, params_str_)
107
+ method_source = re.sub(r"\bdef\s+([a-zA-Z_]\w*)\b", f"def _", method_source)
108
+ methods_code_txt.write(f"""
109
+ @overload_method({struct_type_class.__name__}, "{method_name}", jit_options=jit_options)
110
+ def ol_{method_name}({params_str}):
111
+ {indent(method_source, " ")}
112
+ return _
113
+ """)
114
+ code_txt.write(f"""
115
+ define_boxing({struct_type_class.__name__}, {struct_name})
116
+ """)
117
+ struct_type_name = f"{struct_name}Type"
118
+ struct_fields_ty_str = ", ".join([f"{field}_ty" for field in struct_fields])
119
+ struct_type_code_block = ""
120
+ if fields_types is None:
121
+ struct_type_code_block = f"""fields_types = [{struct_fields_ty_str}]
122
+ fields_and_their_types = list(zip(fields, fields_types))
123
+ {struct_name}Type = {struct_type_class.__name__}(fields_and_their_types)
124
+ """
125
+ else:
126
+ code_txt.write(f"""
127
+ fields_and_their_types = list(zip(fields, fields_types))
128
+ {struct_name}Type = {struct_type_class.__name__}(fields_and_their_types)
129
+ """)
130
+ ctor_code_block = "\n".join([f" struct_.{field} = {field}" for field in struct_fields])
131
+ code_txt.write(f"""
132
+ @overload({struct_name}, strict=False, jit_options=jit_options)
133
+ def ol_{struct_name.lower()}({struct_fields_ty_str}):
134
+ {struct_type_code_block}
135
+ def ctor({struct_fields_str}):
136
+ struct_ = new({struct_type_name})
137
+ {ctor_code_block}
138
+ return struct_
139
+ return ctor
140
+ """)
141
+ if fields_types is not None:
142
+ code_txt.write(f"""
143
+ {make_name}_sig = {struct_name}Type(*fields_types)
144
+ """)
145
+ else:
146
+ code_txt.write(f"""
147
+ {make_name}_sig = None
148
+ """)
149
+ code_txt.write(f"""
150
+ @njit({make_name}_sig, **jit_options)
151
+ def {make_name}({struct_fields_str}):
152
+ return {struct_name}({struct_fields_str})
153
+ """)
154
+ code_txt = code_txt.getvalue() + methods_code_txt.getvalue()
155
+ return code_txt, fields_types
156
+
157
+
158
+ def make_structref(
159
+ struct_name: str,
160
+ struct_fields: Iterable[str] | Dict[str, Type],
161
+ struct_type_class: type | Type,
162
+ *,
163
+ struct_methods: Optional[Dict[str, Callable]] = None,
164
+ jit_options: Optional[dict] = None
165
+ ):
166
+ """
167
+ Makes structure type with `struct_name` and `struct_fields` from the StructRef type class.
168
+
169
+ A unique `struct_type_class` for each structref needs to be provided.
170
+ If caching of code that will be using the created struct type is desired,
171
+ these type class(es) need/s to be defined in a python module that is *not* executed.
172
+ (Same requirement is also to observed even when the full definition of StructRef
173
+ is entirely hard-coded rather than created dynamically.)
174
+
175
+ In particular, that's why `struct_type_class` cannot be incorporated into
176
+ the dynamic compile / exec routine here.
177
+
178
+ Dictionary of methods to be bound to the created structref can be provided as well.
179
+ Struct methods will get inlined into the caller if numba deems it to be optimal
180
+ (even if `jit_options` says otherwise), therefore changing the methods code
181
+ without poking the jitted caller can result in a stale cache - when the latter is
182
+ cached. This is not an exclusive limitation of a dynamic structref creation via
183
+ this function and is equally true when the structref definition is coded explicitly.
184
+ """
185
+ code_txt, fields_types = make_structref_code_txt(
186
+ struct_name, struct_fields, struct_type_class, struct_methods, jit_options
187
+ )
188
+ if jit_options is None:
189
+ jit_options = default_jit_options
190
+ ns = {
191
+ **getmodule(_file_anchor).__dict__,
192
+ **{
193
+ "fields": struct_fields,
194
+ "fields_types": fields_types,
195
+ "define_boxing": define_boxing,
196
+ "jit_options": jit_options,
197
+ "new": new,
198
+ "njit": njit,
199
+ "overload_method": overload_method,
200
+ "StructRefProxy": StructRefProxy,
201
+ struct_type_class.__name__: struct_type_class
202
+ }
203
+ }
204
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
205
+ exec(code, ns)
206
+ return ns[struct_name]
36
207
 
37
208
 
38
209
  def prune_type(ty):
@@ -0,0 +1,17 @@
1
+ import inspect
2
+
3
+
4
+ def make_params_strings(func):
5
+ func_params = inspect.signature(func).parameters
6
+ func_params_str = ', '.join(
7
+ [k if v.default == inspect._empty else f'{k}={v.default}' for k, v in func_params.items()]
8
+ )
9
+ func_names_params_str = ', '.join(func_params.keys())
10
+ return func_params_str, func_names_params_str
11
+
12
+
13
+ if __name__ == "__main__":
14
+ def aux(x, y, z=1):
15
+ pass
16
+ print(make_params_strings(aux))
17
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.2.6
3
+ Version: 0.2.7
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=T150U4daRZ7ULOwxGUzzoBDAqm3bW9UydvCf0KJii9I,22
1
+ numbox/__init__.py,sha256=e3cfQy_iVs9ILsymUalJnJu5D_dd7HuUVoVwKKurcL0,22
2
2
  numbox/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  numbox/core/configurations.py,sha256=0bCmxXL-QMwtvyIDhpXLeT-1KJMf_QpH0wLuEvYLGxQ,68
4
4
  numbox/core/any/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -13,9 +13,9 @@ numbox/core/bindings/call.py,sha256=LrSsp-b4Mz0Zjg7H3XkThEIOEqVcrcViEjI9yqhuMV4,
13
13
  numbox/core/bindings/signatures.py,sha256=OcSBDpJ422eoWkJXxHPEanMNbVB7bq9f5bRq5LGr86w,479
14
14
  numbox/core/bindings/utils.py,sha256=aRtN8oUYBk9vgoUGaUJosGx0Za-vvCNwwbZg_g_-LRs,460
15
15
  numbox/core/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- numbox/core/proxy/proxy.py,sha256=kGYlEdLK40lxxu56e_S32s9YuQ6AuQnFegt5uQrUw5w,3889
16
+ numbox/core/proxy/proxy.py,sha256=Wt7yzswDmeQXt0yjcTcnLi2coneowSHWXy_IFpZZJMU,3612
17
17
  numbox/core/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- numbox/core/work/builder.py,sha256=WFZmH8dHTQNx1TwjpJVtZXN5ud4K2j500HgbF-Msu4c,6063
18
+ numbox/core/work/builder.py,sha256=U7hxopSwOc1ke1Hqup6xCliO7bqjq91zVX1SixYPxoM,6072
19
19
  numbox/core/work/combine_utils.py,sha256=qTVGke_ydzaTQ7o29DFjZWZzKjRNKb0L3yJMaR3TLII,2430
20
20
  numbox/core/work/explain.py,sha256=ESwvsTgfe0w7UnM13yyVpVDtfJyAK2A1sNdF3RNb-jU,1200
21
21
  numbox/core/work/loader_utils.py,sha256=g83mDWidZJ8oLWP3I3rK8aGISYOO2S-w6HDgtosCyck,1572
@@ -26,13 +26,14 @@ numbox/core/work/print_tree.py,sha256=y2u7xmbHvpcA57y8PrGSqOunLNCqhgNXdVtXHqvy1M
26
26
  numbox/core/work/work.py,sha256=V_pYW0sqdYHh45ago3aMz0fG4U_UfsNLIcpBejn_ttU,14725
27
27
  numbox/core/work/work_utils.py,sha256=3q_nnBdzuxWWcdFpbRL2H0T9ZNkUgx1J1uhiZkX3YG4,1039
28
28
  numbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
- numbox/utils/highlevel.py,sha256=gXYzLsFPKHQfGqaz-Z4DWcCQddv0dS6SKwIsM-_xjYg,1487
29
+ numbox/utils/highlevel.py,sha256=0sUVGOFAzFaGycKrXloGySLjp5EAPaf1B0AcOT1dfbw,8326
30
30
  numbox/utils/lowlevel.py,sha256=ACpf8_HyOIsobPlZ31bapkEyuCsV5dojW3AFrcKykrw,10712
31
31
  numbox/utils/meminfo.py,sha256=ykFi8Vt0WcHI3ztgMwvpn6NqaflDSQGL8tjI01jrzm0,1759
32
+ numbox/utils/standard.py,sha256=2fPrMlSXe2TG3CIfjJOT8LQkHEH86oOOj1AvwQkYCfA,450
32
33
  numbox/utils/timer.py,sha256=KkAkWOHQ72WtPjyiAzt_tF1q0DcOnCDkITTb85DvkUM,553
33
34
  numbox/utils/void_type.py,sha256=IkZsjNeAIShYJtvWbvERdHnl_mbF1rCRWiM3gp6II8U,404
34
- numbox-0.2.6.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
35
- numbox-0.2.6.dist-info/METADATA,sha256=H7eyqJTneiiqllMj4Boqaxpj-gwZpLjkQlGEhiOuJlE,2792
36
- numbox-0.2.6.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
37
- numbox-0.2.6.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
38
- numbox-0.2.6.dist-info/RECORD,,
35
+ numbox-0.2.7.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
36
+ numbox-0.2.7.dist-info/METADATA,sha256=J-Ash1idpJn-eUghPfVjNlVQhkbT0DHKa1D4K-A3ZTs,2792
37
+ numbox-0.2.7.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
38
+ numbox-0.2.7.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
39
+ numbox-0.2.7.dist-info/RECORD,,
File without changes