numbox 0.2.4__py3-none-any.whl → 0.2.6__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.4'
1
+ __version__ = '0.2.6'
@@ -1,10 +1,11 @@
1
+ from collections import namedtuple
1
2
  from hashlib import md5
2
3
  from inspect import getfile, getmodule, getsource
3
4
  from io import StringIO
4
5
  from itertools import chain
5
6
  from numba import njit, typeof
6
7
  from numba.core.types import Type
7
- from typing import Any, Callable, NamedTuple, Optional, Sequence, Union
8
+ from typing import Any, Callable, Dict, NamedTuple, Optional, Sequence, Union
8
9
 
9
10
  from numbox.core.configurations import default_jit_options
10
11
  from numbox.core.work.lowlevel_work_utils import ll_make_work
@@ -15,13 +16,33 @@ def _file_anchor():
15
16
  raise NotImplementedError
16
17
 
17
18
 
18
- class End(NamedTuple):
19
+ _specs_registry = dict()
20
+
21
+
22
+ class _End(NamedTuple):
19
23
  name: str
20
24
  init_value: Any
21
25
  ty: Optional[type | Type] = None
22
26
 
23
27
 
24
- class Derived(NamedTuple):
28
+ def _new(cls, super_proxy, *args, **kwargs):
29
+ name = kwargs.get("name")
30
+ assert name, "`name` key-word argument has not been provided"
31
+ if name in _specs_registry:
32
+ raise ValueError(f"Node '{name}' has already been defined on this graph. Pick a different name.")
33
+ spec_ = super_proxy.__new__(cls, *args, **kwargs)
34
+ _specs_registry[name] = spec_
35
+ return spec_
36
+
37
+
38
+ class End(_End):
39
+ __slots__ = ()
40
+
41
+ def __new__(cls, *args, **kwargs):
42
+ return _new(cls, super(), *args, **kwargs)
43
+
44
+
45
+ class _Derived(NamedTuple):
25
46
  name: str
26
47
  init_value: Any
27
48
  derive: Callable
@@ -29,6 +50,13 @@ class Derived(NamedTuple):
29
50
  ty: Optional[type | Type] = None
30
51
 
31
52
 
53
+ class Derived(_Derived):
54
+ __slots__ = ()
55
+
56
+ def __new__(cls, *args, **kwargs):
57
+ return _new(cls, super(), *args, **kwargs)
58
+
59
+
32
60
  SpecTy = Derived | End
33
61
 
34
62
 
@@ -50,6 +78,9 @@ def get_ty(spec_):
50
78
  return spec_.ty or typeof(spec_.init_value)
51
79
 
52
80
 
81
+ _derive_funcs = {}
82
+
83
+
53
84
  def _derived_cres(ty, sources: Sequence[End], derive, jit_options=None):
54
85
  jit_options = jit_options if jit_options is not None else {}
55
86
  sources_ty = []
@@ -58,6 +89,7 @@ def _derived_cres(ty, sources: Sequence[End], derive, jit_options=None):
58
89
  sources_ty.append(source_ty)
59
90
  derive_sig = ty(*sources_ty)
60
91
  derive_cres = cres(derive_sig, **jit_options)(derive)
92
+ _derive_funcs[id(derive_cres)] = derive
61
93
  return derive_cres
62
94
 
63
95
 
@@ -81,29 +113,34 @@ def _derived_line(
81
113
  return f"""{name_} = ll_make_work("{name_}", {init_name}, ({sources_}), {derive_name})"""
82
114
 
83
115
 
84
- def _verify_access_nodes(
85
- all_inputs_: Sequence[End],
86
- all_derived_: Sequence[Derived],
87
- access_nodes: Sequence[SpecTy]
88
- ):
89
- for access_node in access_nodes:
90
- assert access_node in all_inputs_ or access_node in all_derived_, f"{access_node} cannot be reached"
91
-
92
-
93
116
  def code_block_hash(code_txt: str):
94
117
  """ Re-compile and re-save cache when source code has changed. """
95
118
  return md5(code_txt.encode("utf-8")).hexdigest()
96
119
 
97
120
 
98
- def make_graph(
99
- all_inputs_: Sequence[End],
100
- all_derived_: Sequence[Derived],
101
- access_nodes: SpecTy | Sequence[SpecTy],
102
- jit_options: Optional[dict] = None
103
- ):
104
- if isinstance(access_nodes, SpecTy):
105
- access_nodes = (access_nodes,)
106
- _verify_access_nodes(all_inputs_, all_derived_, access_nodes)
121
+ def _infer_end_and_derived_nodes(spec: SpecTy, all_inputs_: Dict[str, Type], all_derived_: Dict[str, Type]):
122
+ if spec.name in all_inputs_ or spec.name in all_derived_:
123
+ return
124
+ if isinstance(spec, End):
125
+ all_inputs_[spec.name] = get_ty(spec)
126
+ return
127
+ for source in spec.sources:
128
+ _infer_end_and_derived_nodes(source, all_inputs_, all_derived_)
129
+ all_derived_[spec.name] = get_ty(spec)
130
+
131
+
132
+ def infer_end_and_derived_nodes(access_nodes: SpecTy | Sequence[SpecTy]):
133
+ all_inputs_ = dict()
134
+ all_derived_ = dict()
135
+ for access_node in access_nodes:
136
+ _infer_end_and_derived_nodes(access_node, all_inputs_, all_derived_)
137
+ all_inputs_lst = [_specs_registry[name] for name in all_inputs_.keys()]
138
+ all_derived_lst = [_specs_registry[name] for name in all_derived_.keys()]
139
+ return all_inputs_lst, all_derived_lst
140
+
141
+
142
+ def make_graph(*access_nodes: SpecTy | Sequence[SpecTy], jit_options: Optional[dict] = None):
143
+ all_inputs_, all_derived_ = infer_end_and_derived_nodes(access_nodes)
107
144
  if jit_options is None:
108
145
  jit_options = {}
109
146
  jit_options = {**default_jit_options, **jit_options}
@@ -114,26 +151,30 @@ def make_graph(
114
151
  _make_args = []
115
152
  code_txt = StringIO()
116
153
  initializers = {}
117
- derive_hashes=[]
154
+ derive_hashes = []
118
155
  for input_ in all_inputs_:
119
156
  line_ = _input_line(input_, ns, initializers)
120
157
  code_txt.write(f"\n\t{line_}")
121
158
  for derived_ in all_derived_:
122
159
  line_ = _derived_line(derived_, ns, initializers, derive_hashes, _make_args, jit_options)
123
160
  code_txt.write(f"\n\t{line_}")
124
- hash_str = f"code_block = {code_txt.getvalue()} initializers = {list(initializers.values())} derive_hashes = {derive_hashes}"
161
+ hash_str = f"code_block = {code_txt.getvalue()} initializers = {list(initializers.values())} derive_hashes = {derive_hashes}" # noqa: E501
125
162
  hash_ = code_block_hash(hash_str)
126
- code_txt.write(f"""\n\taccess_tuple = ({", ".join([n.name for n in access_nodes])})""")
127
- code_txt.write(f"\n\treturn access_tuple")
163
+ access_nodes_names = [n.name for n in access_nodes]
164
+ tup_ = ", ".join(access_nodes_names)
165
+ tup_ = tup_ + ", " if ", " not in tup_ else tup_
166
+ code_txt.write(f"""\n\taccess_tuple = ({tup_})""")
167
+ code_txt.write("\n\treturn access_tuple")
128
168
  code_txt = code_txt.getvalue()
129
169
  make_params = ", ".join(chain(_make_args, initializers.keys()))
130
170
  make_name = f"_make_{hash_}"
131
171
  code_txt = f"""
132
172
  @njit(**jit_options)
133
173
  def {make_name}({make_params}):""" + code_txt + f"""
134
- return_node_ = {make_name}({make_params})
174
+ access_tuple_ = {make_name}({make_params})
135
175
  """
136
176
  code = compile(code_txt, getfile(_file_anchor), mode="exec")
137
177
  exec(code, ns)
138
- return_node_ = ns["return_node_"]
139
- return return_node_
178
+ access_tuple_ = ns["access_tuple_"]
179
+ Access = namedtuple("Access", access_nodes_names)
180
+ return Access(*access_tuple_)
@@ -0,0 +1,38 @@
1
+ from inspect import getsource
2
+ from textwrap import indent
3
+
4
+ from numbox.core.work.builder import _derive_funcs
5
+ from numbox.core.work.work import Work
6
+
7
+
8
+ def get_func_code(derive_func_p_):
9
+ derive_func_ = _derive_funcs.get(derive_func_p_)
10
+ return derive_func_.__name__, indent(getsource(derive_func_), " ")
11
+
12
+
13
+ def _explain(work: Work, derivation_: list, derived_: set):
14
+ if work.name in derived_:
15
+ return
16
+ if len(work.sources) == 0:
17
+ derivation_.append(f"{work.name}: end node\n")
18
+ derived_.add(work.name)
19
+ return
20
+ inputs_names = []
21
+ for source in work.sources:
22
+ _explain(source, derivation_, derived_)
23
+ inputs_names.append(source.name)
24
+ derive_func_ptrs = work.derive
25
+ derive_func_name, derive_func_code = get_func_code(derive_func_ptrs[1])
26
+ derivation_.append(f"""{work.name}: {derive_func_name}({", ".join(inputs_names)})
27
+
28
+ {derive_func_code}""")
29
+ derived_.add(work.name)
30
+
31
+
32
+ def explain(work: Work):
33
+ all_end_nodes = work.all_end_nodes()
34
+ derivation = []
35
+ _explain(work, derivation, set())
36
+ explain_txt = f"All required end nodes: {all_end_nodes}\n\n"
37
+ explain_txt += "\n".join(derivation)
38
+ return explain_txt
numbox/core/work/work.py CHANGED
@@ -17,7 +17,7 @@ from numbox.core.work.lowlevel_work_utils import ll_make_work, WorkTypeClass
17
17
  from numbox.core.work.node import NodeType
18
18
  from numbox.core.work.node_base import NodeBase, NodeBaseType
19
19
  from numbox.utils.lowlevel import (
20
- extract_struct_member, _cast, is_not_null, get_func_p_from_func_struct, get_ll_func_sig
20
+ extract_struct_member, _cast, _get_func_tuple, is_not_null, get_func_p_from_func_struct, get_ll_func_sig
21
21
  )
22
22
 
23
23
 
@@ -73,6 +73,11 @@ class Work(NodeBase):
73
73
  def sources(self):
74
74
  return self.sources
75
75
 
76
+ @property
77
+ @njit(**default_jit_options)
78
+ def derive(self):
79
+ return _get_func_tuple(self.derive)
80
+
76
81
  @property
77
82
  @njit(**default_jit_options)
78
83
  def derived(self):
@@ -441,9 +446,8 @@ def ol_depends_on(self_ty, obj_ty):
441
446
  node = self.as_node()
442
447
  return name_ in node.all_inputs_names()
443
448
  else:
444
- assert isinstance(obj_ty, WorkTypeClass), f"Cannot handle {obj_ty}"
445
-
446
449
  def _(self, obj_):
447
450
  node = self.as_node()
448
451
  return obj_.name in node.all_inputs_names()
452
+ assert isinstance(obj_ty, WorkTypeClass), f"Cannot handle {obj_ty}"
449
453
  return _
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=N5-p8dQB8uwuCMpS1ADLf_E6rvWovtRRp3vY9Cq2gw4,22
1
+ numbox/__init__.py,sha256=T150U4daRZ7ULOwxGUzzoBDAqm3bW9UydvCf0KJii9I,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
@@ -15,14 +15,15 @@ numbox/core/bindings/utils.py,sha256=aRtN8oUYBk9vgoUGaUJosGx0Za-vvCNwwbZg_g_-LRs
15
15
  numbox/core/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  numbox/core/proxy/proxy.py,sha256=kGYlEdLK40lxxu56e_S32s9YuQ6AuQnFegt5uQrUw5w,3889
17
17
  numbox/core/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- numbox/core/work/builder.py,sha256=bIWOb9_mSSS4IMQ_kSPF5XlMh-nhzooZmDn_6N04r3c,4648
18
+ numbox/core/work/builder.py,sha256=WFZmH8dHTQNx1TwjpJVtZXN5ud4K2j500HgbF-Msu4c,6063
19
19
  numbox/core/work/combine_utils.py,sha256=qTVGke_ydzaTQ7o29DFjZWZzKjRNKb0L3yJMaR3TLII,2430
20
+ numbox/core/work/explain.py,sha256=ESwvsTgfe0w7UnM13yyVpVDtfJyAK2A1sNdF3RNb-jU,1200
20
21
  numbox/core/work/loader_utils.py,sha256=g83mDWidZJ8oLWP3I3rK8aGISYOO2S-w6HDgtosCyck,1572
21
22
  numbox/core/work/lowlevel_work_utils.py,sha256=TgRRcNfks0oaOXGXXr3ptafd_Xv_lpmH8sjBrJ9bPuI,5748
22
23
  numbox/core/work/node.py,sha256=CMolyoRQjG2A-pTQqZQ0kxKOYTKipWRC0mu8RWHuTUI,5096
23
24
  numbox/core/work/node_base.py,sha256=uI7asM2itQcHuOByXyJtqvrd4ovW6EXDRdHYp3JVHQ0,998
24
25
  numbox/core/work/print_tree.py,sha256=y2u7xmbHvpcA57y8PrGSqOunLNCqhgNXdVtXHqvy1M0,2340
25
- numbox/core/work/work.py,sha256=oC71F2y-NkIF9Ox63trlv061nYBxla6R-F2Nj-7NXI4,14595
26
+ numbox/core/work/work.py,sha256=V_pYW0sqdYHh45ago3aMz0fG4U_UfsNLIcpBejn_ttU,14725
26
27
  numbox/core/work/work_utils.py,sha256=3q_nnBdzuxWWcdFpbRL2H0T9ZNkUgx1J1uhiZkX3YG4,1039
27
28
  numbox/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
28
29
  numbox/utils/highlevel.py,sha256=gXYzLsFPKHQfGqaz-Z4DWcCQddv0dS6SKwIsM-_xjYg,1487
@@ -30,8 +31,8 @@ numbox/utils/lowlevel.py,sha256=ACpf8_HyOIsobPlZ31bapkEyuCsV5dojW3AFrcKykrw,1071
30
31
  numbox/utils/meminfo.py,sha256=ykFi8Vt0WcHI3ztgMwvpn6NqaflDSQGL8tjI01jrzm0,1759
31
32
  numbox/utils/timer.py,sha256=KkAkWOHQ72WtPjyiAzt_tF1q0DcOnCDkITTb85DvkUM,553
32
33
  numbox/utils/void_type.py,sha256=IkZsjNeAIShYJtvWbvERdHnl_mbF1rCRWiM3gp6II8U,404
33
- numbox-0.2.4.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
34
- numbox-0.2.4.dist-info/METADATA,sha256=REXHYfdLyuZ56CPvvesb9uM3bS0PDDHuGgscGDyzzm4,2792
35
- numbox-0.2.4.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
36
- numbox-0.2.4.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
37
- numbox-0.2.4.dist-info/RECORD,,
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,,
File without changes