pythagoras 0.8.14__tar.gz → 0.9.1__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.
Files changed (75) hide show
  1. {pythagoras-0.8.14/pythagoras.egg-info → pythagoras-0.9.1}/PKG-INFO +1 -1
  2. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_01_foundational_objects/value_addresses.py +4 -4
  3. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/__init__.py +1 -1
  4. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/autonomous_decorators.py +1 -1
  5. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/autonomous_funcs.py +16 -65
  6. pythagoras-0.9.1/pythagoras/_03_autonomous_functions/pth_available_names_retriever.py +13 -0
  7. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/__init__.py +3 -1
  8. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/idempotent_decorator.py +1 -1
  9. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/idempotent_func_and_address.py +127 -36
  10. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/kw_args.py +1 -1
  11. pythagoras-0.9.1/pythagoras/_05_events_and_exceptions/__init__.py +5 -0
  12. pythagoras-0.9.1/pythagoras/_05_events_and_exceptions/event_poster.py +53 -0
  13. pythagoras-0.9.1/pythagoras/_05_events_and_exceptions/global_event_loggers.py +27 -0
  14. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/type_retrievers.py +12 -3
  15. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/uncaught_exception_handlers.py +5 -5
  16. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_06_mission_control/__init__.py +3 -0
  17. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_06_mission_control/global_state_management.py +43 -69
  18. pythagoras-0.9.1/pythagoras/_06_mission_control/operational_hub.py +17 -0
  19. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_06_mission_control/summary.py +2 -2
  20. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/NEW_hash_address.py +1 -1
  21. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/__init__.py +6 -15
  22. {pythagoras-0.8.14 → pythagoras-0.9.1/pythagoras.egg-info}/PKG-INFO +1 -1
  23. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras.egg-info/SOURCES.txt +4 -4
  24. {pythagoras-0.8.14 → pythagoras-0.9.1}/setup.py +1 -1
  25. pythagoras-0.8.14/pythagoras/NEW_exception_logging.py +0 -66
  26. pythagoras-0.8.14/pythagoras/_05_events_and_exceptions/__init__.py +0 -2
  27. pythagoras-0.8.14/pythagoras/_05_events_and_exceptions/event_logger.py +0 -94
  28. pythagoras-0.8.14/pythagoras/_06_mission_control/__events_and_exceptions_OLD__.py +0 -165
  29. pythagoras-0.8.14/pythagoras/__main__.py +0 -12
  30. {pythagoras-0.8.14 → pythagoras-0.9.1}/LICENSE +0 -0
  31. {pythagoras-0.8.14 → pythagoras-0.9.1}/README.md +0 -0
  32. {pythagoras-0.8.14 → pythagoras-0.9.1}/pyproject.toml +0 -0
  33. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/OLD__main__.py +0 -0
  34. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/OLD_p_cloud.py +0 -0
  35. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/OLD_utils.py +0 -0
  36. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_01_foundational_objects/__init__.py +0 -0
  37. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_01_foundational_objects/hash_addresses.py +0 -0
  38. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_01_foundational_objects/hash_and_random_signatures.py +0 -0
  39. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/__init__.py +0 -0
  40. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/assert_ordinarity.py +0 -0
  41. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/check_n_positional_args.py +0 -0
  42. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/code_normalizer.py +0 -0
  43. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/code_normalizer_implementation.py +0 -0
  44. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/ordinary_decorator.py +0 -0
  45. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_02_ordinary_functions/ordinary_funcs.py +0 -0
  46. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/autonomicity_checks.py +0 -0
  47. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/call_graph_explorer.py +0 -0
  48. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/default_island_singleton.py +0 -0
  49. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_03_autonomous_functions/names_usage_analyzer.py +0 -0
  50. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/astkeywords_dict_convertors.py +0 -0
  51. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/idempotency_checks.py +0 -0
  52. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_04_idempotent_functions/process_augmented_func_src.py +0 -0
  53. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/context_utils.py +0 -0
  54. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/current_date_gmt_str.py +0 -0
  55. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/find_in_callstack.py +0 -0
  56. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_05_events_and_exceptions/notebook_checker.py +0 -0
  57. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/__init__.py +0 -0
  58. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/base_16_32_convertors.py +0 -0
  59. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/function_name.py +0 -0
  60. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/id_examiner.py +0 -0
  61. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/long_infoname.py +0 -0
  62. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/output_capturer.py +0 -0
  63. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/_99_misc_utils/package_manager.py +0 -0
  64. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_dependency_discovery.py +0 -0
  65. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_environmental.py +0 -0
  66. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_package_dependencies.py +0 -0
  67. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_persidicts.py +0 -0
  68. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_persiout.py +0 -0
  69. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/OLD_persistent_dicts.py +0 -0
  70. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/__init__.py +0 -0
  71. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras/________OLD________/test_package_dependencies.py +0 -0
  72. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras.egg-info/dependency_links.txt +0 -0
  73. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras.egg-info/requires.txt +0 -0
  74. {pythagoras-0.8.14 → pythagoras-0.9.1}/pythagoras.egg-info/top_level.txt +0 -0
  75. {pythagoras-0.8.14 → pythagoras-0.9.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pythagoras
3
- Version: 0.8.14
3
+ Version: 0.9.1
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
@@ -38,8 +38,8 @@ class ValueAddress(HashAddress):
38
38
 
39
39
  super().__init__(prefix, hash_value)
40
40
 
41
- if push_to_cloud and not (self in pth.global_value_store):
42
- pth.global_value_store[self] = data
41
+ if push_to_cloud and not (self in pth.value_store):
42
+ pth.value_store[self] = data
43
43
 
44
44
  def get_ValueAddress(self):
45
45
  return self
@@ -47,12 +47,12 @@ class ValueAddress(HashAddress):
47
47
  @property
48
48
  def ready(self):
49
49
  """Check if address points to a value that is ready to be retrieved."""
50
- return self in pth.global_value_store
50
+ return self in pth.value_store
51
51
 
52
52
 
53
53
  def get(self, timeout:Optional[int] = None) -> Any:
54
54
  """Retrieve value, referenced by the address"""
55
- return pth.global_value_store[self]
55
+ return pth.value_store[self]
56
56
 
57
57
  def get_typed(self
58
58
  ,expected_type:Type[T]
@@ -44,7 +44,7 @@ from pythagoras._03_autonomous_functions.default_island_singleton import (
44
44
  DefaultIsland, DefaultIslandType)
45
45
 
46
46
  from pythagoras._03_autonomous_functions.autonomous_funcs import (
47
- AutonomousFunction, post_event, print_event)
47
+ AutonomousFunction)
48
48
 
49
49
  from pythagoras._03_autonomous_functions.autonomicity_checks import (
50
50
  is_autonomous, is_loosely_autonomous, is_strictly_autonomous)
@@ -66,7 +66,7 @@ class autonomous:
66
66
  self.island_name = island_name
67
67
  self.require_pth = require_pth
68
68
 
69
- def __call__(self, a_func: Callable) -> Callable:
69
+ def __call__(self, a_func: Callable) -> AutonomousFunction:
70
70
  """Decorator for autonomous functions.
71
71
 
72
72
  It does both static and dynamic checks for autonomous functions.
@@ -4,7 +4,7 @@ import sys
4
4
  import traceback
5
5
  from typing import Callable, Optional, Any
6
6
  from persidict import replace_unsafe_chars
7
- import pythagoras as pth
7
+
8
8
 
9
9
  from pythagoras._02_ordinary_functions.ordinary_funcs import (
10
10
  OrdinaryFunction)
@@ -18,15 +18,16 @@ from pythagoras._03_autonomous_functions.call_graph_explorer import (
18
18
  from pythagoras._03_autonomous_functions.names_usage_analyzer import (
19
19
  analyze_names_in_function)
20
20
 
21
- from pythagoras._05_events_and_exceptions.find_in_callstack import (
22
- find_local_var_in_callstack)
21
+ from pythagoras._03_autonomous_functions.pth_available_names_retriever import (
22
+ retrieve_objs_available_inside_autonomous_functions)
23
23
 
24
- from pythagoras._05_events_and_exceptions.event_logger import (
25
- log_exception)
24
+ from pythagoras._05_events_and_exceptions.global_event_loggers import (
25
+ register_exception_globally)
26
26
 
27
27
  from pythagoras._06_mission_control.global_state_management import (
28
28
  is_correctly_initialized)
29
29
 
30
+ import pythagoras as pth
30
31
 
31
32
 
32
33
  class AutonomousFunction(OrdinaryFunction):
@@ -123,6 +124,8 @@ class AutonomousFunction(OrdinaryFunction):
123
124
  import_required -= set(pth.primary_decorators)
124
125
  builtin_names = set(dir(builtins))
125
126
  import_required -= builtin_names
127
+ pth_names = set(retrieve_objs_available_inside_autonomous_functions())
128
+ import_required -= pth_names
126
129
  import_required -= {name}
127
130
  if self.island_name is not None:
128
131
  island = pth.all_autonomous_functions[self.island_name]
@@ -146,7 +149,7 @@ class AutonomousFunction(OrdinaryFunction):
146
149
  def execute(self, **kwargs) -> Any:
147
150
  try:
148
151
  assert self.runtime_checks()
149
- names_dict = dict()
152
+ names_dict = retrieve_objs_available_inside_autonomous_functions()
150
153
  island = pth.all_autonomous_functions[self.island_name]
151
154
  names_dict["_pth_kwargs"] = kwargs
152
155
  if self.island_name is not None:
@@ -155,6 +158,7 @@ class AutonomousFunction(OrdinaryFunction):
155
158
  else:
156
159
  names_dict[self.name] = island[self.name]
157
160
 
161
+
158
162
  tmp_name = "_pth_tmp_" + self.name
159
163
  source_to_exec = self.naked_source_code + "\n"
160
164
  source_to_exec = source_to_exec.replace(
@@ -164,7 +168,11 @@ class AutonomousFunction(OrdinaryFunction):
164
168
  result = names_dict["_pth_result"]
165
169
  return result
166
170
  except Exception as e:
167
- log_exception()
171
+ if self.__class__ == AutonomousFunction:
172
+ exception_id = f"{self.name}_{self.island_name}"
173
+ exception_id += f"_{e.__class__.__name__}"
174
+ exception_id += f"_{pth.get_random_signature()}"
175
+ register_exception_globally(exception_id=exception_id)
168
176
  raise e
169
177
 
170
178
  def __call__(self, **kwargs) -> Any:
@@ -231,61 +239,4 @@ def register_autonomous_function(f: AutonomousFunction) -> None:
231
239
  if f is not pth.all_autonomous_functions[f.island_name][f.name]:
232
240
  assert not hasattr(f, "_static_checks_passed")
233
241
  assert not hasattr(f, "_runtime_checks_passed")
234
- assert not hasattr(f, "_dependencies")
235
-
236
-
237
- class EventPosterFactory:
238
- def __init__(self, silent:bool = False):
239
- assert isinstance(silent, bool)
240
- self.silent = silent
241
-
242
- def __getitem__(self, item:str)-> EventPoster:
243
- assert isinstance(item, str)
244
- return EventPoster(item, silent=self.silent)
245
-
246
- class EventPoster:
247
- def __init__(self, label:str, silent:bool = False):
248
- assert isinstance(label, str)
249
- assert label == replace_unsafe_chars(label, "")
250
- assert 0 < len(label) < 25
251
- self.label = label
252
- self.silent = silent
253
-
254
- def __call__(self, **event_args)-> None:
255
- callers = find_local_var_in_callstack(name_to_find="self"
256
- , class_to_find=AutonomousFunction)
257
- caller_name = ""
258
- if len(callers) > 0:
259
- caller_name = callers[0].name
260
- caller_prefix = caller_name + "_"
261
- caller_type = callers[0].__class__.__name__
262
- else:
263
- caller_name = "__none__"
264
- caller_prefix = caller_name
265
- caller_type = "AutonomousFunction"
266
- prefix = caller_prefix + self.label
267
- logger = EventLogger(event_log=pth.global_event_log
268
- , prefix=prefix, save_context=False)
269
-
270
- if not self.silent:
271
- print(30*"~")
272
- print(f"Event '{self.label}' "
273
- + f"inside an {caller_type} '{caller_name}':")
274
- for key, value in event_args.items():
275
- print(f" {key} = {value}")
276
- print()
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
-
290
- post_event: EventPosterFactory = EventPosterFactory(silent=True)
291
- print_event: EventPosterFactory = EventPosterFactory(silent=False)
242
+ assert not hasattr(f, "_dependencies")
@@ -0,0 +1,13 @@
1
+ import sys
2
+ from typing import Any
3
+
4
+
5
+ def retrieve_objs_available_inside_autonomous_functions() -> dict[str,Any]:
6
+ """Names available inside autonomous functions without explicit import.
7
+
8
+ """
9
+ result = dict(
10
+ pth = sys.modules['pythagoras']
11
+ , post_event = sys.modules['pythagoras'].post_event
12
+ )
13
+ return result
@@ -2,7 +2,9 @@ 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, FuncOutputAddress)
5
+ IdempotentFunction
6
+ , FunctionExecutionResultAddress
7
+ , FunctionExecutionContext)
6
8
 
7
9
  from pythagoras._04_idempotent_functions.idempotent_decorator import (
8
10
  idempotent)
@@ -28,7 +28,7 @@ class idempotent:
28
28
  self.require_pth = require_pth
29
29
 
30
30
 
31
- def __call__(self, a_func:Callable) -> Callable:
31
+ def __call__(self, a_func:Callable) -> IdempotentFunction:
32
32
  if not self.require_pth and is_fully_unitialized():
33
33
  wrapper = a_func
34
34
  logging.warning(f"Decorator @{self.__class__.__name__}()"
@@ -1,10 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import time
4
+ import traceback
4
5
  from typing import Callable, Any
5
6
 
7
+ from persidict import PersiDict
8
+
6
9
  import pythagoras as pth
7
- from pythagoras import get_random_signature
10
+ from pythagoras import get_random_signature, OutputCapturer
8
11
 
9
12
  from pythagoras._01_foundational_objects.hash_addresses import HashAddress
10
13
  from pythagoras._01_foundational_objects.value_addresses import ValueAddress
@@ -22,7 +25,9 @@ from pythagoras._04_idempotent_functions.kw_args import (
22
25
  UnpackedKwArgs, PackedKwArgs, SortedKwArgs)
23
26
  from pythagoras._04_idempotent_functions.process_augmented_func_src import (
24
27
  process_augmented_func_src)
25
- from pythagoras._05_events_and_exceptions.context_utils import build_context
28
+ from pythagoras._05_events_and_exceptions.context_utils import build_context, add_context
29
+ from pythagoras._05_events_and_exceptions.global_event_loggers import (
30
+ register_exception_globally, register_event_globally)
26
31
 
27
32
 
28
33
  class IdempotentFunction(AutonomousFunction):
@@ -108,21 +113,26 @@ class IdempotentFunction(AutonomousFunction):
108
113
 
109
114
  self.augmented_code_checked = True
110
115
 
116
+ def get_address(self, **kwargs) -> FunctionExecutionResultAddress:
117
+ packed_kwargs = PackedKwArgs(**kwargs)
118
+ output_address = FunctionExecutionResultAddress(self, packed_kwargs)
119
+ return output_address
120
+
111
121
 
112
122
  def execute(self, **kwargs) -> Any:
113
123
  packed_kwargs = PackedKwArgs(**kwargs)
114
- output_address = FuncOutputAddress(self, packed_kwargs)
124
+ output_address = FunctionExecutionResultAddress(self, packed_kwargs)
115
125
  _pth_f_addr_ = output_address
116
126
  if output_address.ready:
117
127
  return output_address.get()
118
- output_address.request_execution()
119
- registration_addr = (output_address[1], get_random_signature())
120
- pth.function_execution_attempts[registration_addr] = build_context()
121
- unpacked_kwargs = UnpackedKwArgs(**packed_kwargs)
122
- result = super().execute(**unpacked_kwargs)
123
- pth.function_output_store[output_address] = ValueAddress(result)
124
- pth.function_execution_requests.delete_if_exists(output_address)
125
- return result
128
+ with FunctionExecutionContext(output_address) as _pth_ec:
129
+ output_address.request_execution()
130
+ _pth_ec.register_execution_attempt()
131
+ unpacked_kwargs = UnpackedKwArgs(**packed_kwargs)
132
+ result = super().execute(**unpacked_kwargs)
133
+ pth.execution_results[output_address] = ValueAddress(result)
134
+ output_address.drop_execution_request()
135
+ return result
126
136
 
127
137
  def list_execute(self, list_of_kwargs:list[dict]) -> Any:
128
138
  assert isinstance(list_of_kwargs, (list, tuple))
@@ -130,7 +140,7 @@ class IdempotentFunction(AutonomousFunction):
130
140
  assert isinstance(kwargs, dict)
131
141
  addrs = []
132
142
  for kwargs in list_of_kwargs:
133
- new_addr = FuncOutputAddress(self, kwargs)
143
+ new_addr = FunctionExecutionResultAddress(self, kwargs)
134
144
  new_addr.request_execution()
135
145
  addrs.append(new_addr)
136
146
  addrs_indexed = list(zip(range(len(addrs)), addrs))
@@ -141,11 +151,6 @@ class IdempotentFunction(AutonomousFunction):
141
151
  results_list = [results_dict[n] for n in range(len(addrs))]
142
152
  return results_list
143
153
 
144
- def execution_attempts(self, **kwargs) -> list:
145
- packed_kwargs = PackedKwArgs(**kwargs)
146
- output_address = FuncOutputAddress(self, packed_kwargs)
147
- return output_address.execution_attempts
148
-
149
154
 
150
155
  def register_idempotent_function(f: IdempotentFunction) -> None:
151
156
  """Register an idempotent function in the Pythagoras system."""
@@ -166,7 +171,7 @@ class FunctionCallSignature:
166
171
  self.f_addr = ValueAddress(f)
167
172
  self.args_addr = ValueAddress(arguments.pack())
168
173
 
169
- class FuncOutputAddress(HashAddress):
174
+ class FunctionExecutionResultAddress(HashAddress):
170
175
  value_prefix: str|None = None
171
176
  def __init__(self, f: IdempotentFunction, arguments:dict[str, Any]):
172
177
  assert isinstance(f, IdempotentFunction)
@@ -186,16 +191,25 @@ class FuncOutputAddress(HashAddress):
186
191
 
187
192
  @property
188
193
  def ready(self):
189
- result = self in pth.function_output_store
194
+ result = self in pth.execution_results
190
195
  return result
191
196
 
192
197
  def request_execution(self):
193
- if self in pth.function_output_store:
194
- if self in pth.function_execution_requests:
195
- del pth.function_execution_requests[self]
198
+ request_address = self + ["execution_requested"]
199
+ if self in pth.execution_results:
200
+ if request_address in pth.operational_hub.binary:
201
+ del pth.operational_hub.binary[request_address]
196
202
  else:
197
- if self not in pth.function_execution_requests:
198
- pth.function_execution_requests[self] = True
203
+ if request_address not in pth.operational_hub.binary:
204
+ pth.operational_hub.binary[request_address] = True
205
+
206
+ def drop_execution_request(self):
207
+ request_address = self + ["execution_requested"]
208
+ pth.operational_hub.binary.delete_if_exists(request_address)
209
+
210
+ def is_execution_requested(self):
211
+ request_address = self + ["execution_requested"]
212
+ return request_address in pth.operational_hub.binary
199
213
 
200
214
  def get(self, timeout: int = None):
201
215
  """Retrieve value, referenced by the address.
@@ -204,7 +218,7 @@ class FuncOutputAddress(HashAddress):
204
218
  till timeout is exceeded. If timeout is None, keep trying forever.
205
219
  """
206
220
  if self.ready:
207
- return pth.global_value_store[pth.function_output_store[self]]
221
+ return pth.value_store[pth.execution_results[self]]
208
222
  self.request_execution()
209
223
 
210
224
  start_time, backoff_period = time.time(), 1.0
@@ -213,8 +227,8 @@ class FuncOutputAddress(HashAddress):
213
227
 
214
228
  while True:
215
229
  if self.ready:
216
- result = pth.global_value_store[pth.function_output_store[self]]
217
- pth.function_execution_requests.delete_if_exists(self)
230
+ result = pth.value_store[pth.execution_results[self]]
231
+ self.drop_execution_request()
218
232
  return result
219
233
  else:
220
234
  time.sleep(backoff_period)
@@ -273,7 +287,7 @@ class FuncOutputAddress(HashAddress):
273
287
  # TODO: these should not be constants
274
288
  if self.ready:
275
289
  return False
276
- past_attempts = pth.function_execution_attempts.get_subdict(self)
290
+ past_attempts = self.execution_attempts
277
291
  n_past_attempts = len(past_attempts)
278
292
  if n_past_attempts == 0:
279
293
  return True
@@ -289,12 +303,89 @@ class FuncOutputAddress(HashAddress):
289
303
  return False
290
304
 
291
305
  @property
292
- def execution_attempts(self) -> list:
293
- attempts = pth.function_execution_attempts.get_subdict(self[1])
294
- attemps_timed = {-attempts.mtimestamp(a):attempts[a] for a in attempts}
295
- times = sorted(attemps_timed)
296
- result = []
297
- for t in times:
298
- result.append(attemps_timed[t])
299
- return result
306
+ def execution_attempts(self) -> PersiDict:
307
+ attempts_path = self + ["attempts"]
308
+ attempts = pth.operational_hub.jason.get_subdict(attempts_path)
309
+ return attempts
310
+
311
+ @property
312
+ def execution_outputs(self) -> PersiDict:
313
+ outputs_path = self + ["outputs"]
314
+ outputs = pth.operational_hub.text.get_subdict(outputs_path)
315
+ return outputs
300
316
 
317
+ @property
318
+ def crashes(self) -> PersiDict:
319
+ crashes_path = self + ["crashes"]
320
+ crashes = pth.operational_hub.jason.get_subdict(crashes_path)
321
+ return crashes
322
+
323
+ @property
324
+ def events(self) -> PersiDict:
325
+ events_path = self + ["events"]
326
+ events = pth.operational_hub.jason.get_subdict(events_path)
327
+ return events
328
+
329
+ class FunctionExecutionContext:
330
+ session_id: str
331
+ f_address: FunctionExecutionResultAddress
332
+ output_capturer = OutputCapturer
333
+ exception_counter: int
334
+ event_counter: int
335
+
336
+ def __init__(self, f_address: FunctionExecutionResultAddress):
337
+ self.session_id = get_random_signature()
338
+ self.f_address = f_address
339
+ self.output_capturer = OutputCapturer()
340
+ self.exception_counter = 0
341
+ self.event_counter = 0
342
+
343
+ def __enter__(self):
344
+ self.output_capturer.__enter__()
345
+ return self
346
+
347
+ def __exit__(self, exc_type, exc_value, trace_back):
348
+ self.output_capturer.__exit__(exc_type, exc_value, traceback)
349
+
350
+ output_id = self.session_id+"_o"
351
+ execution_outputs = self.f_address.execution_outputs
352
+ execution_outputs[output_id] = self.output_capturer.get_output()
353
+
354
+ self.register_exception(
355
+ exc_type=exc_type, exc_value=exc_value, trace_back=trace_back)
356
+
357
+
358
+ def register_execution_attempt(self):
359
+ execution_attempts = self.f_address.execution_attempts
360
+ attempt_id = self.session_id+"_a"
361
+ execution_attempts[attempt_id] = build_context()
362
+
363
+
364
+ def register_exception(self,exc_type, exc_value, trace_back, **kwargs):
365
+ if exc_value is None:
366
+ return
367
+ exception_id = self.session_id + f"_c_{self.exception_counter}"
368
+ self.f_address.crashes[exception_id] = add_context(
369
+ **kwargs, exc_value=exc_value)
370
+ self.exception_counter += 1
371
+ exception_id = exc_type.__name__ + "_"+ exception_id
372
+ exception_id = self.f_address.island_name + "_" + exception_id
373
+ exception_id = self.f_address.f_name + "_" + exception_id
374
+ register_exception_globally(**kwargs, exception_id=exception_id)
375
+
376
+ def register_event(self, event_type:str|None=None, **kwargs):
377
+ event_id = self.session_id + f"_e_{self.event_counter}"
378
+ if event_type is not None:
379
+ event_id += "_"+ event_type
380
+ events = self.f_address.events
381
+ events[event_id] = add_context(**kwargs, event_type=event_type)
382
+
383
+ event_id = self.session_id + f"_e_{self.event_counter}"
384
+ if event_type is not None:
385
+ kwargs["event_type"] = event_type
386
+ event_id = event_type + "_"+ event_id
387
+ event_id = self.f_address.island_name + "_" + event_id
388
+ event_id = self.f_address.f_name + "_" + event_id
389
+ register_event_globally(**kwargs, event_id=event_id)
390
+
391
+ self.event_counter += 1
@@ -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.global_value_store[v]
28
+ unpacked_copy[k] = pth.value_store[v]
29
29
  else:
30
30
  unpacked_copy[k] = v
31
31
  return unpacked_copy
@@ -0,0 +1,5 @@
1
+ from pythagoras._05_events_and_exceptions.notebook_checker import (
2
+ is_executed_in_notebook)
3
+
4
+ from pythagoras._05_events_and_exceptions.event_poster import (
5
+ post_event)
@@ -0,0 +1,53 @@
1
+
2
+ from pythagoras._01_foundational_objects.hash_and_random_signatures import (
3
+ get_random_signature)
4
+ from pythagoras._05_events_and_exceptions.type_retrievers import (
5
+ retrieve_FunctionExecutionContext_class)
6
+ from pythagoras._05_events_and_exceptions.find_in_callstack import \
7
+ find_local_var_in_callstack
8
+ from pythagoras._05_events_and_exceptions.global_event_loggers import (
9
+ register_event_globally)
10
+
11
+ import pythagoras as pth
12
+
13
+
14
+ def get_current_function_execution_context():
15
+ all_context_objects = find_local_var_in_callstack(name_to_find="_pth_ec"
16
+ , class_to_find=retrieve_FunctionExecutionContext_class())
17
+ if len(all_context_objects) > 0:
18
+ return all_context_objects[0]
19
+ else:
20
+ return None
21
+
22
+
23
+ class EventPosterFactory:
24
+ def __init__(self):
25
+ pass
26
+
27
+ def __getitem__(self, item):
28
+ return EventPoster(event_type = item)
29
+
30
+ def __call__(self, **kwargs):
31
+ return EventPoster(event_type = None)(**kwargs)
32
+
33
+ class EventPoster:
34
+ def __init__(self, event_type: str|None):
35
+ assert isinstance(event_type, (str, type(None)))
36
+ self.event_type = event_type
37
+
38
+ def __call__(self,**kwargs) -> None:
39
+ assert pth.is_correctly_initialized(), (
40
+ "The Pythagoras package has not been correctly initialized.")
41
+ context = get_current_function_execution_context()
42
+ if context is not None:
43
+ context.register_event(event_type = self.event_type, **kwargs)
44
+ else:
45
+ if self.event_type is not None:
46
+ kwargs["event_type"] = self.event_type
47
+ event_id = self.event_type + "_" + get_random_signature()
48
+ else:
49
+ event_id = get_random_signature()
50
+ register_event_globally(**kwargs, event_id = event_id)
51
+
52
+ post_event = EventPosterFactory()
53
+
@@ -0,0 +1,27 @@
1
+ import sys
2
+
3
+ from pythagoras._05_events_and_exceptions.context_utils import add_context
4
+ from pythagoras._05_events_and_exceptions.current_date_gmt_str import (
5
+ current_date_gmt_string)
6
+ from pythagoras import get_random_signature
7
+
8
+ import pythagoras as pth
9
+
10
+
11
+
12
+ def register_exception_globally(exception_id = None, **kwargs):
13
+ path = current_date_gmt_string()
14
+ exc_type, exc_value, trace_back = sys.exc_info()
15
+ if exception_id is None:
16
+ exception_id = exc_type.__name__ + "_" + get_random_signature()
17
+ full_path = [path, exception_id]
18
+ pth.crash_history[full_path] = add_context(
19
+ exc_value=exc_value, **kwargs)
20
+
21
+
22
+ def register_event_globally(event_id = None, **kwargs):
23
+ path = current_date_gmt_string()
24
+ if event_id is None:
25
+ event_id = get_random_signature()
26
+ full_path = [path, event_id]
27
+ pth.event_log[full_path] = add_context(**kwargs)
@@ -18,13 +18,22 @@ def retrieve_AutonomousFunction_class() -> type:
18
18
  return sys.modules['pythagoras'].AutonomousFunction
19
19
 
20
20
 
21
- def retrieve_FuncOutputAddress_class() -> type:
22
- """Return the FuncOutputAddress class.
21
+ def retrieve_FunctionExecutionResultAddress_class() -> type:
22
+ """Return the FunctionExecutionResultAddress class.
23
23
 
24
24
  This is for-internal-use-only function, created to
25
25
  avoid circular import dependencies.
26
26
  """
27
- return sys.modules['pythagoras'].FuncOutputAddress
27
+ return sys.modules['pythagoras'].FunctionExecutionResultAddress
28
+
29
+
30
+ def retrieve_FunctionExecutionContext_class() -> type:
31
+ """Return the FunctionExecutionContext class.
32
+
33
+ This is for-internal-use-only function, created to
34
+ avoid circular import dependencies.
35
+ """
36
+ return sys.modules['pythagoras'].FunctionExecutionContext
28
37
 
29
38
 
30
39
 
@@ -1,14 +1,14 @@
1
1
  import sys, traceback
2
2
 
3
3
  from pythagoras._05_events_and_exceptions.notebook_checker import is_executed_in_notebook
4
- from pythagoras._05_events_and_exceptions.event_logger import log_exception
5
-
4
+ from pythagoras._05_events_and_exceptions.global_event_loggers import (
5
+ register_exception_globally)
6
6
 
7
7
  import pythagoras as pth
8
8
 
9
9
 
10
10
  # def log_uncaught_exception(exception: Exception, **kwargs):
11
- # logger = EventLogger(event_log = pth.global_crash_history
11
+ # logger = EventLogger(event_log = pth.crash_history
12
12
  # , prefix = "__none__"+ exception.__class__.__name__
13
13
  # , save_context = True)
14
14
  # logger.log_event(exception=exception, **kwargs)
@@ -21,7 +21,7 @@ def pth_excepthook(exc_type, exc_value, trace_back) -> None:
21
21
  # exc_type, exc_value, trace_back)
22
22
  # log_uncaught_exception(exception = exc_value
23
23
  # , exception_description = exception_description)
24
- log_exception()
24
+ register_exception_globally()
25
25
  sys.__excepthook__(exc_type, exc_value, trace_back)
26
26
 
27
27
  def pth_excepthandler(_, exc_type, exc_value
@@ -30,7 +30,7 @@ def pth_excepthandler(_, exc_type, exc_value
30
30
  # exc_type, exc_value, trace_back)
31
31
  # log_uncaught_exception(exception=exc_value
32
32
  # , exception_description=exception_description)
33
- log_exception()
33
+ register_exception_globally()
34
34
  traceback.print_exception(exc_type, exc_value, trace_back)
35
35
 
36
36
 
@@ -10,3 +10,6 @@ from pythagoras._06_mission_control.global_state_management import (
10
10
  )
11
11
 
12
12
  from pythagoras._06_mission_control.summary import summary
13
+
14
+ from pythagoras._06_mission_control.operational_hub import (
15
+ OperationalHub)