numbox 0.2.6__py3-none-any.whl → 0.2.8__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.8'
@@ -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/core/work/work.py CHANGED
@@ -166,6 +166,9 @@ def _call_derive(typingctx: Context, derive_ty: FunctionType, sources_ty: Tuple)
166
166
  return sig, codegen
167
167
 
168
168
 
169
+ _source_getter_registry = {}
170
+
171
+
169
172
  def _make_source_getter(source_ind):
170
173
  return f"""
171
174
  @intrinsic
@@ -182,8 +185,6 @@ def _get_source_{source_ind}(typingctx: Context, sources_ty: Tuple):
182
185
 
183
186
  def _make_calculate_code(num_sources):
184
187
  code_txt = StringIO()
185
- for source_ind_ in range(num_sources):
186
- code_txt.write(_make_source_getter(source_ind_))
187
188
  code_txt.write("""
188
189
  def _calculate_(work_):
189
190
  if work_.derived:
@@ -194,7 +195,8 @@ def _calculate_(work_):
194
195
  for source_ind_ in range(num_sources):
195
196
  code_txt.write(f"""
196
197
  source_{source_ind_} = _get_source_{source_ind_}(sources)
197
- source_{source_ind_}.calculate()""")
198
+ if not source_{source_ind_}.derived:
199
+ source_{source_ind_}.calculate()""")
198
200
  code_txt.write("""
199
201
  v = _call_derive(work_.derive, work_.sources)
200
202
  work_.derived = True
@@ -206,6 +208,15 @@ def _calculate_(work_):
206
208
  _calculate_registry = {}
207
209
 
208
210
 
211
+ def ensure_presence_of_source_getters_in_ns(num_sources_, ns_):
212
+ for source_i in range(num_sources_):
213
+ _source_getter = _source_getter_registry.get(source_i, None)
214
+ source_getter_code_txt = _make_source_getter(source_i)
215
+ source_getter_code = compile(source_getter_code_txt, getfile(_file_anchor), mode="exec")
216
+ exec(source_getter_code, ns_)
217
+ _source_getter_registry[source_i] = True
218
+
219
+
209
220
  @overload_method(WorkTypeClass, "calculate", strict=False, jit_options=default_jit_options)
210
221
  def ol_calculate(self_ty):
211
222
  derive_ty = self_ty.field_dict["derive"]
@@ -217,13 +228,15 @@ def ol_calculate(self_ty):
217
228
  sources_ty = self_ty.field_dict["sources"]
218
229
  num_sources = sources_ty.count
219
230
  _calculate = _calculate_registry.get(num_sources, None)
220
- if _calculate is None:
221
- code_txt = _make_calculate_code(num_sources)
222
- ns = getmodule(_file_anchor).__dict__
223
- code = compile(code_txt, getfile(_file_anchor), mode="exec")
224
- exec(code, ns)
225
- _calculate = ns["_calculate_"]
226
- _calculate_registry[num_sources] = _calculate
231
+ if _calculate is not None:
232
+ return _calculate
233
+ ns = getmodule(_file_anchor).__dict__
234
+ ensure_presence_of_source_getters_in_ns(num_sources, ns)
235
+ code_txt = _make_calculate_code(num_sources)
236
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
237
+ exec(code, ns)
238
+ _calculate = ns["_calculate_"]
239
+ _calculate_registry[num_sources] = _calculate
227
240
  return _calculate
228
241
 
229
242
 
@@ -246,8 +259,6 @@ def _cast_to_work_data(typingctx, work_ty, data_as_erased_ty: ErasedType):
246
259
 
247
260
  def _make_loader_code(num_sources):
248
261
  code_txt = StringIO()
249
- for source_ind_ in range(num_sources):
250
- code_txt.write(_make_source_getter(source_ind_))
251
262
  code_txt.write("""
252
263
  def _loader_(work_, data_):
253
264
  reset = False
@@ -282,20 +293,20 @@ def ol_load(work_ty, data_ty: DictType):
282
293
  sources_ty = work_ty.field_dict["sources"]
283
294
  num_sources = sources_ty.count
284
295
  _loader = _loader_registry.get(num_sources, None)
285
- if _loader is None:
286
- code_txt = _make_loader_code(num_sources)
287
- ns = getmodule(_file_anchor).__dict__
288
- code = compile(code_txt, getfile(_file_anchor), mode="exec")
289
- exec(code, ns)
290
- _loader = ns["_loader_"]
291
- _loader_registry[num_sources] = _loader
296
+ if _loader is not None:
297
+ return _loader
298
+ ns = getmodule(_file_anchor).__dict__
299
+ ensure_presence_of_source_getters_in_ns(num_sources, ns)
300
+ code_txt = _make_loader_code(num_sources)
301
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
302
+ exec(code, ns)
303
+ _loader = ns["_loader_"]
304
+ _loader_registry[num_sources] = _loader
292
305
  return _loader
293
306
 
294
307
 
295
308
  def _make_combine_code(num_sources):
296
309
  code_txt = StringIO()
297
- for source_ind_ in range(num_sources):
298
- code_txt.write(_make_source_getter(source_ind_))
299
310
  code_txt.write("""
300
311
  def _combine_(work_, data_, harvested_=None):
301
312
  if harvested_ is None:
@@ -331,13 +342,15 @@ def ol_combine(work_ty, data_ty: DictType, harvested_ty=NoneType):
331
342
  sources_ty = work_ty.field_dict["sources"]
332
343
  num_sources = sources_ty.count
333
344
  _combine = _combine_registry.get(num_sources, None)
334
- if _combine is None:
335
- code_txt = _make_combine_code(num_sources)
336
- ns = {**getmodule(_file_anchor).__dict__, **{"boolean": boolean, "Dict": Dict}}
337
- code = compile(code_txt, getfile(_file_anchor), mode="exec")
338
- exec(code, ns)
339
- _combine = ns["_combine_"]
340
- _combine_registry[num_sources] = _combine
345
+ if _combine is not None:
346
+ return _combine
347
+ ns = {**getmodule(_file_anchor).__dict__, **{"boolean": boolean, "Dict": Dict}}
348
+ ensure_presence_of_source_getters_in_ns(num_sources, ns)
349
+ code_txt = _make_combine_code(num_sources)
350
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
351
+ exec(code, ns)
352
+ _combine = ns["_combine_"]
353
+ _combine_registry[num_sources] = _combine
341
354
  return _combine
342
355
 
343
356
 
@@ -364,8 +377,6 @@ def ol_get_inputs_names(self_ty):
364
377
 
365
378
  def _make_inputs_vector_code(num_sources):
366
379
  code_txt = StringIO()
367
- for source_ind_ in range(num_sources):
368
- code_txt.write(_make_source_getter(source_ind_))
369
380
  code_txt.write("""
370
381
  def _inputs_vector_(work_):
371
382
  node = work_.node
@@ -399,13 +410,15 @@ def ol_make_inputs_vector(self_ty):
399
410
  return inputs_vector
400
411
  return _
401
412
  _inputs_vector = _inputs_vector_registry.get(num_sources, None)
402
- if _inputs_vector is None:
403
- code_txt = _make_inputs_vector_code(num_sources)
404
- ns = {**getmodule(_file_anchor).__dict__, **{"new": new}}
405
- code = compile(code_txt, getfile(_file_anchor), mode="exec")
406
- exec(code, ns)
407
- _inputs_vector = ns["_inputs_vector_"]
408
- _inputs_vector_registry[num_sources] = _inputs_vector
413
+ if _inputs_vector is not None:
414
+ return _inputs_vector
415
+ ns = {**getmodule(_file_anchor).__dict__, **{"new": new}}
416
+ ensure_presence_of_source_getters_in_ns(num_sources, ns)
417
+ code_txt = _make_inputs_vector_code(num_sources)
418
+ code = compile(code_txt, getfile(_file_anchor), mode="exec")
419
+ exec(code, ns)
420
+ _inputs_vector = ns["_inputs_vector_"]
421
+ _inputs_vector_registry[num_sources] = _inputs_vector
409
422
  return _inputs_vector
410
423
 
411
424
 
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
+
numbox/utils/timer.py CHANGED
@@ -9,13 +9,16 @@ logging.basicConfig(level=logging.WARNING)
9
9
  class Timer:
10
10
  times = {}
11
11
 
12
+ def __init__(self, precision=3):
13
+ self.precision = precision
14
+
12
15
  def __call__(self, func):
13
16
  def _(*args, **kws):
14
17
  t_start = perf_counter()
15
18
  res = func(*args, **kws)
16
19
  t_end = perf_counter()
17
20
  duration = t_end - t_start
18
- logger.warning(f"Execution of {func.__name__} took {duration:.3f}s")
21
+ logger.warning(f"Execution of {func.__name__} took {duration:.{self.precision}f}s")
19
22
  self.times[func.__name__] = duration
20
23
  return res
21
24
  return _
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.2.6
3
+ Version: 0.2.8
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -34,8 +34,12 @@ Keywords: llvmlite,numba,numpy
34
34
  Requires-Python: >=3.9
35
35
  Description-Content-Type: text/markdown
36
36
  License-File: LICENSE
37
+ Requires-Dist: llvmlite==0.44.0
38
+ Requires-Dist: numba~=0.61.0
39
+ Requires-Dist: numpy~=2.1.3
37
40
  Provides-Extra: docs
38
41
  Requires-Dist: sphinx==8.1.3; extra == "docs"
42
+ Requires-Dist: sphinx-sitemap==2.7.2; extra == "docs"
39
43
  Requires-Dist: sphinx-rtd-theme; extra == "docs"
40
44
 
41
45
  # numbox
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=T150U4daRZ7ULOwxGUzzoBDAqm3bW9UydvCf0KJii9I,22
1
+ numbox/__init__.py,sha256=QS1piWKz3Mys2vOiR2kTlrqfdbiwJYEfhOlgbh73Sg8,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
@@ -23,16 +23,17 @@ numbox/core/work/lowlevel_work_utils.py,sha256=TgRRcNfks0oaOXGXXr3ptafd_Xv_lpmH8
23
23
  numbox/core/work/node.py,sha256=CMolyoRQjG2A-pTQqZQ0kxKOYTKipWRC0mu8RWHuTUI,5096
24
24
  numbox/core/work/node_base.py,sha256=uI7asM2itQcHuOByXyJtqvrd4ovW6EXDRdHYp3JVHQ0,998
25
25
  numbox/core/work/print_tree.py,sha256=y2u7xmbHvpcA57y8PrGSqOunLNCqhgNXdVtXHqvy1M0,2340
26
- numbox/core/work/work.py,sha256=V_pYW0sqdYHh45ago3aMz0fG4U_UfsNLIcpBejn_ttU,14725
26
+ numbox/core/work/work.py,sha256=596flxydeHuEJ3oUhNz3PYPtA58nxERifvBCh8BWVug,15091
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/timer.py,sha256=KkAkWOHQ72WtPjyiAzt_tF1q0DcOnCDkITTb85DvkUM,553
32
+ numbox/utils/standard.py,sha256=2fPrMlSXe2TG3CIfjJOT8LQkHEH86oOOj1AvwQkYCfA,450
33
+ numbox/utils/timer.py,sha256=5_d690Fb3L2axJBRxtoB0qe23exBosNR4qu6cno4QfY,641
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.8.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
36
+ numbox-0.2.8.dist-info/METADATA,sha256=krcMK7v4WNgTrcuriQAWMASeaRod9KybPc57tRUE7w0,2935
37
+ numbox-0.2.8.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
38
+ numbox-0.2.8.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
39
+ numbox-0.2.8.dist-info/RECORD,,
File without changes