numbox 0.3.3__py3-none-any.whl → 0.3.4__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.3'
1
+ __version__ = '0.3.4'
@@ -3,7 +3,7 @@ import warnings
3
3
  from collections import defaultdict
4
4
  from dataclasses import dataclass, field
5
5
  from typing import (
6
- Any, Callable, Dict, List, Mapping, Set, Tuple, TypeAlias, Union
6
+ Any, Callable, Dict, Iterator, List, Mapping, Set, Tuple, TypeAlias, Union
7
7
  )
8
8
 
9
9
 
@@ -23,7 +23,7 @@ _null = _Null()
23
23
  QUAL_SEP = "."
24
24
 
25
25
 
26
- def _make_qual_name(namespace_name: str, var_name: str) -> str:
26
+ def make_qual_name(namespace_name: str, var_name: str) -> str:
27
27
  """ Each `Variable` instance is best contained in a
28
28
  mapping namespace, with the given `namespace_name`.
29
29
  This function thereby returns qualified name of the
@@ -55,6 +55,9 @@ class External:
55
55
  self._vars[name] = variable
56
56
  return variable
57
57
 
58
+ def __iter__(self) -> Iterator['Variable']:
59
+ return iter(self._vars.values())
60
+
58
61
 
59
62
  @dataclass(frozen=True)
60
63
  class Variable:
@@ -114,7 +117,7 @@ class Variable:
114
117
  return isinstance(other, Variable) and self.name == other.name and self.source == other.source
115
118
 
116
119
  def qual_name(self) -> str:
117
- return _make_qual_name(self.source, self.name)
120
+ return make_qual_name(self.source, self.name)
118
121
 
119
122
 
120
123
  class Variables:
@@ -143,6 +146,9 @@ class Variables:
143
146
  """
144
147
  return self.variables[variable_name]
145
148
 
149
+ def __iter__(self) -> Iterator[Variable]:
150
+ return iter(self.variables.values())
151
+
146
152
 
147
153
  @dataclass
148
154
  class Value:
@@ -172,8 +178,8 @@ class CompiledNode:
172
178
  inputs: List[Variable]
173
179
 
174
180
  def __post_init__(self):
175
- if self.variable.formula is None and self.inputs:
176
- raise RuntimeError(f"{self.variable} contains inputs but no formula, how come?")
181
+ if self.variable.formula and not self.inputs:
182
+ raise RuntimeError(f"{self.variable} contains formula but no inputs, how come?")
177
183
 
178
184
  def __hash__(self):
179
185
  return hash((self.variable.source, self.variable.name))
@@ -212,7 +218,6 @@ class CompiledGraph:
212
218
  source and then from the name of the variable within that
213
219
  source to the variable's actual value.
214
220
  :param values: runtime storage of all values, instance of `Values`.
215
- :return:
216
221
  """
217
222
  self._assign_external_values(external_values, values)
218
223
  self._calculate(self.ordered_nodes, values)
@@ -241,7 +246,7 @@ class CompiledGraph:
241
246
  for var_name, variable in variables.items():
242
247
  if var_name not in provided:
243
248
  raise KeyError(
244
- f"Missing value for external variable '{_make_qual_name(source_name, var_name)}'"
249
+ f"Missing value for external variable '{make_qual_name(source_name, var_name)}'"
245
250
  )
246
251
  values.get(variable).value = provided[var_name]
247
252
 
@@ -298,7 +303,7 @@ class CompiledGraph:
298
303
  for src, vals in changed.items():
299
304
  for name, val in vals.items():
300
305
  variable = self.required_external_variables.get(src, {}).get(name)
301
- qual = _make_qual_name(src, name)
306
+ qual = make_qual_name(src, name)
302
307
  if variable is None:
303
308
  try:
304
309
  variable = next(n.variable for n in self.ordered_nodes if n.variable.qual_name() == qual)
@@ -412,7 +417,7 @@ class Graph:
412
417
  if isinstance(source, External):
413
418
  used_external_vars.add(variable)
414
419
  for input_name, input_source in variable.inputs.items():
415
- visit(_make_qual_name(input_source, input_name))
420
+ visit(make_qual_name(input_source, input_name))
416
421
  visiting.remove(qual_name)
417
422
  visited.add(qual_name)
418
423
  ordered_variables.append(variable)
@@ -434,6 +439,40 @@ class Graph:
434
439
  required_external_variables[variable_source][variable_name] = variable
435
440
  return required_external_variables
436
441
 
442
+ def _build_reverse_dependencies(self) -> Dict[str, set[str]]:
443
+ """
444
+ Utility to calculate set of qualified names of variables
445
+ impacted by each of the encountered inputs.
446
+ """
447
+ reverse = defaultdict(set)
448
+ for source_name, source in self.registry.items():
449
+ for variable in source:
450
+ var_qual = make_qual_name(source_name, variable.name)
451
+ for input_name, input_source in variable.inputs.items():
452
+ input_qual = make_qual_name(input_source, input_name)
453
+ reverse[input_qual].add(var_qual)
454
+ return reverse
455
+
456
+ def dependents_of(self, qual_names: List[str] | Set[str] | str) -> Set[str]:
457
+ """
458
+ Return qualified names of `Variable`s that directly or indirectly
459
+ depend on any of `qual_names`.
460
+ """
461
+ if isinstance(qual_names, str):
462
+ qual_names = {qual_names}
463
+ else:
464
+ qual_names = set(qual_names)
465
+ reverse = self._build_reverse_dependencies()
466
+ result = set(qual_names)
467
+ stack = list(qual_names)
468
+ while stack:
469
+ current = stack.pop()
470
+ for dep in reverse.get(current, ()):
471
+ if dep not in result:
472
+ result.add(dep)
473
+ stack.append(dep)
474
+ return result
475
+
437
476
  def explain(self, qual_name: str, direct: bool = True) -> str:
438
477
  """
439
478
  Follow the dependencies chain to explain how the given
@@ -454,8 +493,8 @@ class Graph:
454
493
  variable = variable_source[variable_name]
455
494
  inputs_qual_names = []
456
495
  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))
496
+ inputs_qual_names.append(make_qual_name(input_source, input_name))
497
+ collect(make_qual_name(input_source, input_name))
459
498
  if isinstance(variable_source, External):
460
499
  derivation.append(f"'{variable_name}' comes from external source '{source_name}'\n")
461
500
  else:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numbox
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Author: Mikhail Goykhman
5
5
  License: MIT License (with Citation Clause)
6
6
 
@@ -1,4 +1,4 @@
1
- numbox/__init__.py,sha256=on4Bj4mGEjEjyUkQExxprhOoEopcv_sPapsEnNxyelE,22
1
+ numbox/__init__.py,sha256=Yyz9rKJSsP7kA7oh3l-XTxOFzEuuSR9Ly7oYXA1hfFM,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=yvklS5vEsad2RttxkcJ-4glejc2iLyv4ia24AZrIIRs,18117
18
+ numbox/core/variable/variable.py,sha256=vmkecU_1_OUJov1cg0bT3fU7zxu1L7cGMBWD3_0cvQM,19621
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.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,,
38
+ numbox-0.3.4.dist-info/LICENSE,sha256=ZlmjEDrZFNHpGxy_7HThWRlyBvuOMchK__qgTdiO_Uk,1446
39
+ numbox-0.3.4.dist-info/METADATA,sha256=E3a0zMbjM0vjbO2DVN9zaZOuW1D09A20spTbIZK2imM,2996
40
+ numbox-0.3.4.dist-info/WHEEL,sha256=WnJ8fYhv8N4SYVK2lLYNI6N0kVATA7b0piVUNvqIIJE,91
41
+ numbox-0.3.4.dist-info/top_level.txt,sha256=A67jOkfqidCSYYm6ifjN_WZyIiR1B27fjxv6nNbPvjc,7
42
+ numbox-0.3.4.dist-info/RECORD,,
File without changes