pythagoras 0.24.3__py3-none-any.whl → 0.24.6__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.
Files changed (33) hide show
  1. pythagoras/_020_ordinary_code_portals/code_normalizer.py +37 -9
  2. pythagoras/_020_ordinary_code_portals/function_processing.py +58 -15
  3. pythagoras/_020_ordinary_code_portals/ordinary_decorator.py +14 -0
  4. pythagoras/_020_ordinary_code_portals/ordinary_portal_core_classes.py +196 -24
  5. pythagoras/_030_data_portals/data_portal_core_classes.py +74 -22
  6. pythagoras/_030_data_portals/ready_and_get.py +45 -4
  7. pythagoras/_030_data_portals/storable_decorator.py +18 -1
  8. pythagoras/_040_logging_code_portals/exception_processing_tracking.py +30 -2
  9. pythagoras/_040_logging_code_portals/execution_environment_summary.py +60 -24
  10. pythagoras/_040_logging_code_portals/kw_args.py +74 -12
  11. pythagoras/_040_logging_code_portals/logging_decorator.py +23 -1
  12. pythagoras/_040_logging_code_portals/logging_portal_core_classes.py +365 -12
  13. pythagoras/_040_logging_code_portals/notebook_checker.py +9 -1
  14. pythagoras/_040_logging_code_portals/uncaught_exceptions.py +40 -0
  15. pythagoras/_050_safe_code_portals/safe_decorator.py +27 -1
  16. pythagoras/_050_safe_code_portals/safe_portal_core_classes.py +87 -11
  17. pythagoras/_060_autonomous_code_portals/autonomous_decorators.py +31 -4
  18. pythagoras/_060_autonomous_code_portals/autonomous_portal_core_classes.py +94 -14
  19. pythagoras/_060_autonomous_code_portals/names_usage_analyzer.py +133 -4
  20. pythagoras/_070_protected_code_portals/list_flattener.py +45 -7
  21. pythagoras/_070_protected_code_portals/package_manager.py +99 -24
  22. pythagoras/_070_protected_code_portals/protected_portal_core_classes.py +70 -0
  23. pythagoras/_070_protected_code_portals/system_utils.py +85 -12
  24. pythagoras/_070_protected_code_portals/validation_succesful_const.py +12 -7
  25. pythagoras/_090_swarming_portals/swarming_portals.py +4 -6
  26. pythagoras/_800_signatures_and_converters/base_16_32_convertors.py +55 -20
  27. pythagoras/_800_signatures_and_converters/current_date_gmt_str.py +20 -5
  28. pythagoras/_800_signatures_and_converters/hash_signatures.py +46 -10
  29. pythagoras/_800_signatures_and_converters/node_signature.py +27 -12
  30. pythagoras/_800_signatures_and_converters/random_signatures.py +14 -3
  31. {pythagoras-0.24.3.dist-info → pythagoras-0.24.6.dist-info}/METADATA +1 -1
  32. {pythagoras-0.24.3.dist-info → pythagoras-0.24.6.dist-info}/RECORD +33 -33
  33. {pythagoras-0.24.3.dist-info → pythagoras-0.24.6.dist-info}/WHEEL +0 -0
@@ -3,13 +3,41 @@ import psutil
3
3
  import pynvml
4
4
 
5
5
  def get_unused_ram_mb() -> int:
6
- """Returns the amount of available RAM in MB. """
6
+ """Get the currently available RAM on the system in megabytes (MB).
7
+
8
+ Returns:
9
+ int: Integer number of megabytes of RAM that are currently available
10
+ to user processes as reported by psutil.virtual_memory().available.
11
+
12
+ Notes:
13
+ - The value is rounded down to the nearest integer.
14
+ - Uses powers-of-two conversion (1 MB = 1024^2 bytes).
15
+ - On systems with memory compression or overcommit, this value is an
16
+ approximation provided by the OS.
17
+ """
7
18
  free_ram = psutil.virtual_memory().available / (1024 * 1024)
8
19
  return int(free_ram)
9
20
 
10
21
 
11
22
  def get_unused_cpu_cores() -> float:
12
- """Returns the free (logical) CPU capacity"""
23
+ """Estimate currently unused logical CPU capacity in units of CPU cores.
24
+
25
+ On POSIX systems with load average support, this uses the 1-minute load
26
+ average to estimate remaining capacity: max(logical_cores - load1, 0).
27
+ On other systems, it falls back to instantaneous CPU percent usage as
28
+ reported by psutil and computes: logical_cores * (1 - usage/100).
29
+
30
+ Returns:
31
+ float: A non-negative float representing approximate available logical
32
+ CPU cores. For example, 2.5 means roughly two and a half cores free.
33
+
34
+ Notes:
35
+ - The number of logical cores (with SMT/Hyper-Threading) is used.
36
+ - If psutil reports near-zero usage, a small default (0.5%) is assumed
37
+ to avoid transient 0.0 readings.
38
+ - This is a heuristic; short spikes and scheduling nuances may cause
39
+ deviations from actual availability.
40
+ """
13
41
 
14
42
  cnt = psutil.cpu_count(logical=True) or 1
15
43
 
@@ -24,7 +52,20 @@ def get_unused_cpu_cores() -> float:
24
52
 
25
53
 
26
54
  def process_is_active(pid: int) -> bool:
27
- """Checks if a process with the given PID is active."""
55
+ """Check whether a process with the given PID is currently active.
56
+
57
+ Args:
58
+ pid (int): Operating system process identifier (PID).
59
+
60
+ Returns:
61
+ bool: True if the process exists and is running; False if it does not
62
+ exist, has exited, or cannot be inspected due to permissions or other
63
+ errors.
64
+
65
+ Notes:
66
+ - Any exception from psutil (e.g., NoSuchProcess, AccessDenied) results
67
+ in a False return value for safety.
68
+ """
28
69
  try:
29
70
  process = psutil.Process(pid)
30
71
  return process.is_running()
@@ -33,7 +74,19 @@ def process_is_active(pid: int) -> bool:
33
74
 
34
75
 
35
76
  def get_process_start_time(pid: int) -> int:
36
- """Returns the start time of the process with the given PID."""
77
+ """Get the UNIX timestamp of when a process started.
78
+
79
+ Args:
80
+ pid (int): Operating system process identifier (PID).
81
+
82
+ Returns:
83
+ int: Start time as a UNIX timestamp (seconds since epoch). Returns 0 if
84
+ the process does not exist or cannot be accessed.
85
+
86
+ Notes:
87
+ - Any exception from psutil (e.g., NoSuchProcess, AccessDenied) results
88
+ in a 0 return value for safety.
89
+ """
37
90
  try:
38
91
  process = psutil.Process(pid)
39
92
  return int(process.create_time())
@@ -42,21 +95,41 @@ def get_process_start_time(pid: int) -> int:
42
95
 
43
96
 
44
97
  def get_current_process_id() -> int:
45
- """Returns the current process ID."""
98
+ """Get the current process ID (PID).
99
+
100
+ Returns:
101
+ int: The PID of the running Python process.
102
+ """
46
103
  return psutil.Process().pid
47
104
 
48
105
 
49
106
  def get_current_process_start_time() -> int:
50
- """Returns the start time of the current process."""
107
+ """Get the UNIX timestamp for when the current Python process started.
108
+
109
+ Returns:
110
+ int: Start time as a UNIX timestamp (seconds since epoch). Returns 0 on
111
+ unexpected error.
112
+ """
51
113
  return get_process_start_time(get_current_process_id())
52
114
 
53
115
 
54
116
  def get_unused_nvidia_gpus() -> float:
55
- """Returns the total unused GPU capacity as a float value.
56
-
57
- The function calculates the sum of unused capacity across all available NVIDIA GPUs.
58
- For example, 2.0 means two completely unused GPUs
59
- 0 is returned if no GPUs or on error.
117
+ """Estimate the total unused NVIDIA GPU capacity across all devices.
118
+
119
+ This aggregates the per-GPU unused utilization percentage (100 - gpu%) and
120
+ returns the sum in "GPU units". For example, 2.0 means capacity equivalent
121
+ to two fully idle GPUs. If no NVIDIA GPUs are present or NVML is unavailable,
122
+ the function returns 0.0.
123
+
124
+ Returns:
125
+ float: Sum of unused GPU capacity across all NVIDIA GPUs in GPU units.
126
+
127
+ Notes:
128
+ - Requires NVIDIA Management Library (pynvml) to be installed and the
129
+ NVIDIA driver to be available.
130
+ - Utilization is based on instantaneous NVML readings and may fluctuate.
131
+ - Any NVML error (e.g., no devices, driver issues) results in 0.0 for
132
+ safety.
60
133
  """
61
134
  try:
62
135
  pynvml.nvmlInit()
@@ -70,7 +143,7 @@ def get_unused_nvidia_gpus() -> float:
70
143
 
71
144
  return unused_capacity / 100.0
72
145
 
73
- except pynvml.NVMLError as e:
146
+ except pynvml.NVMLError:
74
147
  # Return 0.0 on any NVML error (no GPUs, driver issues, etc.)
75
148
  return 0.0
76
149
  finally:
@@ -1,11 +1,16 @@
1
- class ValidationSuccessFlag:
2
- """Singleton class to represent a successful validation."""
1
+ from persidict.singletons import Singleton
3
2
 
4
- _instance = None
5
3
 
6
- def __new__(cls):
7
- if cls._instance is None:
8
- cls._instance = super().__new__(cls)
9
- return cls._instance
4
+ class ValidationSuccessFlag(Singleton):
5
+ """Marker singleton indicating that validation has succeeded.
10
6
 
7
+ This lightweight class is used as a unique sentinel object that signals a
8
+ successful validation outcome in protected code portals. Using a singleton
9
+ avoids ambiguity with other truthy values.
10
+ """
11
+ pass
12
+
13
+
14
+ # A canonical, importable singleton value representing a successful validation.
15
+ # Use identity checks (``is VALIDATION_SUCCESSFUL``) rather than equality.
11
16
  VALIDATION_SUCCESSFUL = ValidationSuccessFlag()
@@ -23,7 +23,7 @@ from parameterizable import (
23
23
  access_jsparams)
24
24
  from persidict import PersiDict, Joker, KEEP_CURRENT
25
25
 
26
- from parameterizable.json_processor import _Markers
26
+ from parameterizable import *
27
27
 
28
28
  from .. import VALIDATION_SUCCESSFUL
29
29
  from .._010_basic_portals import get_all_known_portals
@@ -212,10 +212,8 @@ class SwarmingPortal(PureCodePortal):
212
212
  del self._max_n_workers_cache
213
213
  super()._invalidate_cache()
214
214
 
215
- # parameterizable.register_parameterizable_class(SwarmingPortal)
216
215
 
217
-
218
- def _launch_many_background_workers(portal_init_jsparams:JsonSerializedParams) -> None:
216
+ def _launch_many_background_workers(portal_init_jsparams:JsonSerializedObject) -> None:
219
217
  """Launch many background worker processes."""
220
218
 
221
219
 
@@ -265,7 +263,7 @@ def _launch_many_background_workers(portal_init_jsparams:JsonSerializedParams) -
265
263
  list_of_all_workers = new_list_of_all_workers
266
264
 
267
265
 
268
- def _background_worker(portal_init_jsparams:JsonSerializedParams) -> None:
266
+ def _background_worker(portal_init_jsparams:JsonSerializedObject) -> None:
269
267
  """Background worker that keeps processing random execution requests."""
270
268
  portal = parameterizable.loadjs(portal_init_jsparams)
271
269
  assert isinstance(portal, SwarmingPortal)
@@ -283,7 +281,7 @@ def _background_worker(portal_init_jsparams:JsonSerializedParams) -> None:
283
281
  portal._randomly_delay_execution()
284
282
 
285
283
 
286
- def _process_random_execution_request(portal_init_jsparams:JsonSerializedParams):
284
+ def _process_random_execution_request(portal_init_jsparams:JsonSerializedObject):
287
285
  """Process one random execution request."""
288
286
  # portal = parameterizable.get_object_from_portable_params(
289
287
  # portal_init_params)
@@ -1,48 +1,83 @@
1
+ from typing import Final
1
2
 
2
- base32_alphabet = '0123456789abcdefghijklmnopqrstuv'
3
- base32_alphabet_map = {char:index for index,char in enumerate(base32_alphabet)}
3
+ _BASE32_ALPHABET: Final[str] = '0123456789abcdefghijklmnopqrstuv'
4
+ _BASE32_ALPHABET_MAP: Final[dict[str, int]] = {
5
+ char:index for index,char in enumerate(_BASE32_ALPHABET)}
4
6
 
5
7
 
6
8
  def convert_base16_to_base32(hexdigest: str) -> str:
7
- """
8
- Convert a hexadecimal (base 16) string to a base 32 string.
9
+ """Convert a hexadecimal (base16) string to this project's base32.
10
+
11
+ Args:
12
+ hexdigest (str): A hexadecimal string (case-insensitive). May be an
13
+ empty string or "0" to represent zero.
9
14
 
10
- :name hexdigest: A string representing a hexadecimal number.
11
- :return: A string representing the equivalent number in base 32.
15
+ Returns:
16
+ str: The corresponding value encoded with the custom base32 alphabet
17
+ (digits 0-9 then letters a-v).
18
+
19
+ Examples:
20
+ >>> convert_base16_to_base32("ff")
21
+ '7v'
12
22
  """
13
23
 
14
- if not hexdigest:
15
- return '0'
16
- num = int(hexdigest,16)
24
+ try:
25
+ num = int(hexdigest, 16)
26
+ except ValueError as e:
27
+ raise ValueError(f"Invalid hexadecimal string: {hexdigest}") from e
28
+
17
29
  base32_str = convert_int_to_base32(num)
18
30
 
19
31
  return base32_str
20
32
 
21
33
 
22
34
  def convert_int_to_base32(n: int) -> str:
23
- """
24
- Convert an integer to a base 32 string.
35
+ """Convert a non-negative integer to Pythagoras' base32 string.
36
+
37
+ Args:
38
+ n (int): Non-negative integer to encode.
39
+
40
+ Returns:
41
+ str: The base32 representation.
25
42
 
26
- :name n: An integer.
27
- :return: A string representing the equivalent number in base 32.
43
+ Raises:
44
+ ValueError: If n is negative.
28
45
  """
46
+ if n < 0:
47
+ raise ValueError("n must be non-negative")
48
+
49
+ if n == 0:
50
+ return "0"
51
+
29
52
  base32_str = ''
30
53
  while n > 0:
31
- base32_str = base32_alphabet[n & 31] + base32_str
54
+ base32_str = _BASE32_ALPHABET[n & 31] + base32_str
32
55
  n >>= 5
33
56
 
34
57
  return base32_str
35
58
 
36
59
  def convert_base_32_to_int(digest: str) -> int:
37
- """
38
- Convert a base 32 string to an integer.
60
+ """Convert a base32 string (custom alphabet) to an integer.
39
61
 
40
- :name digest: A string representing a number in base 32.
41
- :return: An integer representing the equivalent number.
62
+ Args:
63
+ digest (str): String encoded with Pythagoras' base32 alphabet.
64
+
65
+ Returns:
66
+ int: The decoded non-negative integer value.
67
+
68
+ Raises:
69
+ KeyError: If digest contains a character outside the supported
70
+ base32 alphabet (0-9, a-v).
42
71
  """
72
+ if not digest:
73
+ raise ValueError("Digest cannot be empty")
74
+
43
75
  digest = digest.lower()
44
76
  num = 0
45
- for char in digest:
46
- num = num * 32 + base32_alphabet_map[char]
77
+ try:
78
+ for char in digest:
79
+ num = num * 32 + _BASE32_ALPHABET_MAP[char]
80
+ except KeyError as e:
81
+ raise ValueError(f"Invalid character '{e.args[0]}' in base32 digest: {digest}") from e
47
82
  return num
48
83
 
@@ -1,11 +1,26 @@
1
1
  from datetime import datetime, timezone
2
+ from typing import Final
2
3
 
4
+ _MONTH_ABBREVIATIONS: Final[tuple[str, ...]] = (
5
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
6
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec")
3
7
 
4
- def current_date_gmt_string():
5
- """ Return the current date and time in the format '2024_12Jan_22_utc'
8
+
9
+ def current_date_gmt_string() -> str:
10
+ """Get the current UTC date as a compact string.
11
+
12
+ Produces an underscore-delimited UTC date string suitable for
13
+ stable file names and log records.
14
+
15
+ The format is: "YYYY_MMMonAbbrev_dd_utc" (e.g., "2024_12Dec_11_utc").
16
+
17
+ Returns:
18
+ str: The formatted UTC date string, for the current moment.
6
19
  """
7
20
 
8
21
  utc_now = datetime.now(timezone.utc)
9
- date_str = utc_now.strftime("%Y_%m%b_%d_utc")
10
-
11
- return date_str
22
+ month_abbrev = _MONTH_ABBREVIATIONS[utc_now.month - 1]
23
+ # locale-dependent month abbreviation
24
+ result = (f"{utc_now.year}_{utc_now.month:02d}{month_abbrev}" +
25
+ f"_{utc_now.day:02d}_utc")
26
+ return result
@@ -1,33 +1,69 @@
1
1
  import sys
2
- from typing import Any
2
+ from typing import Any, Final
3
3
 
4
4
  import joblib.hashing
5
5
 
6
6
  from .base_16_32_convertors import convert_base16_to_base32
7
7
 
8
8
 
9
- hash_type: str = "sha256"
10
- max_signature_length: int = 22
9
+ _HASH_TYPE: Final[str] = "sha256"
10
+ _MAX_SIGNATURE_LENGTH: Final[int] = 22
11
11
 
12
12
  def get_base16_hash_signature(x:Any) -> str:
13
- """Return base16 hash signature of an object.
13
+ """Compute a hexadecimal (base16) hash for an arbitrary Python object.
14
14
 
15
- Uses joblib's Hasher (or NumpyHasher). It uses Pickle for serialization,
16
- except for NumPy arrays, which use optimized custom routines.
15
+ This function delegates to joblib's hashing utilities. If NumPy is
16
+ imported in the current process, it uses NumpyHasher for efficient and
17
+ stable hashing of NumPy arrays; otherwise it uses the generic Hasher.
18
+
19
+ Args:
20
+ x (Any): The object to hash. Must be picklable by joblib unless a
21
+ specialized routine (e.g., for NumPy arrays) is available.
22
+
23
+ Returns:
24
+ str: A hexadecimal string digest computed with the configured
25
+ algorithm (sha256 by default).
26
+
27
+ Notes:
28
+ - joblib relies on pickle for most Python objects; ensure that custom
29
+ objects are picklable for stable results.
30
+ - The digest is deterministic for the same object content.
17
31
  """
18
32
  if 'numpy' in sys.modules:
19
- hasher = joblib.hashing.NumpyHasher(hash_name=hash_type)
33
+ hasher = joblib.hashing.NumpyHasher(hash_name=_HASH_TYPE)
20
34
  else:
21
- hasher = joblib.hashing.Hasher(hash_name=hash_type)
35
+ hasher = joblib.hashing.Hasher(hash_name=_HASH_TYPE)
22
36
  hash_signature = hasher.hash(x)
23
37
  return str(hash_signature)
24
38
 
25
39
  def get_base32_hash_signature(x:Any) -> str:
26
- """Return base32 hash signature of an object"""
40
+ """Compute a base32-encoded hash for an arbitrary Python object.
41
+
42
+ Internally computes a hexadecimal digest first, then converts it to the
43
+ custom base32 alphabet used by Pythagoras.
44
+
45
+ Args:
46
+ x (Any): The object to hash.
47
+
48
+ Returns:
49
+ str: The full-length base32 digest string (not truncated).
50
+ """
27
51
  base_16_hash = get_base16_hash_signature(x)
28
52
  base_32_hash = convert_base16_to_base32(base_16_hash)
29
53
  return base_32_hash
30
54
 
31
55
  def get_hash_signature(x:Any) -> str:
32
- return get_base32_hash_signature(x)[:max_signature_length]
56
+ """Compute a short, URL-safe hash signature for an object.
57
+
58
+ This is a convenience wrapper that returns the first max_signature_length
59
+ characters of the base32 digest, which is typically sufficient for
60
+ collision-resistant identifiers in logs and filenames.
61
+
62
+ Args:
63
+ x (Any): The object to hash.
64
+
65
+ Returns:
66
+ str: The truncated base32 digest string.
67
+ """
68
+ return get_base32_hash_signature(x)[:_MAX_SIGNATURE_LENGTH]
33
69
 
@@ -1,4 +1,6 @@
1
- import uuid, platform, getpass
1
+ import getpass
2
+ import platform
3
+ import uuid
2
4
  from functools import cache
3
5
 
4
6
  from .hash_signatures import get_hash_signature
@@ -6,15 +8,28 @@ from .hash_signatures import get_hash_signature
6
8
 
7
9
  @cache
8
10
  def get_node_signature() -> str:
9
- """Returns a globally-unique signature for the current computing node.
11
+ """Return a stable signature for the current computing node and user.
12
+
13
+ The signature is derived from a concatenation of multiple system- and
14
+ user-specific attributes (MAC address, OS info, CPU, username) and then
15
+ hashed using Pythagoras' short base32 digest. The result is intended to
16
+ uniquely identify the node within logs and distributed systems.
17
+
18
+ Caching:
19
+ The result is cached for the lifetime of the process using
20
+ functools.cache, as the underlying attributes are not expected to
21
+ change while the process is running.
22
+
23
+ Returns:
24
+ str: A short base32 signature string representing this node.
10
25
  """
11
- mac = uuid.getnode()
12
- system = platform.system()
13
- release = platform.release()
14
- version = platform.version()
15
- machine = platform.machine()
16
- processor = platform.processor()
17
- user = getpass.getuser()
18
- id_string = f"{mac}{system}{release}{version}"
19
- id_string += f"{machine}{processor}{user}"
20
- return get_hash_signature(id_string)
26
+ id_parts = [
27
+ str(uuid.getnode()),
28
+ platform.system(),
29
+ platform.release(),
30
+ platform.version(),
31
+ platform.machine(),
32
+ platform.processor(),
33
+ getpass.getuser(),
34
+ ]
35
+ return get_hash_signature("".join(id_parts))
@@ -1,11 +1,22 @@
1
1
  import uuid
2
+ from typing import Final
2
3
 
3
4
  from .base_16_32_convertors import convert_int_to_base32
4
5
 
5
- max_signature_length: int = 22
6
+ _MAX_SIGNATURE_LENGTH: Final[int] = 22
6
7
 
7
8
  def get_random_signature() -> str:
8
- # random_int = uuid.uuid4().int + uuid.uuid1().int
9
+ """Generate a short, random base32 signature string.
10
+
11
+ The randomness is sourced from uuid.uuid4(), which uses a cryptographically
12
+ strong RNG provided by the OS. The resulting large integer is encoded with
13
+ Pythagoras' base32 alphabet and truncated to max_signature_length
14
+ characters.
15
+
16
+ Returns:
17
+ str: A random, URL-safe base32 string of length up to
18
+ max_signature_length.
19
+ """
9
20
  random_int = uuid.uuid4().int
10
21
  random_str = convert_int_to_base32(random_int)
11
- return random_str[:max_signature_length]
22
+ return random_str[:_MAX_SIGNATURE_LENGTH]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pythagoras
3
- Version: 0.24.3
3
+ Version: 0.24.6
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
@@ -6,59 +6,59 @@ pythagoras/_010_basic_portals/long_infoname.py,sha256=KXOmHfQ_5hdZNqfB3Cif2CQiZ3
6
6
  pythagoras/_010_basic_portals/portal_tester.py,sha256=x6HiJ3GW9XWplnsT6Ob7QCy2J_JPgGpdaJ8QRyFH-e8,3353
7
7
  pythagoras/_010_basic_portals/post_init_metaclass.py,sha256=94FEVMCJBUReRb-fo2-LW8YWXUXw5lLLYlXMnlxHJuU,1495
8
8
  pythagoras/_020_ordinary_code_portals/__init__.py,sha256=p3kSqaQYj0xlhk9BwptFgA1USdTbfHkAB5Q9MH-ANI0,1295
9
- pythagoras/_020_ordinary_code_portals/code_normalizer.py,sha256=7L3P5AaZKS9IPqrIEv5UJc3HHDP48fw6EGQWXZcxQtM,5004
10
- pythagoras/_020_ordinary_code_portals/function_processing.py,sha256=rlhB0dpaUztv6SM2wlUdaUdETcV2pVUICYufVrQCRcc,3623
11
- pythagoras/_020_ordinary_code_portals/ordinary_decorator.py,sha256=J4qx03NEEgpYWvg4D8UkAL0PdtAt2sQyMN1op6LMFsA,1028
12
- pythagoras/_020_ordinary_code_portals/ordinary_portal_core_classes.py,sha256=bY2Hzy19lTezv96dSc1l5SsaGxNkMTOq8IsfnkdV1wY,9743
9
+ pythagoras/_020_ordinary_code_portals/code_normalizer.py,sha256=GJXvBX85W230OcwNAg8XXHAE4m39Q70piJ9g2jcIr4Q,6616
10
+ pythagoras/_020_ordinary_code_portals/function_processing.py,sha256=b9Y4vNf1KSRkpUfS9UmWj3N_CNuPDgUMXdnR3IeyAoM,5021
11
+ pythagoras/_020_ordinary_code_portals/ordinary_decorator.py,sha256=ETmy-HKRzCJfzTPOI-gelQT2tlJpVLRu4I85yv02vuo,1437
12
+ pythagoras/_020_ordinary_code_portals/ordinary_portal_core_classes.py,sha256=C5nobGkYZBi2IHc1Pjfxjx_8h_ajF3Sf9Jq3yxFIR68,15963
13
13
  pythagoras/_030_data_portals/__init__.py,sha256=f_F9DCmuVgPMgzwRjuNj6FI63S3oXu7lj3zU66Nw7Hc,1427
14
- pythagoras/_030_data_portals/data_portal_core_classes.py,sha256=CJmJD2uzZwDuk8lQEJbpWAtN25UF57tkKYTot_yZmfo,20418
15
- pythagoras/_030_data_portals/ready_and_get.py,sha256=UKiQHkLhdAdvEwP5BTdoAnp4XEs7HDGx6026M2eMuc0,2842
16
- pythagoras/_030_data_portals/storable_decorator.py,sha256=l8W3GhVmIscgjoCTGq3tmdehKGDLIVnFbTM-GW-1G4g,578
14
+ pythagoras/_030_data_portals/data_portal_core_classes.py,sha256=D_Zg-q15II7IwweEGdBAMhGt09DYN_v_G0XFb5K3WB4,22459
15
+ pythagoras/_030_data_portals/ready_and_get.py,sha256=lgkDygF4lFnZXcCvP5dmvzQX64wrZ8AnYJTI7v2ppng,4172
16
+ pythagoras/_030_data_portals/storable_decorator.py,sha256=u70K8J44NTlofc4HmKHtxxbwKdUkBz6BDsIWds4dALQ,1160
17
17
  pythagoras/_040_logging_code_portals/__init__.py,sha256=q2hVyOVgE-9Ru3ycilK98YS9Rat8tSc6erd7AtGxpaA,996
18
- pythagoras/_040_logging_code_portals/exception_processing_tracking.py,sha256=sU-FCayvppF6gafBRAKsJcMC0JMBcnCCiLzu3yFmxiA,778
19
- pythagoras/_040_logging_code_portals/execution_environment_summary.py,sha256=hTvTbadYAtisZ4H8rq-n_hsKPCS38jsSz8lw_A1DIqY,2268
20
- pythagoras/_040_logging_code_portals/kw_args.py,sha256=4EYpPrr2xCgFAarmdFRKlEvGhIHC9kk9kc-VPW4S-XA,2717
21
- pythagoras/_040_logging_code_portals/logging_decorator.py,sha256=079w2_Z5HhXFLrgyXQekjuOby9CdUgFUGRbRT5lpujU,891
22
- pythagoras/_040_logging_code_portals/logging_portal_core_classes.py,sha256=FZ_tFg6tVO-kCCXR3X9FLLXxe_5M7tHtkrSmyYhM9f4,21953
23
- pythagoras/_040_logging_code_portals/notebook_checker.py,sha256=5lQJDIDzhRIRSmX1T88nAREMEMoDDFf0OIKcvTpnhzk,541
18
+ pythagoras/_040_logging_code_portals/exception_processing_tracking.py,sha256=DH1eeJAeVL6Fn-6sXBqx3Ocu2RXxVhLqdH1mvhM24VY,1850
19
+ pythagoras/_040_logging_code_portals/execution_environment_summary.py,sha256=-0ynNibGfRh3J1Sq-N9j7eN1FlGvetEBiW0L4K_qJ30,3813
20
+ pythagoras/_040_logging_code_portals/kw_args.py,sha256=j3Iao80gTBjPx6dk1Azd9D8pcdQ3QdfpkQtQq-4ATV0,4954
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
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
- pythagoras/_040_logging_code_portals/uncaught_exceptions.py,sha256=B3bPvX5nnJJx4JjLSGdl1xXOBU2pqo3CP-MomJAfXaE,3121
25
+ pythagoras/_040_logging_code_portals/uncaught_exceptions.py,sha256=vQrY1mOYdAeKaCmCCY1MUy4xoXurQkfwQuDA43giPl0,4564
26
26
  pythagoras/_050_safe_code_portals/__init__.py,sha256=YR-V6W2WZ17SjqmTyY2xdY16xTVEEuLs2MddJj_WCZU,557
27
- pythagoras/_050_safe_code_portals/safe_decorator.py,sha256=ZTsIMmtb3eGAWSpwdMYXRmIyaJiqV6mdFbB_Mqng784,804
28
- pythagoras/_050_safe_code_portals/safe_portal_core_classes.py,sha256=G1jYgKaOzkzYxIBMvlLYKMPk2OOpK_SQzMQVsHfBJqY,2562
27
+ pythagoras/_050_safe_code_portals/safe_decorator.py,sha256=AYvX7-km2reRMZ55ndO_2IS2SfHbnpyFv79AVwGg7Po,1681
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=diWX03jZaInc55jAg391ZRBh-St5exJRLDZiS7dqYvg,2895
31
- pythagoras/_060_autonomous_code_portals/autonomous_portal_core_classes.py,sha256=21JNwBgEoIHXwCrBPb_eN5vMaHTZ98LdFkHuaMHtkI0,6665
32
- pythagoras/_060_autonomous_code_portals/names_usage_analyzer.py,sha256=mqrzAQw3tGxPYXsMA8E0fhhIpJopvRFrzkc1MVSsPXQ,7474
30
+ pythagoras/_060_autonomous_code_portals/autonomous_decorators.py,sha256=Y5zKrCK7ROY3_0RAIz6yf47Udsr0m3Co1f1isdybBcQ,4042
31
+ pythagoras/_060_autonomous_code_portals/autonomous_portal_core_classes.py,sha256=Nj4TPML94eS0WThoOfaqZhlPJu6RttvDg69VT86WPlg,9881
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
34
  pythagoras/_070_protected_code_portals/basic_pre_validators.py,sha256=6wrWKumBr2eyEhqpzZv8UlcX0WwUnAUzQ9D4cFyx1OE,2067
35
35
  pythagoras/_070_protected_code_portals/fn_arg_names_checker.py,sha256=6FjOUJmGgDCjkFcXf5Ook-E9eiEFguarY2qqzOyJj7A,1230
36
- pythagoras/_070_protected_code_portals/list_flattener.py,sha256=mlS1Eq2dwgHbNI55CPXKXzbRca49pDNRHTgCOmuo1LU,331
37
- pythagoras/_070_protected_code_portals/package_manager.py,sha256=QRHXGIatzx6NKPPC06CMijUmASl_mrPwikVBWG7Z03Y,1965
36
+ pythagoras/_070_protected_code_portals/list_flattener.py,sha256=9V1Xj_y5nOCXS2V9mcBFX6UsyDdOR108SBqxbC-Ziyk,1604
37
+ pythagoras/_070_protected_code_portals/package_manager.py,sha256=KbvEGfeKQsWIz0UogVUHfW6enbBmnqo1OjJz1xMTL4o,5437
38
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=ZTSD6m9HGTJDa9WuInb-0wqzP8NzaoIqWapg9XUXD-E,13583
40
- pythagoras/_070_protected_code_portals/system_utils.py,sha256=h4oiEQFAyFKzqvd0ywwAI0WDYKSuIh_vif86XQIXYwE,2360
41
- pythagoras/_070_protected_code_portals/validation_succesful_const.py,sha256=4NWGwN5Gu6kbbHTMkmJs8Ym0rFee_cIE2VlAPonmlJI,298
39
+ pythagoras/_070_protected_code_portals/protected_portal_core_classes.py,sha256=pYuAxDEZKmxAN6CnqjHzFKq_5XoLZ6sEBpnJcwBPJQo,17034
40
+ pythagoras/_070_protected_code_portals/system_utils.py,sha256=Uv111FaO33xAA9wZ2iwtW8Gf-FXJBP2ld1sMBmvsHdo,5124
41
+ pythagoras/_070_protected_code_portals/validation_succesful_const.py,sha256=DrM-Mf6dDLFJ7AmfzntD39Z23YMFfF6am78XU54AlnM,577
42
42
  pythagoras/_080_pure_code_portals/__init__.py,sha256=OI7836lLHT51SYdFfmWp4GdGRgcAkpLiAj-Zj_g2Gxo,1052
43
43
  pythagoras/_080_pure_code_portals/pure_core_classes.py,sha256=6AjtE9QdiG84e9WuJtsrvkuHTRC4MovC31xItGn2PD8,20455
44
44
  pythagoras/_080_pure_code_portals/pure_decorator.py,sha256=WHZQzmyxgCpALHrqfeiOMrM6TDkZcv0Y2b756ez4Q2k,2279
45
45
  pythagoras/_080_pure_code_portals/recursion_pre_validator.py,sha256=n03ooGISJvuwNWteBN9t7CFFSLYAu86AHHFJVcywPqg,1865
46
46
  pythagoras/_090_swarming_portals/__init__.py,sha256=TuA17PftTBudptAblNtBlD46BqUiitksOtf3y01QKm0,514
47
47
  pythagoras/_090_swarming_portals/output_suppressor.py,sha256=ENRtQtK_-7A94lAqtUQsIWrvtcgKniEpaWcZZZrpfQM,611
48
- pythagoras/_090_swarming_portals/swarming_portals.py,sha256=ZZuzkAf4Ls9oZyg_yUbj3kEEmXGTPjTCevVh-w7AAkE,12784
48
+ pythagoras/_090_swarming_portals/swarming_portals.py,sha256=3d8sRniGdW_rKp2zKxdqoCvLA4Em1XW5xofhFtzDLf0,12696
49
49
  pythagoras/_100_top_level_API/__init__.py,sha256=s5LtwskY2nwkRPFKzP0PrCzQ1c9oScZO0kM9_bWLi3U,64
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
52
  pythagoras/_800_signatures_and_converters/__init__.py,sha256=WAzpPe8fsh_w_7HhVxJZLBid7gxnW3pmPZW86fYnJjk,166
53
- pythagoras/_800_signatures_and_converters/base_16_32_convertors.py,sha256=ZjVtKjjjMgMgHUhM-1Q9qLYWCDKhllqq9z4YgKL0qCg,1236
54
- pythagoras/_800_signatures_and_converters/current_date_gmt_str.py,sha256=K-rGHyrREsyBdYMq7vWrv3FdAacepWQpvOfT_mrZqNM,268
55
- pythagoras/_800_signatures_and_converters/hash_signatures.py,sha256=AsUID_Z7yeF06Jmk8kKAFXIuxoF0hN0OwOS1T5nu7_k,989
56
- pythagoras/_800_signatures_and_converters/node_signature.py,sha256=pSZ4yB4aXNH6yhizQ6Z3m4uRcuDNkr_-lZ8024NbZ7w,592
57
- pythagoras/_800_signatures_and_converters/random_signatures.py,sha256=wXTyjATM8IwMXq2vHhoAq6T-yI7DcN72Svyt05EjFBo,323
53
+ pythagoras/_800_signatures_and_converters/base_16_32_convertors.py,sha256=-E67xY0zUUMyn-xeRpwz7-sZfFXaaiVFLKQf2OHgNw0,2146
54
+ pythagoras/_800_signatures_and_converters/current_date_gmt_str.py,sha256=jMBQaUj_33Yto415IxuiRrNoiuxbORZS-En7bPP1JZU,841
55
+ pythagoras/_800_signatures_and_converters/hash_signatures.py,sha256=-RDExpYwXCWXtjgIfS3xiCYAJxGuiFSZzJ4p2pAvdmc,2278
56
+ pythagoras/_800_signatures_and_converters/node_signature.py,sha256=W5Rg6q0jBRRJzHnnemt8mVapoy2jIswOEg9xIm4poXo,1090
57
+ pythagoras/_800_signatures_and_converters/random_signatures.py,sha256=IpZ7uwReCd-K9Yq1IZoubxn7kidnRfpB9-GBKXdqYdA,719
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
61
  pythagoras/core/__init__.py,sha256=cXtQ-Vbm8TqzazvkFws5cV3AEEYbEKzNXYeuHeLGFK0,328
62
- pythagoras-0.24.3.dist-info/WHEEL,sha256=X16MKk8bp2DRsAuyteHJ-9qOjzmnY0x1aj0P1ftqqWA,78
63
- pythagoras-0.24.3.dist-info/METADATA,sha256=tOfVHjizrk-0w3mhvbdhqpSNY-z3U_BhhMuYsa-CCVE,7467
64
- pythagoras-0.24.3.dist-info/RECORD,,
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,,