numbox 0.3.1__py3-none-any.whl → 0.3.3__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.3.1'
1
+ __version__ = '0.3.3'
@@ -92,6 +92,8 @@ class Variable:
92
92
  these variables.
93
93
  :param formula: (optional) function that calculates value
94
94
  of this `Variable` from its sources.
95
+ :param metadata: any possible metadata associated with
96
+ this variable.
95
97
  :param cacheable: (default `False`) when `True`, the
96
98
  corresponding `Value` (see below) will be cached during
97
99
  calculation by the `id` of the corresponding Python object
@@ -102,6 +104,7 @@ class Variable:
102
104
  source: str = field(default="")
103
105
  inputs: Mapping[str, str] = field(default_factory=lambda: {})
104
106
  formula: Callable = field(default=None)
107
+ metadata: str | None = field(default=None)
105
108
  cacheable: bool = field(default=False)
106
109
 
107
110
  def __hash__(self):
@@ -238,7 +241,7 @@ class CompiledGraph:
238
241
  for var_name, variable in variables.items():
239
242
  if var_name not in provided:
240
243
  raise KeyError(
241
- f"Missing value for external variable '{source_name}.{var_name}'"
244
+ f"Missing value for external variable '{_make_qual_name(source_name, var_name)}'"
242
245
  )
243
246
  values.get(variable).value = provided[var_name]
244
247
 
@@ -274,12 +277,13 @@ class CompiledGraph:
274
277
  if node.variable.formula is None:
275
278
  continue
276
279
  args = tuple(values.get(input_).value for input_ in node.inputs)
277
- # assert _null not in args, f"Uninitialized input for {node.variable}, args = {args}"
280
+ assert not any(
281
+ [arg is _null for arg in args]
282
+ ), f"Uninitialized input for {node.variable}, args = {args}"
278
283
  cache_key = (node.variable, args)
279
- if node.variable.cacheable:
280
- if cache_key in values.cache:
281
- values.get(node.variable).value = values.cache[cache_key]
282
- continue
284
+ if node.variable.cacheable and cache_key in values.cache:
285
+ values.get(node.variable).value = values.cache[cache_key]
286
+ continue
283
287
  result = node.variable.formula(*args)
284
288
  if node.variable.cacheable:
285
289
  values.cache[cache_key] = result
@@ -348,6 +352,9 @@ class Graph:
348
352
  self.compiled_graphs = {}
349
353
 
350
354
  def compile(self, required: List[str] | str) -> CompiledGraph:
355
+ """
356
+ :required: list of qualified variables names that need to be calculated.
357
+ """
351
358
  if isinstance(required, str):
352
359
  required = [required]
353
360
  required_tup = tuple(sorted(required))
@@ -426,3 +433,37 @@ class Graph:
426
433
  variable_source = variable.source
427
434
  required_external_variables[variable_source][variable_name] = variable
428
435
  return required_external_variables
436
+
437
+ def explain(self, qual_name: str, direct: bool = True) -> str:
438
+ """
439
+ Follow the dependencies chain to explain how the given
440
+ variable is derived.
441
+ :param qual_name: qualified name of the `Variable`.
442
+ :param direct: when `True` (default), begin explanation
443
+ with `qual_name`.
444
+ """
445
+ derived = set()
446
+ derivation = []
447
+
448
+ def collect(qual_name_: str):
449
+ if qual_name_ in derived:
450
+ return
451
+ derived.add(qual_name_)
452
+ source_name, variable_name = qual_name_.split(QUAL_SEP)
453
+ variable_source = self.registry[source_name]
454
+ variable = variable_source[variable_name]
455
+ inputs_qual_names = []
456
+ for input_name, input_source in variable.inputs.items():
457
+ inputs_qual_names.append(_make_qual_name(input_source, input_name))
458
+ collect(_make_qual_name(input_source, input_name))
459
+ if isinstance(variable_source, External):
460
+ derivation.append(f"'{variable_name}' comes from external source '{source_name}'\n")
461
+ else:
462
+ derivation.append(
463
+ f"""'{qual_name_}' depends on {tuple(sorted(inputs_qual_names))} via \n\n{variable.metadata}"""
464
+ )
465
+
466
+ collect(qual_name)
467
+ derivation = reversed(derivation) if direct else derivation
468
+ derivation_txt = "\n" + "\n".join(derivation)
469
+ return derivation_txt
@@ -1,6 +1,6 @@
1
1
  MIT License (with Citation Clause)
2
2
 
3
- Copyright (c) 2025 Mikhail Goykhman
3
+ Copyright (c) 2026 Mikhail Goykhman
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
7
- Copyright (c) 2025 Mikhail Goykhman
7
+ Copyright (c) 2026 Mikhail Goykhman
8
8
 
9
9
  Permission is hereby granted, free of charge, to any person obtaining a copy
10
10
  of this software and associated documentation files (the "Software"), to deal
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=TZkGuMIRSRmUY3XCIs5owt2o60vXyqYMHWIkhx65uYE,22
1
+ numbox/__init__.py,sha256=on4Bj4mGEjEjyUkQExxprhOoEopcv_sPapsEnNxyelE,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,7 +15,7 @@ numbox/core/bindings/utils.py,sha256=OATfF4k8e5oPa9_wlHHkLQhY_DhrPNKYdeeGu9Nj5yg
15
15
  numbox/core/proxy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
16
  numbox/core/proxy/proxy.py,sha256=Wt7yzswDmeQXt0yjcTcnLi2coneowSHWXy_IFpZZJMU,3612
17
17
  numbox/core/variable/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
- numbox/core/variable/variable.py,sha256=GoCsB1hUDJJzZByK1OK13RZn4M-maBDjXfnbvRFjcS8,16371
18
+ numbox/core/variable/variable.py,sha256=yvklS5vEsad2RttxkcJ-4glejc2iLyv4ia24AZrIIRs,18117
19
19
  numbox/core/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
20
  numbox/core/work/builder.py,sha256=d0DRwJoyskp-6tYQyV1VE-v9eX99qJbQJ_FdAFrjuiE,6273
21
21
  numbox/core/work/builder_utils.py,sha256=z8au1x10AwnzQ0_MAbQ6DnKTp3u9HeYZ1jyfkUMYjVg,1213
@@ -35,8 +35,8 @@ numbox/utils/meminfo.py,sha256=ykFi8Vt0WcHI3ztgMwvpn6NqaflDSQGL8tjI01jrzm0,1759
35
35
  numbox/utils/standard.py,sha256=SPsQcyLZw21RaNCdfkIGE_QBaVnMtZjJY4F40_GGuak,347
36
36
  numbox/utils/timer.py,sha256=5_d690Fb3L2axJBRxtoB0qe23exBosNR4qu6cno4QfY,641
37
37
  numbox/utils/void_type.py,sha256=IkZsjNeAIShYJtvWbvERdHnl_mbF1rCRWiM3gp6II8U,404
38
- numbox-0.3.1.dist-info/LICENSE,sha256=YYgNvjH_p6-1NsdrIqGJnr1GUbZzA_8DxsP6vVfM6nY,1446
39
- numbox-0.3.1.dist-info/METADATA,sha256=L2Ol4D5QRR_K8j31xvFgbdJtxFiFLDJG2MPWrmS81Zk,2996
40
- numbox-0.3.1.dist-info/WHEEL,sha256=WnJ8fYhv8N4SYVK2lLYNI6N0kVATA7b0piVUNvqIIJE,91
41
- numbox-0.3.1.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
42
- numbox-0.3.1.dist-info/RECORD,,
38
+ numbox-0.3.3.dist-info/LICENSE,sha256=ZlmjEDrZFNHpGxy_7HThWRlyBvuOMchK__qgTdiO_Uk,1446
39
+ numbox-0.3.3.dist-info/METADATA,sha256=JZUXJUW8WU5zLOAPRs_QvIkrkCCCz8x1n4QpWFyQV8I,2996
40
+ numbox-0.3.3.dist-info/WHEEL,sha256=WnJ8fYhv8N4SYVK2lLYNI6N0kVATA7b0piVUNvqIIJE,91
41
+ numbox-0.3.3.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
42
+ numbox-0.3.3.dist-info/RECORD,,
File without changes