pythagoras 0.8.5__tar.gz → 0.8.9__tar.gz
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-0.8.5/pythagoras.egg-info → pythagoras-0.8.9}/PKG-INFO +7 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/README.md +3 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_01_foundational_objects/hash_addresses.py +2 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_01_foundational_objects/value_addresses.py +5 -4
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/ordinary_funcs.py +5 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/autonomous_decorators.py +1 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/autonomous_funcs.py +28 -25
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/__init__.py +1 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/idempotent_decorator.py +1 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/idempotent_func_and_address.py +111 -10
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/kw_args.py +1 -1
- pythagoras-0.8.9/pythagoras/_05_events_and_exceptions/__init__.py +2 -0
- pythagoras-0.8.5/pythagoras/_99_misc_utils/context_builder.py → pythagoras-0.8.9/pythagoras/_05_events_and_exceptions/context_utils.py +13 -5
- pythagoras-0.8.9/pythagoras/_05_events_and_exceptions/event_logger.py +88 -0
- {pythagoras-0.8.5/pythagoras/_99_misc_utils → pythagoras-0.8.9/pythagoras/_05_events_and_exceptions}/find_in_callstack.py +13 -10
- pythagoras-0.8.9/pythagoras/_05_events_and_exceptions/type_retrievers.py +30 -0
- pythagoras-0.8.9/pythagoras/_05_events_and_exceptions/uncaught_exception_handlers.py +62 -0
- {pythagoras-0.8.5/pythagoras/_05_mission_control → pythagoras-0.8.9/pythagoras/_06_mission_control}/__events_and_exceptions_OLD__.py +1 -1
- {pythagoras-0.8.5/pythagoras/_05_mission_control → pythagoras-0.8.9/pythagoras/_06_mission_control}/__init__.py +2 -2
- {pythagoras-0.8.5/pythagoras/_05_mission_control → pythagoras-0.8.9/pythagoras/_06_mission_control}/global_state_management.py +59 -34
- {pythagoras-0.8.5/pythagoras/_05_mission_control → pythagoras-0.8.9/pythagoras/_06_mission_control}/summary.py +2 -2
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/__init__.py +0 -3
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/NEW_hash_address.py +1 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/__init__.py +11 -4
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/__main__.py +1 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9/pythagoras.egg-info}/PKG-INFO +7 -1
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras.egg-info/SOURCES.txt +12 -10
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras.egg-info/requires.txt +3 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/setup.py +7 -3
- pythagoras-0.8.5/pythagoras/_05_mission_control/events_and_exceptions_core.py +0 -89
- pythagoras-0.8.5/pythagoras/_99_misc_utils/isinstance_txt.py +0 -34
- {pythagoras-0.8.5 → pythagoras-0.8.9}/LICENSE +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pyproject.toml +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/NEW_exception_logging.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/OLD__main__.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/OLD_p_cloud.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/OLD_utils.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_01_foundational_objects/__init__.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_01_foundational_objects/hash_signature.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/__init__.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/assert_ordinarity.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/check_n_positional_args.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/code_normalizer.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/code_normalizer_implementation.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_02_ordinary_functions/ordinary_decorator.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/__init__.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/autonomicity_checks.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/call_graph_explorer.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/default_island_singleton.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/names_usage_analyzer.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/astkeywords_dict_convertors.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/idempotency_checks.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/process_augmented_func_src.py +0 -0
- {pythagoras-0.8.5/pythagoras/_99_misc_utils → pythagoras-0.8.9/pythagoras/_05_events_and_exceptions}/current_date_gmt_str.py +0 -0
- {pythagoras-0.8.5/pythagoras/_99_misc_utils → pythagoras-0.8.9/pythagoras/_05_events_and_exceptions}/notebook_checker.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/base_16_32_convertors.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/function_name.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/id_examiner.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/long_infoname.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/output_capturer.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/package_manager.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_99_misc_utils/random_safe_str_creator.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_dependency_discovery.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_environmental.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_package_dependencies.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_persidicts.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_persiout.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/OLD_persistent_dicts.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/__init__.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/________OLD________/test_package_dependencies.py +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras.egg-info/dependency_links.txt +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras.egg-info/top_level.txt +0 -0
- {pythagoras-0.8.5 → pythagoras-0.8.9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pythagoras
|
3
|
-
Version: 0.8.
|
3
|
+
Version: 0.8.9
|
4
4
|
Summary: Simple framework for planet-scale idempotent computations in Python.
|
5
5
|
Home-page: https://github.com/vladlpavlov/pythagoras
|
6
6
|
Author: Volodymyr (Vlad) Pavlov
|
@@ -34,6 +34,9 @@ Requires-Dist: boto3
|
|
34
34
|
Requires-Dist: moto
|
35
35
|
Requires-Dist: pytest
|
36
36
|
Requires-Dist: autopep8
|
37
|
+
Requires-Dist: torch
|
38
|
+
Requires-Dist: keras
|
39
|
+
Requires-Dist: tensorflow
|
37
40
|
|
38
41
|
# Pythagoras
|
39
42
|
|
@@ -74,6 +77,9 @@ at the Python package index at: https://pypi.org/project/pythagoras
|
|
74
77
|
* [jsonpickle](https://jsonpickle.github.io)
|
75
78
|
* [scikit-learn](https://scikit-learn.org)
|
76
79
|
* [autopep8](https://pypi.org/project/autopep8)
|
80
|
+
* [pytorch](https://pytorch.org)
|
81
|
+
* [tensorflow](https://www.tensorflow.org)
|
82
|
+
* [keras](https://keras.io)
|
77
83
|
|
78
84
|
## Key Contacts
|
79
85
|
|
@@ -37,6 +37,9 @@ at the Python package index at: https://pypi.org/project/pythagoras
|
|
37
37
|
* [jsonpickle](https://jsonpickle.github.io)
|
38
38
|
* [scikit-learn](https://scikit-learn.org)
|
39
39
|
* [autopep8](https://pypi.org/project/autopep8)
|
40
|
+
* [pytorch](https://pytorch.org)
|
41
|
+
* [tensorflow](https://www.tensorflow.org)
|
42
|
+
* [keras](https://keras.io)
|
40
43
|
|
41
44
|
## Key Contacts
|
42
45
|
|
@@ -79,10 +79,11 @@ class HashAddress(SafeStrTuple, ABC):
|
|
79
79
|
address = cls.__new__(cls)
|
80
80
|
super(cls, address).__init__(prefix, hash_value)
|
81
81
|
if assert_readiness:
|
82
|
-
assert address.ready
|
82
|
+
assert address.ready
|
83
83
|
return address
|
84
84
|
|
85
85
|
|
86
|
+
@property
|
86
87
|
@abstractmethod
|
87
88
|
def ready(self) -> bool:
|
88
89
|
"""Check if address points to a value that is ready to be retrieved."""
|
{pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_01_foundational_objects/value_addresses.py
RENAMED
@@ -38,17 +38,18 @@ class ValueAddress(HashAddress):
|
|
38
38
|
|
39
39
|
super().__init__(prefix, hash_value)
|
40
40
|
|
41
|
-
if push_to_cloud and not (self in pth.
|
42
|
-
pth.
|
41
|
+
if push_to_cloud and not (self in pth.global_value_store):
|
42
|
+
pth.global_value_store[self] = data
|
43
43
|
|
44
|
+
@property
|
44
45
|
def ready(self):
|
45
46
|
"""Check if address points to a value that is ready to be retrieved."""
|
46
|
-
return self in pth.
|
47
|
+
return self in pth.global_value_store
|
47
48
|
|
48
49
|
|
49
50
|
def get(self, timeout:Optional[int] = None) -> Any:
|
50
51
|
"""Retrieve value, referenced by the address"""
|
51
|
-
return pth.
|
52
|
+
return pth.global_value_store[self]
|
52
53
|
|
53
54
|
def get_typed(self
|
54
55
|
,expected_type:Type[T]
|
{pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/autonomous_decorators.py
RENAMED
@@ -35,7 +35,7 @@ from pythagoras._03_autonomous_functions.default_island_singleton import (
|
|
35
35
|
DefaultIslandType, DefaultIsland)
|
36
36
|
from pythagoras._03_autonomous_functions.autonomous_funcs import (
|
37
37
|
AutonomousFunction)
|
38
|
-
from pythagoras.
|
38
|
+
from pythagoras._06_mission_control.global_state_management import (
|
39
39
|
is_fully_unitialized)
|
40
40
|
|
41
41
|
|
{pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_03_autonomous_functions/autonomous_funcs.py
RENAMED
@@ -17,12 +17,16 @@ from pythagoras._03_autonomous_functions.call_graph_explorer import (
|
|
17
17
|
|
18
18
|
from pythagoras._03_autonomous_functions.names_usage_analyzer import (
|
19
19
|
analyze_names_in_function)
|
20
|
-
from pythagoras._05_mission_control.events_and_exceptions_core import \
|
21
|
-
EventLogger
|
22
20
|
|
23
|
-
from pythagoras.
|
21
|
+
from pythagoras._05_events_and_exceptions.find_in_callstack import (
|
22
|
+
find_local_var_in_callstack)
|
23
|
+
|
24
|
+
from pythagoras._05_events_and_exceptions.event_logger import (
|
25
|
+
log_exception)
|
26
|
+
|
27
|
+
from pythagoras._06_mission_control.global_state_management import (
|
24
28
|
is_correctly_initialized)
|
25
|
-
|
29
|
+
|
26
30
|
|
27
31
|
|
28
32
|
class AutonomousFunction(OrdinaryFunction):
|
@@ -139,7 +143,7 @@ class AutonomousFunction(OrdinaryFunction):
|
|
139
143
|
return True
|
140
144
|
|
141
145
|
|
142
|
-
def
|
146
|
+
def execute(self, **kwargs) -> Any:
|
143
147
|
try:
|
144
148
|
assert self.runtime_checks()
|
145
149
|
names_dict = dict()
|
@@ -163,6 +167,9 @@ class AutonomousFunction(OrdinaryFunction):
|
|
163
167
|
log_exception()
|
164
168
|
raise e
|
165
169
|
|
170
|
+
def __call__(self, **kwargs) -> Any:
|
171
|
+
return self.execute(**kwargs)
|
172
|
+
|
166
173
|
def __getstate__(self):
|
167
174
|
draft_state = dict(name = self.name
|
168
175
|
, naked_source_code = self.naked_source_code
|
@@ -226,21 +233,6 @@ def register_autonomous_function(f: AutonomousFunction) -> None:
|
|
226
233
|
assert not hasattr(f, "_runtime_checks_passed")
|
227
234
|
assert not hasattr(f, "_dependencies")
|
228
235
|
|
229
|
-
def log_exception():
|
230
|
-
callers = find_in_callstack(name_to_find="self"
|
231
|
-
, class_to_find=AutonomousFunction)
|
232
|
-
caller_name = ""
|
233
|
-
if len(callers) > 0:
|
234
|
-
caller_name = callers[0].name + "_"
|
235
|
-
(exc_type, exc_value, trace_back) = sys.exc_info()
|
236
|
-
exception_description = traceback.format_exception(
|
237
|
-
exc_type, exc_value, trace_back)
|
238
|
-
logger = EventLogger(event_log = pth.crash_history
|
239
|
-
, prefix = caller_name + exc_type.__name__
|
240
|
-
, save_context = True)
|
241
|
-
logger.log_event(exception=exc_value
|
242
|
-
, exception_description=exception_description)
|
243
|
-
|
244
236
|
|
245
237
|
class EventPosterFactory:
|
246
238
|
def __init__(self, silent:bool = False):
|
@@ -260,8 +252,8 @@ class EventPoster:
|
|
260
252
|
self.silent = silent
|
261
253
|
|
262
254
|
def __call__(self, **event_args)-> None:
|
263
|
-
callers =
|
264
|
-
|
255
|
+
callers = find_local_var_in_callstack(name_to_find="self"
|
256
|
+
, class_to_find=AutonomousFunction)
|
265
257
|
caller_name = ""
|
266
258
|
if len(callers) > 0:
|
267
259
|
caller_name = callers[0].name
|
@@ -272,11 +264,10 @@ class EventPoster:
|
|
272
264
|
caller_prefix = caller_name
|
273
265
|
caller_type = "AutonomousFunction"
|
274
266
|
prefix = caller_prefix + self.label
|
275
|
-
logger = EventLogger(event_log=pth.
|
267
|
+
logger = EventLogger(event_log=pth.global_event_log
|
276
268
|
, prefix=prefix, save_context=False)
|
277
|
-
logger.log_event(**event_args)
|
278
|
-
if not self.silent:
|
279
269
|
|
270
|
+
if not self.silent:
|
280
271
|
print(30*"~")
|
281
272
|
print(f"Event '{self.label}' "
|
282
273
|
+ f"inside an {caller_type} '{caller_name}':")
|
@@ -284,5 +275,17 @@ class EventPoster:
|
|
284
275
|
print(f" {key} = {value}")
|
285
276
|
print()
|
286
277
|
|
278
|
+
label_arg_name = "event_label"
|
279
|
+
while label_arg_name in event_args:
|
280
|
+
label_arg_name += "_"
|
281
|
+
event_args[label_arg_name] = self.label
|
282
|
+
|
283
|
+
caller_arg_name = "caller_name"
|
284
|
+
while caller_arg_name in event_args:
|
285
|
+
caller_arg_name += "_"
|
286
|
+
event_args[caller_arg_name] = caller_name
|
287
|
+
|
288
|
+
logger.log_event(**event_args)
|
289
|
+
|
287
290
|
post_event: EventPosterFactory = EventPosterFactory(silent=True)
|
288
291
|
print_event: EventPosterFactory = EventPosterFactory(silent=False)
|
@@ -2,7 +2,7 @@ from pythagoras._04_idempotent_functions.kw_args import (
|
|
2
2
|
SortedKwArgs, PackedKwArgs, UnpackedKwArgs)
|
3
3
|
|
4
4
|
from pythagoras._04_idempotent_functions.idempotent_func_and_address import (
|
5
|
-
IdempotentFunction)
|
5
|
+
IdempotentFunction, FuncOutputAddress)
|
6
6
|
|
7
7
|
from pythagoras._04_idempotent_functions.idempotent_decorator import (
|
8
8
|
idempotent)
|
{pythagoras-0.8.5 → pythagoras-0.8.9}/pythagoras/_04_idempotent_functions/idempotent_decorator.py
RENAMED
@@ -8,7 +8,7 @@ from pythagoras._03_autonomous_functions.default_island_singleton import (
|
|
8
8
|
from pythagoras._04_idempotent_functions.idempotent_func_and_address import (
|
9
9
|
IdempotentFunction)
|
10
10
|
|
11
|
-
from pythagoras.
|
11
|
+
from pythagoras._06_mission_control.global_state_management import (
|
12
12
|
is_fully_unitialized)
|
13
13
|
|
14
14
|
|
@@ -4,12 +4,13 @@ import time
|
|
4
4
|
from typing import Callable, Any
|
5
5
|
|
6
6
|
import pythagoras as pth
|
7
|
+
from pythagoras import get_random_safe_str
|
7
8
|
|
8
9
|
from pythagoras._01_foundational_objects.hash_addresses import HashAddress
|
9
10
|
from pythagoras._01_foundational_objects.value_addresses import ValueAddress
|
10
11
|
|
11
12
|
from pythagoras._03_autonomous_functions.autonomous_funcs import (
|
12
|
-
AutonomousFunction, register_autonomous_function
|
13
|
+
AutonomousFunction, register_autonomous_function)
|
13
14
|
|
14
15
|
from pythagoras._02_ordinary_functions.ordinary_funcs import (
|
15
16
|
OrdinaryFunction)
|
@@ -21,6 +22,8 @@ from pythagoras._04_idempotent_functions.kw_args import (
|
|
21
22
|
UnpackedKwArgs, PackedKwArgs, SortedKwArgs)
|
22
23
|
from pythagoras._04_idempotent_functions.process_augmented_func_src import (
|
23
24
|
process_augmented_func_src)
|
25
|
+
from pythagoras._05_events_and_exceptions.context_utils import build_context
|
26
|
+
|
24
27
|
|
25
28
|
class IdempotentFunction(AutonomousFunction):
|
26
29
|
augmented_code_checked: bool
|
@@ -105,16 +108,45 @@ class IdempotentFunction(AutonomousFunction):
|
|
105
108
|
|
106
109
|
self.augmented_code_checked = True
|
107
110
|
|
108
|
-
|
111
|
+
|
112
|
+
def execute(self, **kwargs) -> Any:
|
109
113
|
packed_kwargs = PackedKwArgs(**kwargs)
|
110
114
|
output_address = FuncOutputAddress(self, packed_kwargs)
|
111
|
-
|
115
|
+
_pth_f_addr_ = output_address
|
116
|
+
if output_address.ready:
|
112
117
|
return output_address.get()
|
118
|
+
output_address.request_execution()
|
119
|
+
registration_addr = (output_address[0]
|
120
|
+
, output_address[1], get_random_safe_str())
|
121
|
+
pth.function_execution_attempts[registration_addr] = build_context()
|
113
122
|
unpacked_kwargs = UnpackedKwArgs(**packed_kwargs)
|
114
|
-
result = super().
|
123
|
+
result = super().execute(**unpacked_kwargs)
|
115
124
|
pth.function_output_store[output_address] = ValueAddress(result)
|
125
|
+
pth.function_execution_requests.delete_if_exists(output_address)
|
116
126
|
return result
|
117
127
|
|
128
|
+
def list_execute(self, list_of_kwargs:list[dict]) -> Any:
|
129
|
+
assert isinstance(list_of_kwargs, (list, tuple))
|
130
|
+
for kwargs in list_of_kwargs:
|
131
|
+
assert isinstance(kwargs, dict)
|
132
|
+
addrs = []
|
133
|
+
for kwargs in list_of_kwargs:
|
134
|
+
new_addr = FuncOutputAddress(self, kwargs)
|
135
|
+
new_addr.request_execution()
|
136
|
+
addrs.append(new_addr)
|
137
|
+
addrs_indexed = list(zip(range(len(addrs)), addrs))
|
138
|
+
pth.entropy_infuser.shuffle(addrs_indexed)
|
139
|
+
results_dict = dict()
|
140
|
+
for n, an_addr in addrs_indexed:
|
141
|
+
results_dict[n] = an_addr.function.execute(**an_addr.arguments)
|
142
|
+
results_list = [results_dict[n] for n in range(len(addrs))]
|
143
|
+
return results_list
|
144
|
+
|
145
|
+
def execution_attempts(self, **kwargs) -> list:
|
146
|
+
packed_kwargs = PackedKwArgs(**kwargs)
|
147
|
+
output_address = FuncOutputAddress(self, packed_kwargs)
|
148
|
+
return output_address.execution_attempts
|
149
|
+
|
118
150
|
|
119
151
|
def register_idempotent_function(f: IdempotentFunction) -> None:
|
120
152
|
"""Register an idempotent function in the Pythagoras system."""
|
@@ -143,8 +175,18 @@ class FuncOutputAddress(HashAddress):
|
|
143
175
|
tmp = ValueAddress(signature)
|
144
176
|
super().__init__(tmp.prefix, tmp.hash_value)
|
145
177
|
|
178
|
+
@property
|
146
179
|
def ready(self):
|
147
|
-
|
180
|
+
result = self in pth.function_output_store
|
181
|
+
return result
|
182
|
+
|
183
|
+
def request_execution(self):
|
184
|
+
if self in pth.function_output_store:
|
185
|
+
if self in pth.function_execution_requests:
|
186
|
+
del pth.function_execution_requests[self]
|
187
|
+
else:
|
188
|
+
if self not in pth.function_execution_requests:
|
189
|
+
pth.function_execution_requests[self] = True
|
148
190
|
|
149
191
|
def get(self, timeout: int = None):
|
150
192
|
"""Retrieve value, referenced by the address.
|
@@ -152,14 +194,20 @@ class FuncOutputAddress(HashAddress):
|
|
152
194
|
If the value is not immediately available, backoff exponentially
|
153
195
|
till timeout is exceeded. If timeout is None, keep trying forever.
|
154
196
|
"""
|
197
|
+
if self.ready:
|
198
|
+
return pth.global_value_store[pth.function_output_store[self]]
|
199
|
+
self.request_execution()
|
200
|
+
|
155
201
|
start_time, backoff_period = time.time(), 1.0
|
156
202
|
stop_time = (start_time + timeout) if timeout else None
|
157
203
|
# start_time, stop_time and backoff_period are in seconds
|
204
|
+
|
158
205
|
while True:
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
206
|
+
if self.ready:
|
207
|
+
result = pth.global_value_store[pth.function_output_store[self]]
|
208
|
+
pth.function_execution_requests.delete_if_exists(self)
|
209
|
+
return result
|
210
|
+
else:
|
163
211
|
time.sleep(backoff_period)
|
164
212
|
backoff_period *= 2.0
|
165
213
|
backoff_period += pth.entropy_infuser.uniform(-0.5, 0.5)
|
@@ -185,9 +233,62 @@ class FuncOutputAddress(HashAddress):
|
|
185
233
|
signature = signature_addr.get()
|
186
234
|
return signature.f_name
|
187
235
|
|
236
|
+
@property
|
237
|
+
def island_name(self) -> str:
|
238
|
+
return self.function.island_name
|
239
|
+
|
188
240
|
@property
|
189
241
|
def arguments(self) -> SortedKwArgs:
|
190
242
|
signature_addr = ValueAddress.from_strings(
|
191
243
|
prefix=self.prefix, hash_value=self.hash_value)
|
192
244
|
signature = signature_addr.get()
|
193
|
-
return signature.args_addr.get()
|
245
|
+
return signature.args_addr.get()
|
246
|
+
|
247
|
+
@property
|
248
|
+
def can_be_executed(self) -> bool:
|
249
|
+
"""Indicates if the function can be executed in the current session.
|
250
|
+
|
251
|
+
Currently, it's just a placeholder that always returns True.
|
252
|
+
|
253
|
+
The function should fe refactored once we start supporting
|
254
|
+
VALIDATORS, CORRECTORS and SEQUENCERS
|
255
|
+
"""
|
256
|
+
return True
|
257
|
+
|
258
|
+
@property
|
259
|
+
def needs_execution(self) -> bool:
|
260
|
+
"""Indicates if the function is a good candidate for execution.
|
261
|
+
|
262
|
+
Returns False if the result is already available, or if some other
|
263
|
+
process is currently working on it. Otherwise, returns True.
|
264
|
+
"""
|
265
|
+
DEFAULT_EXECUTION_TIME = 10
|
266
|
+
MAX_EXECUTION_ATTEMPTS = 5
|
267
|
+
# TODO: these should not be constants
|
268
|
+
if self.ready:
|
269
|
+
return False
|
270
|
+
past_attempts = pth.function_execution_attempts.get_subdict(self)
|
271
|
+
n_past_attempts = len(past_attempts)
|
272
|
+
if n_past_attempts == 0:
|
273
|
+
return True
|
274
|
+
if n_past_attempts > MAX_EXECUTION_ATTEMPTS:
|
275
|
+
#TODO: log this event. Should we have DLQ?
|
276
|
+
return False
|
277
|
+
most_recent_timestamp = max(
|
278
|
+
past_attempts.mtimestamp(a) for a in past_attempts)
|
279
|
+
current_timestamp = time.time()
|
280
|
+
if (current_timestamp - most_recent_timestamp
|
281
|
+
> DEFAULT_EXECUTION_TIME*(2**n_past_attempts)):
|
282
|
+
return True
|
283
|
+
return False
|
284
|
+
|
285
|
+
@property
|
286
|
+
def execution_attempts(self) -> list:
|
287
|
+
attempts = pth.function_execution_attempts.get_subdict(self)
|
288
|
+
attemps_timed = {-attempts.mtimestamp(a):attempts[a] for a in attempts}
|
289
|
+
times = sorted(attemps_timed)
|
290
|
+
result = []
|
291
|
+
for t in times:
|
292
|
+
result.append(attemps_timed[t])
|
293
|
+
return result
|
294
|
+
|
@@ -25,7 +25,7 @@ class SortedKwArgs(dict):
|
|
25
25
|
unpacked_copy = dict()
|
26
26
|
for k,v in self.items():
|
27
27
|
if isinstance(v, ValueAddress):
|
28
|
-
unpacked_copy[k] = pth.
|
28
|
+
unpacked_copy[k] = pth.global_value_store[v]
|
29
29
|
else:
|
30
30
|
unpacked_copy[k] = v
|
31
31
|
return unpacked_copy
|
@@ -5,7 +5,8 @@ import socket
|
|
5
5
|
from typing import Dict
|
6
6
|
from getpass import getuser
|
7
7
|
from datetime import datetime
|
8
|
-
|
8
|
+
import torch
|
9
|
+
from pythagoras._05_events_and_exceptions.notebook_checker import is_executed_in_notebook
|
9
10
|
|
10
11
|
def build_context()-> Dict:
|
11
12
|
"""Capture core information about execution environment.
|
@@ -14,7 +15,6 @@ def build_context()-> Dict:
|
|
14
15
|
to help debug (distributed) applications.
|
15
16
|
"""
|
16
17
|
cwd = os.getcwd()
|
17
|
-
is_in_notebook = is_executed_in_notebook()
|
18
18
|
|
19
19
|
context = dict(
|
20
20
|
hostname = socket.gethostname()
|
@@ -26,12 +26,20 @@ def build_context()-> Dict:
|
|
26
26
|
,processor = platform.processor()
|
27
27
|
,cpu_count = psutil.cpu_count()
|
28
28
|
,cpu_load_avg = psutil.getloadavg()
|
29
|
+
,cuda_gpu_count=torch.cuda.device_count()
|
29
30
|
,disk_usage = psutil.disk_usage(cwd)
|
30
31
|
,virtual_memory = psutil.virtual_memory()
|
31
|
-
,cwd = os.getcwd()
|
32
32
|
,working_directory = cwd
|
33
33
|
,local_timezone = datetime.now().astimezone().tzname()
|
34
|
-
,is_in_notebook =
|
34
|
+
,is_in_notebook = is_executed_in_notebook()
|
35
35
|
)
|
36
36
|
|
37
|
-
return context
|
37
|
+
return context
|
38
|
+
|
39
|
+
|
40
|
+
def add_context(**kwargs):
|
41
|
+
context_param_name = "context"
|
42
|
+
while context_param_name in kwargs:
|
43
|
+
context_param_name += "_"
|
44
|
+
kwargs[context_param_name] = build_context()
|
45
|
+
return kwargs
|
@@ -0,0 +1,88 @@
|
|
1
|
+
import sys
|
2
|
+
import traceback
|
3
|
+
from copy import copy
|
4
|
+
|
5
|
+
from pythagoras._05_events_and_exceptions.context_utils import add_context
|
6
|
+
from pythagoras._05_events_and_exceptions.current_date_gmt_str import (
|
7
|
+
current_date_gmt_string)
|
8
|
+
from pythagoras._05_events_and_exceptions.find_in_callstack import (
|
9
|
+
find_local_var_in_callstack)
|
10
|
+
from pythagoras._05_events_and_exceptions.type_retrievers import (
|
11
|
+
retrieve_AutonomousFunction_class, retrieve_FuncOutputAddress_class)
|
12
|
+
from pythagoras._99_misc_utils.random_safe_str_creator import (
|
13
|
+
get_random_safe_str)
|
14
|
+
|
15
|
+
from persidict import PersiDict
|
16
|
+
import pythagoras as pth
|
17
|
+
|
18
|
+
|
19
|
+
def log_one_entry(event_log_dict:PersiDict
|
20
|
+
, path:list[str] | None
|
21
|
+
, prefixes: list[str] | None
|
22
|
+
, name:str
|
23
|
+
, event:any):
|
24
|
+
if prefixes is not None and len(prefixes) > 0:
|
25
|
+
name = "_".join(prefixes + [name])
|
26
|
+
if path is None or len(path) == 0:
|
27
|
+
address = [name]
|
28
|
+
else:
|
29
|
+
address = path + [name]
|
30
|
+
event_log_dict[address] = event
|
31
|
+
|
32
|
+
def log_two_mirrored_entries(
|
33
|
+
global_event_log_dict:PersiDict | None
|
34
|
+
, local_event_log_dict:PersiDict | None
|
35
|
+
, prefix: str | None
|
36
|
+
, event: any):
|
37
|
+
func_addrs = find_local_var_in_callstack(name_to_find="_pth_f_addr_"
|
38
|
+
, class_to_find = retrieve_FuncOutputAddress_class())
|
39
|
+
if len(func_addrs) > 0:
|
40
|
+
func_pointer = func_addrs[0]
|
41
|
+
local_path = list(func_pointer)
|
42
|
+
else:
|
43
|
+
funcs = find_local_var_in_callstack(name_to_find="self"
|
44
|
+
, class_to_find=retrieve_AutonomousFunction_class())
|
45
|
+
if len(funcs) > 0:
|
46
|
+
func_pointer = funcs[0]
|
47
|
+
local_path = None
|
48
|
+
else:
|
49
|
+
assert False, "No function pointer found in callstack"
|
50
|
+
|
51
|
+
island_name = func_pointer.island_name
|
52
|
+
function_name = func_pointer.f_name
|
53
|
+
event_name = get_random_safe_str()
|
54
|
+
|
55
|
+
if prefix is not None:
|
56
|
+
prefixes = [prefix]
|
57
|
+
else:
|
58
|
+
prefixes = []
|
59
|
+
|
60
|
+
if global_event_log_dict is not None:
|
61
|
+
if island_name is not None:
|
62
|
+
global_prefixes = [island_name] + prefixes
|
63
|
+
else:
|
64
|
+
global_prefixes = copy(prefixes)
|
65
|
+
global_prefixes = [function_name] + global_prefixes
|
66
|
+
global_path = [current_date_gmt_string()]
|
67
|
+
log_one_entry(global_event_log_dict
|
68
|
+
, global_path, global_prefixes, event_name, event)
|
69
|
+
|
70
|
+
if local_event_log_dict is not None and local_path is not None:
|
71
|
+
local_prefixes = copy(prefixes)
|
72
|
+
log_one_entry(local_event_log_dict
|
73
|
+
, local_path, local_prefixes, event_name, event)
|
74
|
+
|
75
|
+
|
76
|
+
def log_exception():
|
77
|
+
(exc_type, exc_value, trace_back) = sys.exc_info()
|
78
|
+
description = traceback.format_exception(
|
79
|
+
exc_type, exc_value, trace_back)
|
80
|
+
event = add_context(
|
81
|
+
exception_description=description
|
82
|
+
,exception=exc_value
|
83
|
+
,trace_back= trace_back)
|
84
|
+
log_two_mirrored_entries(
|
85
|
+
global_event_log_dict=pth.global_crash_history
|
86
|
+
, local_event_log_dict=pth.function_crash_history
|
87
|
+
, prefix=exc_type.__name__
|
88
|
+
, event=event)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import inspect
|
2
2
|
from typing import List, Any
|
3
3
|
|
4
|
-
def
|
4
|
+
def find_local_var_in_callstack(
|
5
5
|
name_to_find: str
|
6
|
-
, class_to_find: None | type = None
|
6
|
+
, class_to_find: None | type | str = None
|
7
7
|
) -> List[Any]:
|
8
|
-
""" Search the entire call stack for objects with the specified name/type.
|
8
|
+
""" Search the entire call stack for local objects with the specified name/type.
|
9
9
|
|
10
10
|
If the callstack contains objects
|
11
11
|
with name name_to_find and type class_to_find,
|
@@ -19,16 +19,18 @@ def find_in_callstack(
|
|
19
19
|
|
20
20
|
Parameters:
|
21
21
|
name_to_find (str): The name of the object to search for.
|
22
|
-
class_to_find (None | type): The type of the object to search for.
|
22
|
+
class_to_find (None | type | str): The type of the object to search for.
|
23
23
|
|
24
24
|
Returns:
|
25
|
-
List[Any]: A list of objects found in the stack
|
25
|
+
List[Any]: A list of local objects found in the stack
|
26
26
|
with the specified name/type.
|
27
27
|
The list contains no duplicates.
|
28
28
|
"""
|
29
29
|
|
30
30
|
assert isinstance(name_to_find, str) and len(name_to_find)
|
31
|
-
assert class_to_find is None
|
31
|
+
assert (class_to_find is None
|
32
|
+
or inspect.isclass(class_to_find)
|
33
|
+
or isinstance(class_to_find, str))
|
32
34
|
|
33
35
|
found_objects = []
|
34
36
|
|
@@ -36,11 +38,12 @@ def find_in_callstack(
|
|
36
38
|
frame = frame_info.frame
|
37
39
|
if name_to_find in frame.f_locals:
|
38
40
|
candidate = frame.f_locals[name_to_find]
|
39
|
-
if class_to_find is None
|
41
|
+
if class_to_find is None:
|
40
42
|
found_objects.append(candidate)
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
elif isinstance(class_to_find, str):
|
44
|
+
if candidate.__class__.__name__ == class_to_find:
|
45
|
+
found_objects.append(candidate)
|
46
|
+
elif isinstance(candidate, class_to_find):
|
44
47
|
found_objects.append(candidate)
|
45
48
|
|
46
49
|
dedup_dict = dict()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
def retrieve_IdempotentFunction_class() -> type:
|
4
|
+
"""Return the IdempotentFunction class.
|
5
|
+
|
6
|
+
This is for-internal-use-only function, created to
|
7
|
+
avoid circular import dependencies.
|
8
|
+
"""
|
9
|
+
return sys.modules['pythagoras'].IdempotentFunction
|
10
|
+
|
11
|
+
|
12
|
+
def retrieve_AutonomousFunction_class() -> type:
|
13
|
+
"""Return the AutonomousFunction class.
|
14
|
+
|
15
|
+
This is for-internal-use-only function, created to
|
16
|
+
avoid circular import dependencies.
|
17
|
+
"""
|
18
|
+
return sys.modules['pythagoras'].AutonomousFunction
|
19
|
+
|
20
|
+
|
21
|
+
def retrieve_FuncOutputAddress_class() -> type:
|
22
|
+
"""Return the FuncOutputAddress class.
|
23
|
+
|
24
|
+
This is for-internal-use-only function, created to
|
25
|
+
avoid circular import dependencies.
|
26
|
+
"""
|
27
|
+
return sys.modules['pythagoras'].FuncOutputAddress
|
28
|
+
|
29
|
+
|
30
|
+
|