pythagoras 0.24.4__py3-none-any.whl → 0.24.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.
- pythagoras/_060_autonomous_code_portals/autonomous_decorators.py +31 -4
- pythagoras/_060_autonomous_code_portals/autonomous_portal_core_classes.py +94 -14
- pythagoras/_060_autonomous_code_portals/names_usage_analyzer.py +133 -4
- pythagoras/_070_protected_code_portals/basic_pre_validators.py +130 -15
- pythagoras/_070_protected_code_portals/fn_arg_names_checker.py +20 -18
- pythagoras/_070_protected_code_portals/list_flattener.py +45 -7
- pythagoras/_070_protected_code_portals/package_manager.py +99 -24
- pythagoras/_070_protected_code_portals/protected_decorators.py +59 -1
- pythagoras/_070_protected_code_portals/protected_portal_core_classes.py +239 -4
- pythagoras/_070_protected_code_portals/system_utils.py +85 -12
- pythagoras/_070_protected_code_portals/validation_succesful_const.py +12 -7
- pythagoras/_080_pure_code_portals/pure_core_classes.py +178 -25
- pythagoras/_080_pure_code_portals/pure_decorator.py +37 -0
- pythagoras/_080_pure_code_portals/recursion_pre_validator.py +39 -0
- pythagoras/_090_swarming_portals/output_suppressor.py +32 -3
- pythagoras/_090_swarming_portals/swarming_portals.py +165 -19
- pythagoras/_100_top_level_API/__init__.py +11 -0
- pythagoras/_800_signatures_and_converters/__init__.py +17 -0
- pythagoras/_800_signatures_and_converters/base_16_32_convertors.py +55 -20
- pythagoras/_800_signatures_and_converters/current_date_gmt_str.py +20 -5
- pythagoras/_800_signatures_and_converters/hash_signatures.py +46 -10
- pythagoras/_800_signatures_and_converters/node_signature.py +27 -12
- pythagoras/_800_signatures_and_converters/random_signatures.py +14 -3
- pythagoras/core/__init__.py +54 -0
- {pythagoras-0.24.4.dist-info → pythagoras-0.24.7.dist-info}/METADATA +1 -1
- {pythagoras-0.24.4.dist-info → pythagoras-0.24.7.dist-info}/RECORD +27 -27
- {pythagoras-0.24.4.dist-info → pythagoras-0.24.7.dist-info}/WHEEL +0 -0
|
@@ -51,6 +51,12 @@ CACHED_EXECUTION_RESULTS_TXT = "Cached execution results"
|
|
|
51
51
|
EXECUTION_QUEUE_SIZE_TXT = "Execution queue size"
|
|
52
52
|
|
|
53
53
|
class PureCodePortal(ProtectedCodePortal):
|
|
54
|
+
"""Portal that manages execution and caching for pure functions.
|
|
55
|
+
|
|
56
|
+
The portal extends ProtectedCodePortal with two persistent dictionaries:
|
|
57
|
+
- execution_results: append-only, stores ValueAddr of function outputs
|
|
58
|
+
- execution_requests: mutable, tracks pending execution requests
|
|
59
|
+
"""
|
|
54
60
|
|
|
55
61
|
_execution_results: PersiDict | None
|
|
56
62
|
_execution_requests: PersiDict | None
|
|
@@ -60,6 +66,14 @@ class PureCodePortal(ProtectedCodePortal):
|
|
|
60
66
|
, p_consistency_checks: float | Joker = KEEP_CURRENT
|
|
61
67
|
, excessive_logging: bool | Joker = KEEP_CURRENT
|
|
62
68
|
):
|
|
69
|
+
"""Initialize a PureCodePortal instance.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
root_dict: Backing persistent dictionary or path used to create it.
|
|
73
|
+
p_consistency_checks: Probability [0..1] to re-check cached
|
|
74
|
+
results for consistency. KEEP_CURRENT to inherit.
|
|
75
|
+
excessive_logging: Verbosity flag; KEEP_CURRENT to inherit.
|
|
76
|
+
"""
|
|
63
77
|
ProtectedCodePortal.__init__(self
|
|
64
78
|
, root_dict=root_dict
|
|
65
79
|
, p_consistency_checks=p_consistency_checks
|
|
@@ -89,7 +103,13 @@ class PureCodePortal(ProtectedCodePortal):
|
|
|
89
103
|
|
|
90
104
|
|
|
91
105
|
def describe(self) -> pd.DataFrame:
|
|
92
|
-
"""
|
|
106
|
+
"""Describe the portal state as a DataFrame.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
pandas.DataFrame: Concatenated report that includes base portal
|
|
110
|
+
parameters plus counts of cached execution results and queued
|
|
111
|
+
execution requests.
|
|
112
|
+
"""
|
|
93
113
|
all_params = [super().describe()]
|
|
94
114
|
|
|
95
115
|
all_params.append(_describe_persistent_characteristic(
|
|
@@ -102,6 +122,7 @@ class PureCodePortal(ProtectedCodePortal):
|
|
|
102
122
|
return result
|
|
103
123
|
|
|
104
124
|
def _clear(self):
|
|
125
|
+
"""Release references to backing dicts and clear base portal state."""
|
|
105
126
|
self._execution_results = None
|
|
106
127
|
self._execution_requests = None
|
|
107
128
|
super()._clear()
|
|
@@ -113,6 +134,12 @@ class PureFnCallSignature(ProtectedFnCallSignature):
|
|
|
113
134
|
_execution_results_addr_cache: PureFnExecutionResultAddr | None
|
|
114
135
|
|
|
115
136
|
def __init__(self, fn: PureFn, arguments: dict):
|
|
137
|
+
"""Create a signature object for a specific PureFn call.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
fn: The pure function being called.
|
|
141
|
+
arguments: Keyword arguments for the call.
|
|
142
|
+
"""
|
|
116
143
|
assert isinstance(fn, PureFn)
|
|
117
144
|
assert isinstance(arguments, dict)
|
|
118
145
|
super().__init__(fn, arguments)
|
|
@@ -132,6 +159,12 @@ class PureFnCallSignature(ProtectedFnCallSignature):
|
|
|
132
159
|
|
|
133
160
|
|
|
134
161
|
class PureFn(ProtectedFn):
|
|
162
|
+
"""Wrapper around a callable that provides pure-function semantics.
|
|
163
|
+
|
|
164
|
+
A PureFn executes inside a PureCodePortal, caches results by call
|
|
165
|
+
signature, and exposes convenience APIs to request execution, run
|
|
166
|
+
immediately, and retrieve results via address objects.
|
|
167
|
+
"""
|
|
135
168
|
|
|
136
169
|
def __init__(self, fn: Callable | str
|
|
137
170
|
, pre_validators: list[AutonomousFn] | List[Callable] | None = None
|
|
@@ -139,6 +172,17 @@ class PureFn(ProtectedFn):
|
|
|
139
172
|
, excessive_logging: bool | Joker = KEEP_CURRENT
|
|
140
173
|
, fixed_kwargs: dict | None = None
|
|
141
174
|
, portal: PureCodePortal | None = None):
|
|
175
|
+
"""Construct a PureFn.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
fn: Target callable.
|
|
179
|
+
pre_validators: Optional list of pre-execution validators.
|
|
180
|
+
post_validators: Optional list of post-execution validators.
|
|
181
|
+
excessive_logging: Verbosity flag; KEEP_CURRENT to inherit.
|
|
182
|
+
fixed_kwargs: Mapping of argument names to fixed values injected
|
|
183
|
+
into each call.
|
|
184
|
+
portal: Optional PureCodePortal to bind this PureFn to.
|
|
185
|
+
"""
|
|
142
186
|
ProtectedFn.__init__(self
|
|
143
187
|
, fn=fn
|
|
144
188
|
, portal = portal
|
|
@@ -149,21 +193,45 @@ class PureFn(ProtectedFn):
|
|
|
149
193
|
|
|
150
194
|
|
|
151
195
|
def get_address(self, **kwargs) -> PureFnExecutionResultAddr:
|
|
152
|
-
"""
|
|
196
|
+
"""Build an address object for a call with the given arguments.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
**kwargs: Keyword arguments to pass to the function.
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
PureFnExecutionResultAddr: Address referencing the (cached or
|
|
203
|
+
future) result corresponding to the provided arguments.
|
|
204
|
+
"""
|
|
153
205
|
with self.portal:
|
|
154
206
|
packed_kwargs = KwArgs(**kwargs).pack()
|
|
155
207
|
return PureFnExecutionResultAddr(self, packed_kwargs)
|
|
156
208
|
|
|
157
209
|
|
|
158
210
|
def get_signature(self, arguments: dict) -> PureFnCallSignature:
|
|
211
|
+
"""Build a call signature for the given arguments.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
arguments: Keyword arguments for a potential call.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
PureFnCallSignature: The signature object identifying the call.
|
|
218
|
+
"""
|
|
159
219
|
return PureFnCallSignature(self, arguments)
|
|
160
220
|
|
|
161
221
|
|
|
162
222
|
def swarm(self, **kwargs) -> PureFnExecutionResultAddr:
|
|
163
|
-
"""
|
|
223
|
+
"""Request background function execution for the given arguments.
|
|
224
|
+
|
|
225
|
+
The function is not executed immediately; instead, an execution request
|
|
226
|
+
is recorded in the portal. The returned address can later be used to
|
|
227
|
+
check readiness or retrieve the value.
|
|
164
228
|
|
|
165
|
-
|
|
166
|
-
|
|
229
|
+
Args:
|
|
230
|
+
**kwargs: Keyword arguments to pass to the underlying function.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
PureFnExecutionResultAddr: Address that identifies the pending (or
|
|
234
|
+
already cached) execution result for these arguments.
|
|
167
235
|
"""
|
|
168
236
|
with self.portal:
|
|
169
237
|
result_address = self.get_address(**kwargs)
|
|
@@ -171,10 +239,16 @@ class PureFn(ProtectedFn):
|
|
|
171
239
|
return result_address
|
|
172
240
|
|
|
173
241
|
def run(self, **kwargs) -> PureFnExecutionResultAddr:
|
|
174
|
-
"""
|
|
242
|
+
"""Execute immediately and return the result address.
|
|
243
|
+
|
|
244
|
+
The function is executed synchronously within the current process.
|
|
245
|
+
|
|
246
|
+
Args:
|
|
247
|
+
**kwargs: Keyword arguments to pass to the underlying function.
|
|
175
248
|
|
|
176
|
-
|
|
177
|
-
|
|
249
|
+
Returns:
|
|
250
|
+
PureFnExecutionResultAddr: Address of the computed value (which can
|
|
251
|
+
be used to fetch logs/metadata or the value again if needed).
|
|
178
252
|
"""
|
|
179
253
|
with self.portal:
|
|
180
254
|
result_address = self.get_address(**kwargs)
|
|
@@ -183,12 +257,18 @@ class PureFn(ProtectedFn):
|
|
|
183
257
|
|
|
184
258
|
|
|
185
259
|
def execute(self, **kwargs) -> Any:
|
|
186
|
-
"""
|
|
260
|
+
"""Execute the function with the given arguments and return the result.
|
|
261
|
+
|
|
262
|
+
The function is executed immediately and its result is memoized by the
|
|
263
|
+
portal. Subsequent calls with identical arguments return the cached
|
|
264
|
+
value (optionally performing consistency checks depending on the
|
|
265
|
+
portal's p_consistency_checks setting).
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
**kwargs: Keyword arguments to pass to the underlying function.
|
|
187
269
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
only the first time it's called; subsequent calls return the
|
|
191
|
-
cached result.
|
|
270
|
+
Returns:
|
|
271
|
+
Any: The computed result value.
|
|
192
272
|
"""
|
|
193
273
|
|
|
194
274
|
with self.portal as portal:
|
|
@@ -224,6 +304,16 @@ class PureFn(ProtectedFn):
|
|
|
224
304
|
self
|
|
225
305
|
, list_of_kwargs:list[dict]
|
|
226
306
|
) -> list[PureFnExecutionResultAddr]:
|
|
307
|
+
"""Queue background execution for a batch of argument sets.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
list_of_kwargs: A list of keyword-argument mappings. Each mapping
|
|
311
|
+
represents one call to the function.
|
|
312
|
+
|
|
313
|
+
Returns:
|
|
314
|
+
list[PureFnExecutionResultAddr]: Addresses for all requested
|
|
315
|
+
executions, in the same order as the input list.
|
|
316
|
+
"""
|
|
227
317
|
assert isinstance(list_of_kwargs, (list, tuple))
|
|
228
318
|
for kwargs in list_of_kwargs:
|
|
229
319
|
assert isinstance(kwargs, dict)
|
|
@@ -244,6 +334,17 @@ class PureFn(ProtectedFn):
|
|
|
244
334
|
self
|
|
245
335
|
, list_of_kwargs:list[dict]
|
|
246
336
|
) -> list[PureFnExecutionResultAddr]:
|
|
337
|
+
"""Execute a batch of calls immediately and return their addresses.
|
|
338
|
+
|
|
339
|
+
Execution is performed in a shuffled order.
|
|
340
|
+
|
|
341
|
+
Args:
|
|
342
|
+
list_of_kwargs: A list of keyword-argument mappings for each call.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
list[PureFnExecutionResultAddr]: Addresses for the executed calls,
|
|
346
|
+
in the same order as the input list.
|
|
347
|
+
"""
|
|
247
348
|
with self.portal:
|
|
248
349
|
addrs = self.swarm_list(list_of_kwargs)
|
|
249
350
|
addrs_workspace = copy(addrs)
|
|
@@ -275,6 +376,13 @@ class PureFn(ProtectedFn):
|
|
|
275
376
|
|
|
276
377
|
@property
|
|
277
378
|
def portal(self) -> PureCodePortal:
|
|
379
|
+
"""Active PureCodePortal used for this function execution.
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
PureCodePortal: The portal that governs execution and persistence
|
|
383
|
+
for this PureFn (falls back to the current active portal if this
|
|
384
|
+
function isn't explicitly bound).
|
|
385
|
+
"""
|
|
278
386
|
return super().portal
|
|
279
387
|
|
|
280
388
|
|
|
@@ -297,6 +405,12 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
297
405
|
_ready_cache: bool | None
|
|
298
406
|
|
|
299
407
|
def __init__(self, fn: PureFn, arguments:dict[str, Any]):
|
|
408
|
+
"""Create an address for a pure-function execution result.
|
|
409
|
+
|
|
410
|
+
Args:
|
|
411
|
+
fn: The PureFn whose execution result is addressed.
|
|
412
|
+
arguments: The keyword arguments for the call (packed dict).
|
|
413
|
+
"""
|
|
300
414
|
assert isinstance(fn, PureFn)
|
|
301
415
|
with fn.portal as portal:
|
|
302
416
|
self._kwargs_cache = KwArgs(**arguments)
|
|
@@ -339,6 +453,7 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
339
453
|
|
|
340
454
|
@property
|
|
341
455
|
def call_signature(self) -> PureFnCallSignature:
|
|
456
|
+
"""The PureFnCallSignature for this address' call."""
|
|
342
457
|
if (not hasattr(self, "_call_signature_cache")
|
|
343
458
|
or self._call_signature_cache is None):
|
|
344
459
|
self._call_signature_cache = self.get_ValueAddr().get()
|
|
@@ -384,6 +499,15 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
384
499
|
|
|
385
500
|
@property
|
|
386
501
|
def _ready_in_nonactive_portals(self) -> bool:
|
|
502
|
+
"""Try importing a ready result from non-active portals.
|
|
503
|
+
|
|
504
|
+
If another known portal already has the execution result, copy the
|
|
505
|
+
corresponding key/value into the active portal's stores.
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
bool: True if the value was found in a non-active portal and
|
|
509
|
+
imported; False otherwise.
|
|
510
|
+
"""
|
|
387
511
|
for another_portal in get_nonactive_portals():
|
|
388
512
|
with another_portal:
|
|
389
513
|
if self in another_portal._execution_results:
|
|
@@ -399,6 +523,12 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
399
523
|
|
|
400
524
|
@property
|
|
401
525
|
def ready(self) -> bool:
|
|
526
|
+
"""Whether the execution result is already available.
|
|
527
|
+
|
|
528
|
+
Returns:
|
|
529
|
+
bool: True if the result is present in the active portal (or can
|
|
530
|
+
be imported from a known non-active portal); False otherwise.
|
|
531
|
+
"""
|
|
402
532
|
if hasattr(self, "_ready_cache"):
|
|
403
533
|
assert self._ready_cache
|
|
404
534
|
return True
|
|
@@ -413,7 +543,11 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
413
543
|
|
|
414
544
|
|
|
415
545
|
def execute(self):
|
|
416
|
-
"""Execute the function and store the result in the portal.
|
|
546
|
+
"""Execute the function and store the result in the portal.
|
|
547
|
+
|
|
548
|
+
Returns:
|
|
549
|
+
Any: The computed result of the underlying pure function call.
|
|
550
|
+
"""
|
|
417
551
|
if hasattr(self, "_result_cache"):
|
|
418
552
|
return self._result_cache
|
|
419
553
|
with self.fn.portal:
|
|
@@ -439,7 +573,13 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
439
573
|
|
|
440
574
|
@property
|
|
441
575
|
def execution_requested(self):
|
|
442
|
-
"""
|
|
576
|
+
"""Whether execution for this call has been requested.
|
|
577
|
+
|
|
578
|
+
Returns:
|
|
579
|
+
bool: True if there's a pending execution request in the active
|
|
580
|
+
portal or any known non-active portal (also synchronizes the
|
|
581
|
+
request into the active portal); False otherwise.
|
|
582
|
+
"""
|
|
443
583
|
with self.fn.portal as active_portal:
|
|
444
584
|
if self in active_portal._execution_requests:
|
|
445
585
|
return True
|
|
@@ -451,15 +591,22 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
451
591
|
|
|
452
592
|
|
|
453
593
|
def get(self, timeout: int = None):
|
|
454
|
-
"""Retrieve value
|
|
594
|
+
"""Retrieve the value referenced by this address, waiting if needed.
|
|
595
|
+
|
|
596
|
+
The method does not execute the function itself. If the value is not
|
|
597
|
+
immediately available, it requests execution and waits with
|
|
598
|
+
exponential backoff until the result arrives or the timeout elapses.
|
|
455
599
|
|
|
456
|
-
|
|
457
|
-
|
|
600
|
+
Args:
|
|
601
|
+
timeout: Optional maximum number of seconds to wait. If None,
|
|
602
|
+
tries/waits indefinitely.
|
|
458
603
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
604
|
+
Returns:
|
|
605
|
+
Any: The value produced by the pure function call.
|
|
606
|
+
|
|
607
|
+
Raises:
|
|
608
|
+
TimeoutError: If the timeout elapses before the value becomes
|
|
609
|
+
available.
|
|
463
610
|
"""
|
|
464
611
|
assert timeout is None or timeout >= 0
|
|
465
612
|
if hasattr(self, "_result_cache"):
|
|
@@ -502,10 +649,16 @@ class PureFnExecutionResultAddr(HashAddr):
|
|
|
502
649
|
|
|
503
650
|
@property
|
|
504
651
|
def can_be_executed(self) -> PureFnCallSignature | ValidationSuccessFlag | None:
|
|
505
|
-
"""
|
|
652
|
+
"""Whether execution is currently feasible.
|
|
653
|
+
|
|
654
|
+
This checks pre-validators/guards for the underlying pure function and
|
|
655
|
+
returns a directive for the protected execution pipeline.
|
|
506
656
|
|
|
507
|
-
|
|
508
|
-
|
|
657
|
+
Returns:
|
|
658
|
+
PureFnCallSignature | ValidationSuccessFlag | None: If a dependent
|
|
659
|
+
call must be executed first, returns its call signature; if checks
|
|
660
|
+
pass immediately, returns VALIDATION_SUCCESSFUL; otherwise None to
|
|
661
|
+
indicate that the execution is not possible.
|
|
509
662
|
"""
|
|
510
663
|
with self.fn.portal:
|
|
511
664
|
return self.fn.can_be_executed(self.kwargs)
|
|
@@ -29,6 +29,18 @@ from .._080_pure_code_portals.pure_core_classes import (
|
|
|
29
29
|
from persidict import KEEP_CURRENT, Joker
|
|
30
30
|
|
|
31
31
|
class pure(protected):
|
|
32
|
+
"""Decorator that marks a function as pure and enables result caching.
|
|
33
|
+
|
|
34
|
+
Pure functions are assumed to be deterministic and free of side effects:
|
|
35
|
+
given the same arguments they always produce the same result. When you
|
|
36
|
+
decorate a function with @pure(), Pythagoras caches execution results in
|
|
37
|
+
a persistent store, avoids re-executing the function for identical calls,
|
|
38
|
+
as well as tracks source-code changes to recompute the function
|
|
39
|
+
when necessary.
|
|
40
|
+
|
|
41
|
+
This decorator is a thin, typed wrapper over the generic `protected`
|
|
42
|
+
decorator configured for pure-function semantics.
|
|
43
|
+
"""
|
|
32
44
|
|
|
33
45
|
def __init__(self
|
|
34
46
|
, pre_validators: list[ValidatorFn] | None = None
|
|
@@ -37,6 +49,22 @@ class pure(protected):
|
|
|
37
49
|
, excessive_logging: bool | Joker = KEEP_CURRENT
|
|
38
50
|
, portal: PureCodePortal | None = None
|
|
39
51
|
):
|
|
52
|
+
"""Initialize the pure decorator.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
pre_validators: Optional list of validator functions that run
|
|
56
|
+
before execution.
|
|
57
|
+
post_validators: Optional list of validator functions that run
|
|
58
|
+
after execution to validate results or side conditions.
|
|
59
|
+
fixed_kwargs: Mapping of argument names to values that will be
|
|
60
|
+
always injected into the decorated function calls.
|
|
61
|
+
excessive_logging: Controls verbosity inside the portal; keep
|
|
62
|
+
KEEP_CURRENT to inherit from the active portal, True/False to
|
|
63
|
+
override.
|
|
64
|
+
portal: Optional PureCodePortal to bind the decorated function to.
|
|
65
|
+
If omitted, the portal(s) to use will be inferred
|
|
66
|
+
during the function call(s).
|
|
67
|
+
"""
|
|
40
68
|
protected.__init__(self=self
|
|
41
69
|
, portal=portal
|
|
42
70
|
, excessive_logging=excessive_logging
|
|
@@ -46,6 +74,15 @@ class pure(protected):
|
|
|
46
74
|
|
|
47
75
|
|
|
48
76
|
def __call__(self, fn:Callable|str) -> PureFn:
|
|
77
|
+
"""Wrap a function as a PureFn within a PureCodePortal.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
fn: The target callable or its import path string.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
PureFn: A wrapped function instance that supports memoized
|
|
84
|
+
execution via run/swarm/execute and address-based retrieval.
|
|
85
|
+
"""
|
|
49
86
|
wrapper = PureFn(fn
|
|
50
87
|
, portal=self._portal
|
|
51
88
|
, pre_validators=self._pre_validators
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
"""Pre-validators that help with recursive pure functions.
|
|
2
|
+
|
|
3
|
+
This module provides utilities to short-circuit or schedule execution for
|
|
4
|
+
recursive calls, e.g., Fibonacci-like functions. The pre-validator returns
|
|
5
|
+
either a success flag (skip execution), a call signature to be executed first,
|
|
6
|
+
or None to proceed as usual.
|
|
7
|
+
"""
|
|
1
8
|
from unittest import result
|
|
2
9
|
|
|
3
10
|
import pythagoras as pth
|
|
@@ -14,6 +21,26 @@ def _recursion_pre_validator(
|
|
|
14
21
|
, fn_addr:ValueAddr
|
|
15
22
|
, param_name:str
|
|
16
23
|
)-> PureFnCallSignature | ValidationSuccessFlag | None:
|
|
24
|
+
"""Pre-validator to aid recursion by ensuring prerequisites are ready.
|
|
25
|
+
|
|
26
|
+
For a non-negative integer parameter specified by param_name, this
|
|
27
|
+
validator checks whether smaller sub-problems have already been computed.
|
|
28
|
+
It returns:
|
|
29
|
+
- VALIDATION_SUCCESSFUL if a base case is detected or all smaller results
|
|
30
|
+
are already available; or
|
|
31
|
+
- a PureFnCallSignature for the smallest missing sub-problem to compute
|
|
32
|
+
first; or
|
|
33
|
+
- None to proceed normally.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
packed_kwargs: Packed arguments (KwArgs) of the current call.
|
|
37
|
+
fn_addr: ValueAddr pointing to the underlying PureFn.
|
|
38
|
+
param_name: Name of the recursive integer argument to inspect.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
PureFnCallSignature | ValidationSuccessFlag | None: Directive for the
|
|
42
|
+
protected execution pipeline.
|
|
43
|
+
"""
|
|
17
44
|
unpacked_kwargs = packed_kwargs.unpack()
|
|
18
45
|
assert param_name in unpacked_kwargs
|
|
19
46
|
fn = fn_addr.get()
|
|
@@ -49,6 +76,18 @@ def _recursion_pre_validator(
|
|
|
49
76
|
def recursive_parameters(
|
|
50
77
|
*args
|
|
51
78
|
) -> list[ComplexPreValidatorFn]:
|
|
79
|
+
"""Build pre-validators for one or more recursive parameters.
|
|
80
|
+
|
|
81
|
+
Each provided name produces a pre-validator function that uses
|
|
82
|
+
_recursion_pre_validator to ensure prerequisite sub-problems are ready.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
*args: One or more names of integer parameters that govern recursion.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
list[ComplexPreValidatorFn]: A list of pre-validators to plug into the
|
|
89
|
+
pure/protected decorator configuration.
|
|
90
|
+
"""
|
|
52
91
|
result = []
|
|
53
92
|
for name in args:
|
|
54
93
|
assert isinstance(name, str)
|
|
@@ -1,13 +1,32 @@
|
|
|
1
|
+
"""Utilities for silencing worker process output.
|
|
2
|
+
|
|
3
|
+
This module provides a small context manager that redirects stdout and stderr
|
|
4
|
+
to the system null device (os.devnull). It is used by swarming workers to keep
|
|
5
|
+
background processing quiet and avoid polluting logs or test output.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
import os
|
|
2
9
|
from contextlib import ExitStack, redirect_stderr, redirect_stdout
|
|
3
10
|
|
|
4
11
|
|
|
5
|
-
|
|
6
12
|
class OutputSuppressor:
|
|
7
|
-
"""
|
|
13
|
+
"""Context manager to suppress stdout and stderr.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
with OutputSuppressor():
|
|
17
|
+
noisy_function()
|
|
18
|
+
|
|
19
|
+
Notes:
|
|
20
|
+
Internally uses contextlib.ExitStack to manage all redirections and to
|
|
21
|
+
ensure restoration even when exceptions are raised.
|
|
22
|
+
"""
|
|
8
23
|
|
|
9
24
|
def __enter__(self):
|
|
10
|
-
"""
|
|
25
|
+
"""Enter the suppression context.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
OutputSuppressor: The context manager instance.
|
|
29
|
+
"""
|
|
11
30
|
self._stack = ExitStack()
|
|
12
31
|
devnull = self._stack.enter_context(open(os.devnull, "w"))
|
|
13
32
|
self._stack.enter_context(redirect_stdout(devnull))
|
|
@@ -15,4 +34,14 @@ class OutputSuppressor:
|
|
|
15
34
|
return self
|
|
16
35
|
|
|
17
36
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
37
|
+
"""Exit the suppression context, restoring stdio streams.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
exc_type: Exception class if an exception occurred, else None.
|
|
41
|
+
exc_val: Exception instance if an exception occurred, else None.
|
|
42
|
+
exc_tb: Traceback if an exception occurred, else None.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
bool: Whatever is returned by ExitStack.__exit__().
|
|
46
|
+
"""
|
|
18
47
|
return self._stack.__exit__(exc_type, exc_val, exc_tb)
|