pythagoras 0.24.6__py3-none-any.whl → 0.24.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.
@@ -45,6 +45,29 @@ BACKGROUND_WORKERS_TXT = "Background workers"
45
45
 
46
46
 
47
47
  class SwarmingPortal(PureCodePortal):
48
+ """Portal for asynchronous swarming execution of pure functions.
49
+
50
+ The SwarmingPortal distributes execution of registered pure functions
51
+ across background worker processes (potentially on different machines)
52
+ in a best-effort, eventually-executed manner. It manages a child process
53
+ that maintains a pool of background workers and randomly dispatches
54
+ execution requests. No strong guarantees are provided regarding which
55
+ worker runs a task, how many times it runs, or when it will run; only that
56
+ eligible requests will eventually be executed at least once.
57
+
58
+ Notes:
59
+ - Parent/child: The portal instance created by user code is the parent.
60
+ It may spawn a separate child process whose responsibility is to keep
61
+ background workers alive. Child processes created by the portal do not
62
+ spawn further workers (max_n_workers is forced to 0 in children).
63
+ - Resources: The effective number of workers is automatically bounded by
64
+ currently available CPU cores and RAM at runtime.
65
+ - Environment logging: Runtime environment summary is stored under compute_nodes
66
+ for debugging purposes to help describe where the parent process is running.
67
+
68
+ See also: OutputSuppressor for silencing worker output, PureCodePortal for
69
+ the base API and lifecycle management, and tests in tests/_090_swarming_portals.
70
+ """
48
71
  _compute_nodes: OverlappingMultiDict | None
49
72
  _node_id: str | None
50
73
 
@@ -62,6 +85,31 @@ class SwarmingPortal(PureCodePortal):
62
85
  , parent_process_id: int | None = None
63
86
  , parent_process_start_time: float | None = None
64
87
  ):
88
+ """Initialize a swarming portal.
89
+
90
+ Args:
91
+ root_dict: Persistent dictionary or path used to back the portal's
92
+ state. If None, a default dictionary will be used.
93
+ p_consistency_checks: Probability or Joker controlling internal
94
+ consistency checks. Passed to PureCodePortal.
95
+ excessive_logging: Whether to enable verbose logging. Passed to
96
+ PureCodePortal.
97
+ max_n_workers: Desired maximum number of background workers for the
98
+ parent process. Children must pass 0 here.
99
+ The effective value may be reduced based on available CPUs and
100
+ RAM at runtime.
101
+ parent_process_id: ID of the parent process when this portal is
102
+ constructed inside a child process. For parent portals, it
103
+ must be None.
104
+ parent_process_start_time: Start time of the parent process, used to
105
+ detect PID reuse. For parents, it must be None.
106
+
107
+ Notes:
108
+ - When parent_process_id or parent_process_start_time is provided,
109
+ both must be provided and max_n_workers must be 0.
110
+ - Initializes compute_nodes storage and captures a unique
111
+ node signature for this runtime.
112
+ """
65
113
  PureCodePortal.__init__(self
66
114
  , root_dict=root_dict
67
115
  , p_consistency_checks=p_consistency_checks
@@ -95,6 +143,13 @@ class SwarmingPortal(PureCodePortal):
95
143
 
96
144
 
97
145
  def get_params(self) -> dict:
146
+ """Return portal parameters including parent process metadata.
147
+
148
+ Returns:
149
+ dict: Sorted dictionary of portal parameters inherited from
150
+ PureCodePortal plus parent_process_id and
151
+ parent_process_start_time.
152
+ """
98
153
  params = super().get_params()
99
154
  params["parent_process_id"] = self._parent_process_id
100
155
  params["parent_process_start_time"] = self._parent_process_start_time
@@ -104,13 +159,26 @@ class SwarmingPortal(PureCodePortal):
104
159
 
105
160
  @property
106
161
  def is_parent(self) -> bool:
107
- """Check if this portal is the parent process."""
162
+ """Whether this portal instance represents the parent process.
163
+
164
+ Returns:
165
+ bool: True if this process created the portal instance on the node
166
+ (no parent metadata set); False if this is a child portal
167
+ instantiated inside the background worker process.
168
+ """
108
169
  if self._parent_process_id is None:
109
170
  return True
110
171
  return False
111
172
 
112
173
 
113
174
  def _post_init_hook(self) -> None:
175
+ """Lifecycle hook invoked after initialization.
176
+
177
+ Registers a global atexit handler once per process to terminate any
178
+ child processes spawned by portals. For parent portals with a positive
179
+ max_n_workers, spawns a child process that manages the pool of
180
+ background worker processes.
181
+ """
114
182
  super()._post_init_hook()
115
183
 
116
184
  if not SwarmingPortal._atexit_is_registered:
@@ -132,7 +200,12 @@ class SwarmingPortal(PureCodePortal):
132
200
 
133
201
 
134
202
  def _terminate_child_process(self):
135
- """Terminate the child process if it is running."""
203
+ """Terminate the child process if it is running.
204
+
205
+ This method is idempotent and safe to call from atexit handlers.
206
+ It attempts a graceful termination, then escalates to kill if the
207
+ child does not stop within a short grace period.
208
+ """
136
209
  if self._child_process is not None:
137
210
  if self._child_process.is_alive():
138
211
  self._child_process.terminate()
@@ -145,14 +218,28 @@ class SwarmingPortal(PureCodePortal):
145
218
 
146
219
  @property
147
220
  def _execution_environment_address(self) -> list[str]: #TODO: move to Logs
148
- """Get the address of the execution environment in the compute nodes."""
221
+ """Address path for storing execution environment summary.
222
+
223
+ Returns:
224
+ list[str]: A hierarchical key used in the compute_nodes storage of
225
+ the form [node_id, parent_pid_and_start, "execution_environment"].
226
+ """
149
227
  s = str(self._parent_process_id) + "_" + str(self._parent_process_start_time)
150
228
  return [self._node_id, s, "execution_environment"]
151
229
 
152
230
 
153
231
  @property
154
232
  def max_n_workers(self) -> int:
155
- """Get the maximum number of background workers"""
233
+ """Effective cap on background worker processes.
234
+
235
+ The configured max_n_workers value is adjusted down by runtime
236
+ resource availability: currently unused CPU cores and available RAM.
237
+ The result is cached in RAM for the life of the portal process
238
+ until the cache is invalidated.
239
+
240
+ Returns:
241
+ int: Effective maximum number of worker processes to use.
242
+ """
156
243
  if not hasattr(self, "_max_n_workers_cache"):
157
244
  n = self._get_config_setting("max_n_workers")
158
245
  if n in (None, KEEP_CURRENT):
@@ -166,7 +253,13 @@ class SwarmingPortal(PureCodePortal):
166
253
 
167
254
 
168
255
  def describe(self) -> pd.DataFrame:
169
- """Get a DataFrame describing the portal's current state"""
256
+ """Describe the current portal configuration and runtime.
257
+
258
+ Returns:
259
+ pandas.DataFrame: A table combining PureCodePortal description with
260
+ swarming-specific characteristics such as effective number of
261
+ background workers.
262
+ """
170
263
  all_params = [super().describe()]
171
264
  all_params.append(_describe_runtime_characteristic(
172
265
  BACKGROUND_WORKERS_TXT, self.max_n_workers))
@@ -177,6 +270,12 @@ class SwarmingPortal(PureCodePortal):
177
270
 
178
271
 
179
272
  def parent_runtime_is_live(self):
273
+ """Check that the recorded parent process is still alive.
274
+
275
+ Returns:
276
+ bool: True if the parent PID exists and its start time matches the
277
+ recorded start time (to avoid PID reuse issues); False otherwise.
278
+ """
180
279
  if not process_is_active(self._parent_process_id):
181
280
  return False
182
281
  if get_process_start_time(self._parent_process_id) != self._parent_process_start_time:
@@ -185,6 +284,12 @@ class SwarmingPortal(PureCodePortal):
185
284
 
186
285
 
187
286
  def _clear(self):
287
+ """Release resources and clear internal state.
288
+
289
+ Side Effects:
290
+ Terminates the child process if present and clears references to
291
+ compute node metadata before delegating to the base implementation.
292
+ """
188
293
  self._compute_nodes = None
189
294
  self._terminate_child_process()
190
295
  super()._clear()
@@ -195,18 +300,28 @@ class SwarmingPortal(PureCodePortal):
195
300
  , min_delay:float = 0.02
196
301
  , max_delay:float = 0.22
197
302
  ) -> None:
198
- """Randomly delay execution by a given probability."""
303
+ """Introduce randomized backoff to reduce contention.
304
+
305
+ With probability p, sleeps for a random delay uniformly drawn from
306
+ [min_delay, max_delay]. Uses the portal's entropy_infuser to remain
307
+ deterministic when seeded in tests.
308
+
309
+ Args:
310
+ p: Probability of applying the delay.
311
+ min_delay: Minimum sleep duration in seconds.
312
+ max_delay: Maximum sleep duration in seconds.
313
+ """
199
314
  if self.entropy_infuser.uniform(0, 1) < p:
200
315
  delay = self.entropy_infuser.uniform(min_delay, max_delay)
201
316
  sleep(delay)
202
317
 
203
318
 
204
319
  def _invalidate_cache(self):
205
- """Invalidate the object's attribute cache.
320
+ """Drop cached computed attributes and delegate to base class.
206
321
 
207
- If the object's attribute named ATTR is cached,
208
- its cached value will be stored in an attribute named _ATTR_cache
209
- This method should delete all such attributes.
322
+ This implementation removes any attributes used as local caches by this
323
+ class (currently _max_n_workers_cache) and then calls the base
324
+ implementation to allow it to clear its own caches.
210
325
  """
211
326
  if hasattr(self, "_max_n_workers_cache"):
212
327
  del self._max_n_workers_cache
@@ -214,7 +329,19 @@ class SwarmingPortal(PureCodePortal):
214
329
 
215
330
 
216
331
  def _launch_many_background_workers(portal_init_jsparams:JsonSerializedObject) -> None:
217
- """Launch many background worker processes."""
332
+ """Spawn and maintain a pool of background worker processes.
333
+
334
+ This function is executed inside a dedicated child process created by the
335
+ parent portal. It spawns up to max_n_workers worker processes, restarts
336
+ any that exit unexpectedly, and records an execution environment summary
337
+ under the portal's compute_nodes.
338
+
339
+ Args:
340
+ portal_init_jsparams: Serialized initialization parameters for
341
+ reconstructing a SwarmingPortal. The parameters are adjusted to
342
+ indicate this is a child context (max_n_workers=0) and to record
343
+ the parent process metadata.
344
+ """
218
345
 
219
346
 
220
347
  n_workers_to_launch = access_jsparams(portal_init_jsparams
@@ -264,7 +391,16 @@ def _launch_many_background_workers(portal_init_jsparams:JsonSerializedObject) -
264
391
 
265
392
 
266
393
  def _background_worker(portal_init_jsparams:JsonSerializedObject) -> None:
267
- """Background worker that keeps processing random execution requests."""
394
+ """Worker loop that processes random execution requests serially.
395
+
396
+ Runs indefinitely until the parent process is detected as dead.
397
+ Within the loop, each individual request is handled in a subprocess to
398
+ isolate failures and to reduce the risk of state leakage.
399
+
400
+ Args:
401
+ portal_init_jsparams: Serialized initialization parameters for
402
+ reconstructing a SwarmingPortal in child context.
403
+ """
268
404
  portal = parameterizable.loadjs(portal_init_jsparams)
269
405
  assert isinstance(portal, SwarmingPortal)
270
406
  with portal:
@@ -282,9 +418,18 @@ def _background_worker(portal_init_jsparams:JsonSerializedObject) -> None:
282
418
 
283
419
 
284
420
  def _process_random_execution_request(portal_init_jsparams:JsonSerializedObject):
285
- """Process one random execution request."""
286
- # portal = parameterizable.get_object_from_portable_params(
287
- # portal_init_params)
421
+ """Process a single pending execution request, if any.
422
+
423
+ The function reconstructs a child-context portal, selects a random pending
424
+ execution request (if available), and validates readiness. If validation
425
+ yields a PureFnCallSignature, it continues with it; otherwise, it executes
426
+ the request when validation returns VALIDATION_SUCCESSFUL. Output during
427
+ execution is suppressed by the caller to keep workers quiet.
428
+
429
+ Args:
430
+ portal_init_jsparams: Serialized initialization parameters for
431
+ reconstructing a SwarmingPortal in child context.
432
+ """
288
433
  portal_init_jsparams = update_jsparams(
289
434
  portal_init_jsparams, max_n_workers=0)
290
435
  portal = parameterizable.loadjs(portal_init_jsparams)
@@ -326,13 +471,14 @@ def _process_random_execution_request(portal_init_jsparams:JsonSerializedObject)
326
471
 
327
472
 
328
473
  def _terminate_all_portals_child_processes():
329
- """ Clean runtime id.
474
+ """Terminate child processes for all known portals.
330
475
 
331
- This function is called at the end of the program execution.
332
- It deletes the principal_runtime_id record from all portals.
476
+ Registered with atexit the first time a SwarmingPortal is initialized.
477
+ Ensures that any child processes are terminated to avoid orphaned workers.
333
478
  """
334
479
  for portal in get_all_known_portals():
335
480
  try:
336
481
  portal._terminate_child_process()
337
- except:
482
+ except Exception:
483
+ # Best-effort cleanup; ignore errors during shutdown.
338
484
  pass
@@ -1,2 +1,13 @@
1
+ """Top-level, user-facing API shortcuts.
2
+
3
+ This subpackage exposes the easiest entry points for application authors,
4
+ primarily constructors and helpers to obtain a portal and interact with it.
5
+
6
+ Exports:
7
+ top_level_API: Functions that construct and return a portal (e.g., get_portal).
8
+ default_local_portal: Defaults and helpers for creating a local portal
9
+ when not explicitly created/provided by an application that uses Pythagoras.
10
+ """
11
+
1
12
  from .top_level_API import *
2
13
  from .default_local_portal import *
@@ -1,3 +1,20 @@
1
+ """Signatures and conversion utilities.
2
+
3
+ This subpackage provides helpers for generating stable identifiers and
4
+ converting between common textual/byte representations used across
5
+ Pythagoras. It re-exports frequently used helpers for convenience.
6
+
7
+ The modules exposed here are intentionally lightweight and side-effect free
8
+ so they can be used in hashing and address computations.
9
+
10
+ Exports:
11
+ base_16_32_convertors: Base-16/32 encoding and decoding helpers.
12
+ current_date_gmt_str: Utilities to format current date/time in GMT.
13
+ hash_signatures: Functions to compute content hash/signature strings.
14
+ node_signature: Functions to derive signatures for the current node.
15
+ random_signatures: Helpers to generate random, collision-resistant IDs.
16
+ """
17
+
1
18
  from .base_16_32_convertors import *
2
19
  from .current_date_gmt_str import *
3
20
  from .hash_signatures import *
@@ -1,3 +1,57 @@
1
+ """Pythagoras core convenience namespace.
2
+
3
+ This module re-exports the most frequently used decorators, classes, and
4
+ helpers from the Pythagoras subpackages, providing a compact import surface
5
+ for day‑to‑day work. It is safe to use either explicit imports or a star import
6
+ from this module depending on your style and needs.
7
+
8
+ Public API
9
+ ready, get
10
+ Utilities for working with addressable values. "ready(obj)" recursively
11
+ checks that all ValueAddr/HashAddr objects inside a nested structure are
12
+ ready. "get(obj)" deep‑copies a structure and replaces every contained
13
+ address with the concrete value via .get().
14
+
15
+ pure, recursive_parameters, PureFn
16
+ Decorator and helpers for pure functions. A pure function is assumed to
17
+ be deterministic and side‑effect free; Pythagoras persistently caches
18
+ its results by call signature and tracks source‑code changes. The
19
+ "recursive_parameters(...)" factory returns pre‑validators used to
20
+ optimize recursive computations.
21
+
22
+ autonomous
23
+ Decorator for declaring an autonomous function: implementation must be
24
+ self‑contained (imports done inside the body, no nonlocal/global state
25
+ except built‑ins), with autonomicity validated at decoration and at
26
+ runtime.
27
+
28
+ Basic pre‑validators
29
+ Small, composable validators intended to be attached to pure functions,
30
+ for example::
31
+
32
+ - unused_cpu(cores: int)
33
+ - unused_ram(Gb: int)
34
+ - installed_packages(*names: str)
35
+
36
+ These factories return validator instances (SimplePreValidatorFn) that
37
+ a portal can execute to check whether it should run the user code.
38
+
39
+ SwarmingPortal
40
+ Portal enabling asynchronous, distributed ("swarming") execution of
41
+ pure functions across background workers and processes. Execution is
42
+ best‑effort with eventual‑execution semantics.
43
+
44
+ get_portal
45
+ Factory for constructing a portal.
46
+
47
+ Notes
48
+ - Star‑importing from this module will also bring the basic pre‑validators
49
+ into your namespace. Prefer explicit imports if you want a stricter
50
+ namespace.
51
+ - This namespace focuses on high‑impact primitives. For advanced or
52
+ lower‑level APIs, import directly from the corresponding subpackages.
53
+ """
54
+
1
55
  from .._030_data_portals import ready, get
2
56
  from .._060_autonomous_code_portals import autonomous
3
57
  from .._070_protected_code_portals.basic_pre_validators import *
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pythagoras
3
- Version: 0.24.6
3
+ Version: 0.24.8
4
4
  Summary: Planet-scale distributed computing in Python.
5
5
  Keywords: cloud,ML,AI,serverless,distributed,parallel,machine-learning,deep-learning,pythagoras
6
6
  Author: Volodymyr (Vlad) Pavlov
@@ -19,7 +19,7 @@ pythagoras/_040_logging_code_portals/exception_processing_tracking.py,sha256=DH1
19
19
  pythagoras/_040_logging_code_portals/execution_environment_summary.py,sha256=-0ynNibGfRh3J1Sq-N9j7eN1FlGvetEBiW0L4K_qJ30,3813
20
20
  pythagoras/_040_logging_code_portals/kw_args.py,sha256=j3Iao80gTBjPx6dk1Azd9D8pcdQ3QdfpkQtQq-4ATV0,4954
21
21
  pythagoras/_040_logging_code_portals/logging_decorator.py,sha256=-BGduV2U5SJ40qW8afRCUMrzYv5Pf_CgB4HlSEGDmlA,1766
22
- pythagoras/_040_logging_code_portals/logging_portal_core_classes.py,sha256=R--DuvPGKzEB4ojWrmmuVU2SezUBVrSXrmdFjnrf72g,34977
22
+ pythagoras/_040_logging_code_portals/logging_portal_core_classes.py,sha256=PPtYlI9PB9N3A8WrC5HrLD7MijofZWqUpaQgbwOqEN4,35094
23
23
  pythagoras/_040_logging_code_portals/notebook_checker.py,sha256=qO7zfMC20hM4tSxlqB7gy6WI4imWX4Xl7ojSwgeVu0A,871
24
24
  pythagoras/_040_logging_code_portals/output_capturer.py,sha256=ohCp6qqxL7IuJGfnFuCIgj5Oc4HmC8c7uZGE_uzWkZk,4216
25
25
  pythagoras/_040_logging_code_portals/uncaught_exceptions.py,sha256=vQrY1mOYdAeKaCmCCY1MUy4xoXurQkfwQuDA43giPl0,4564
@@ -27,29 +27,29 @@ pythagoras/_050_safe_code_portals/__init__.py,sha256=YR-V6W2WZ17SjqmTyY2xdY16xTV
27
27
  pythagoras/_050_safe_code_portals/safe_decorator.py,sha256=AYvX7-km2reRMZ55ndO_2IS2SfHbnpyFv79AVwGg7Po,1681
28
28
  pythagoras/_050_safe_code_portals/safe_portal_core_classes.py,sha256=naY4R91N5bcCq8C_-YeBqhrr6UG8zkEQ5t8C3O8ytOw,5673
29
29
  pythagoras/_060_autonomous_code_portals/__init__.py,sha256=hnv_dxxRx8c7IDf1QgVYHfYoeVAz8oD9K0oWI_o9N20,1704
30
- pythagoras/_060_autonomous_code_portals/autonomous_decorators.py,sha256=Y5zKrCK7ROY3_0RAIz6yf47Udsr0m3Co1f1isdybBcQ,4042
30
+ pythagoras/_060_autonomous_code_portals/autonomous_decorators.py,sha256=RFNHplYQR9L2w7YxDu7A2nqpvkReAF9cEU-76neXkNQ,4155
31
31
  pythagoras/_060_autonomous_code_portals/autonomous_portal_core_classes.py,sha256=Nj4TPML94eS0WThoOfaqZhlPJu6RttvDg69VT86WPlg,9881
32
32
  pythagoras/_060_autonomous_code_portals/names_usage_analyzer.py,sha256=arfAuFBY4Dx9Zmf0b3x-axrd35QY2Kg_2jHJC8ek3p8,11977
33
33
  pythagoras/_070_protected_code_portals/__init__.py,sha256=TvGcJaz20Qqsmv8m2pA4duBtFn_CdCKfkSbOSFoJS8k,989
34
- pythagoras/_070_protected_code_portals/basic_pre_validators.py,sha256=6wrWKumBr2eyEhqpzZv8UlcX0WwUnAUzQ9D4cFyx1OE,2067
35
- pythagoras/_070_protected_code_portals/fn_arg_names_checker.py,sha256=6FjOUJmGgDCjkFcXf5Ook-E9eiEFguarY2qqzOyJj7A,1230
34
+ pythagoras/_070_protected_code_portals/basic_pre_validators.py,sha256=N5E1Gz_ULafZ8RQ1MvCQ6y29rfRVTQw7NZTqZ-pMOPo,6570
35
+ pythagoras/_070_protected_code_portals/fn_arg_names_checker.py,sha256=HZJVhdyX2xNw0e7S9Wyz0jDun-5xBuhM71Tw2zHbYXc,1603
36
36
  pythagoras/_070_protected_code_portals/list_flattener.py,sha256=9V1Xj_y5nOCXS2V9mcBFX6UsyDdOR108SBqxbC-Ziyk,1604
37
37
  pythagoras/_070_protected_code_portals/package_manager.py,sha256=KbvEGfeKQsWIz0UogVUHfW6enbBmnqo1OjJz1xMTL4o,5437
38
- pythagoras/_070_protected_code_portals/protected_decorators.py,sha256=5Y62rswuD7CD1duXd54_rhMb6-lLh7YvgdDgojP577g,1598
39
- pythagoras/_070_protected_code_portals/protected_portal_core_classes.py,sha256=pYuAxDEZKmxAN6CnqjHzFKq_5XoLZ6sEBpnJcwBPJQo,17034
38
+ pythagoras/_070_protected_code_portals/protected_decorators.py,sha256=BrVcFiMHR4nD_dZgmlGkkMi-7ee3FqYFRCwl_nT35-E,4221
39
+ pythagoras/_070_protected_code_portals/protected_portal_core_classes.py,sha256=nclgUd02KySQ1ffFSvLWMbonGcbq0SpJy2x3jLw5sAU,23419
40
40
  pythagoras/_070_protected_code_portals/system_utils.py,sha256=Uv111FaO33xAA9wZ2iwtW8Gf-FXJBP2ld1sMBmvsHdo,5124
41
41
  pythagoras/_070_protected_code_portals/validation_succesful_const.py,sha256=DrM-Mf6dDLFJ7AmfzntD39Z23YMFfF6am78XU54AlnM,577
42
- pythagoras/_080_pure_code_portals/__init__.py,sha256=OI7836lLHT51SYdFfmWp4GdGRgcAkpLiAj-Zj_g2Gxo,1052
43
- pythagoras/_080_pure_code_portals/pure_core_classes.py,sha256=6AjtE9QdiG84e9WuJtsrvkuHTRC4MovC31xItGn2PD8,20455
44
- pythagoras/_080_pure_code_portals/pure_decorator.py,sha256=WHZQzmyxgCpALHrqfeiOMrM6TDkZcv0Y2b756ez4Q2k,2279
45
- pythagoras/_080_pure_code_portals/recursion_pre_validator.py,sha256=n03ooGISJvuwNWteBN9t7CFFSLYAu86AHHFJVcywPqg,1865
42
+ pythagoras/_080_pure_code_portals/__init__.py,sha256=m9fC8hK4ve5VOJJKywAbUcyZJ9v5KiovI0O-HsXZHCg,1302
43
+ pythagoras/_080_pure_code_portals/pure_core_classes.py,sha256=GniCEvJtEwYsqIxtz0QVh8wcgTHoisVuBKkIJKkz144,26381
44
+ pythagoras/_080_pure_code_portals/pure_decorator.py,sha256=rmvtw_RpTbLjPTfy_2rdjfNSvV735hzTV_9q3drQKew,4036
45
+ pythagoras/_080_pure_code_portals/recursion_pre_validator.py,sha256=qrVBK0U6YM08tQ4rsTlKNkGbqmF3Wj2yGrnWLCAP7BY,3461
46
46
  pythagoras/_090_swarming_portals/__init__.py,sha256=TuA17PftTBudptAblNtBlD46BqUiitksOtf3y01QKm0,514
47
- pythagoras/_090_swarming_portals/output_suppressor.py,sha256=ENRtQtK_-7A94lAqtUQsIWrvtcgKniEpaWcZZZrpfQM,611
48
- pythagoras/_090_swarming_portals/swarming_portals.py,sha256=3d8sRniGdW_rKp2zKxdqoCvLA4Em1XW5xofhFtzDLf0,12696
49
- pythagoras/_100_top_level_API/__init__.py,sha256=s5LtwskY2nwkRPFKzP0PrCzQ1c9oScZO0kM9_bWLi3U,64
47
+ pythagoras/_090_swarming_portals/output_suppressor.py,sha256=IspRrfLt6pI9iuD8I1dfpnQLpRi5sO11pP5QvIGVoMo,1581
48
+ pythagoras/_090_swarming_portals/swarming_portals.py,sha256=aLHo8iFjEmd-3psFOkiYg9vCKApUD_Wv0-poxQEFu1U,19624
49
+ pythagoras/_100_top_level_API/__init__.py,sha256=Jt6VWVCBygqnwl7_-s-jhdYp6masO_SuM2xQP4a96tk,505
50
50
  pythagoras/_100_top_level_API/default_local_portal.py,sha256=SnykTpTXg1KuT1qwDnrAZ63lYshMy-0nNiUgoOVMxCs,339
51
51
  pythagoras/_100_top_level_API/top_level_API.py,sha256=S2NXW4bfL98o6Txn6NM0EeBb1nzwFtPSl-yWNevAQIE,906
52
- pythagoras/_800_signatures_and_converters/__init__.py,sha256=WAzpPe8fsh_w_7HhVxJZLBid7gxnW3pmPZW86fYnJjk,166
52
+ pythagoras/_800_signatures_and_converters/__init__.py,sha256=bva3Tyy00hC3NVEGnxU_uITXkoMHUfdHUd7pndLks0M,915
53
53
  pythagoras/_800_signatures_and_converters/base_16_32_convertors.py,sha256=-E67xY0zUUMyn-xeRpwz7-sZfFXaaiVFLKQf2OHgNw0,2146
54
54
  pythagoras/_800_signatures_and_converters/current_date_gmt_str.py,sha256=jMBQaUj_33Yto415IxuiRrNoiuxbORZS-En7bPP1JZU,841
55
55
  pythagoras/_800_signatures_and_converters/hash_signatures.py,sha256=-RDExpYwXCWXtjgIfS3xiCYAJxGuiFSZzJ4p2pAvdmc,2278
@@ -58,7 +58,7 @@ pythagoras/_800_signatures_and_converters/random_signatures.py,sha256=IpZ7uwReCd
58
58
  pythagoras/_900_project_stats_collector/__init__.py,sha256=Eagt-BhPPtBGgpMywx2lkLDK1603Y9t_QBdtHKUHHFY,71
59
59
  pythagoras/_900_project_stats_collector/project_analyzer.py,sha256=uhycFKjUIXEpYcZYnak3yn4JFhchl-oZ7wt6spFxhoY,3574
60
60
  pythagoras/__init__.py,sha256=TMPtJdSi_WShCpJnsVVdO48Wcvs78GMbUi5gHc1eMLw,1233
61
- pythagoras/core/__init__.py,sha256=cXtQ-Vbm8TqzazvkFws5cV3AEEYbEKzNXYeuHeLGFK0,328
62
- pythagoras-0.24.6.dist-info/WHEEL,sha256=X16MKk8bp2DRsAuyteHJ-9qOjzmnY0x1aj0P1ftqqWA,78
63
- pythagoras-0.24.6.dist-info/METADATA,sha256=uBQsa9SitAVOruwJdT0dxnjU6rO4fiB7BEOIh4g9D3U,7467
64
- pythagoras-0.24.6.dist-info/RECORD,,
61
+ pythagoras/core/__init__.py,sha256=yfamQZNt_7FL7vfxSoCTZq2ZL6rupp6qzcp9CHhTj3E,2674
62
+ pythagoras-0.24.8.dist-info/WHEEL,sha256=X16MKk8bp2DRsAuyteHJ-9qOjzmnY0x1aj0P1ftqqWA,78
63
+ pythagoras-0.24.8.dist-info/METADATA,sha256=yrcNe2LC_-vrLl3BsyPGTyPOJPjmjBMByp2JqDjXpZ4,7467
64
+ pythagoras-0.24.8.dist-info/RECORD,,