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
@@ -2,7 +2,15 @@
2
2
  _is_in_notebook: bool|None = None
3
3
 
4
4
  def is_executed_in_notebook() -> bool:
5
- """ Return True if running inside a Jupyter notebook. """
5
+ """Return whether code is running inside a Jupyter/IPython notebook.
6
+
7
+ Uses a lightweight heuristic: checks if IPython is present and whether the
8
+ current shell exposes the set_custom_exc attribute, which is specific to
9
+ IPython interactive environments (including Jupyter).
10
+
11
+ Returns:
12
+ bool: True if running inside a Jupyter/IPython notebook, False otherwise.
13
+ """
6
14
  global _is_in_notebook
7
15
  if _is_in_notebook is not None:
8
16
  return _is_in_notebook
@@ -16,6 +16,17 @@ from .._800_signatures_and_converters.random_signatures import (
16
16
 
17
17
 
18
18
  def pth_excepthook(exc_type, exc_value, trace_back) -> None:
19
+ """sys.excepthook replacement that logs uncaught exceptions.
20
+
21
+ Args:
22
+ exc_type: The exception class.
23
+ exc_value: The exception instance.
24
+ trace_back: Traceback object for the exception.
25
+
26
+ Side Effects:
27
+ - Records the exception in the active LoggingCodePortal's crash history.
28
+ - Calls the original sys.__excepthook__ after logging.
29
+ """
19
30
  if _exception_needs_to_be_processed(exc_type, exc_value, trace_back):
20
31
  exception_id = "app_"+ get_random_signature() + "_crash"
21
32
  event_body = add_execution_environment_summary(
@@ -30,6 +41,17 @@ def pth_excepthook(exc_type, exc_value, trace_back) -> None:
30
41
 
31
42
  def pth_excepthandler(_, exc_type, exc_value
32
43
  , trace_back, tb_offset=None) -> None:
44
+ """IPython custom exception handler that logs uncaught exceptions.
45
+
46
+ This signature matches IPython's set_custom_exc handler protocol.
47
+
48
+ Args:
49
+ _: Unused first parameter required by IPython.
50
+ exc_type: The exception class.
51
+ exc_value: The exception instance.
52
+ trace_back: Traceback object for the exception.
53
+ tb_offset: Optional traceback offset used by IPython. Unused.
54
+ """
33
55
  if _exception_needs_to_be_processed(exc_type, exc_value, trace_back):
34
56
  exception_id = "app_" + get_random_signature() + "_crash"
35
57
  event_body = add_execution_environment_summary(
@@ -45,6 +67,15 @@ _previous_excepthook = None
45
67
  _number_of_handlers_registrations = 0
46
68
 
47
69
  def register_systemwide_uncaught_exception_handlers() -> None:
70
+ """Install Pythagoras handlers for uncaught exceptions system-wide.
71
+
72
+ In standard Python, replaces sys.excepthook; in Jupyter/IPython,
73
+ registers a custom exception handler via IPython.set_custom_exc when
74
+ available. Multiple registrations are reference-counted and idempotent.
75
+
76
+ Returns:
77
+ None
78
+ """
48
79
  global _number_of_handlers_registrations, _previous_excepthook
49
80
  _number_of_handlers_registrations += 1
50
81
  if _number_of_handlers_registrations > 1:
@@ -64,6 +95,15 @@ def register_systemwide_uncaught_exception_handlers() -> None:
64
95
 
65
96
 
66
97
  def unregister_systemwide_uncaught_exception_handlers() -> None:
98
+ """Uninstall previously registered Pythagoras exception handlers.
99
+
100
+ Decrements the registration reference counter. When it reaches zero,
101
+ restores the previous sys.excepthook (if any) and removes the custom
102
+ IPython exception handler in notebook environments.
103
+
104
+ Returns:
105
+ None
106
+ """
67
107
  global _number_of_handlers_registrations, _previous_excepthook
68
108
  _number_of_handlers_registrations -= 1
69
109
  if _number_of_handlers_registrations > 0:
@@ -7,12 +7,29 @@ from .safe_portal_core_classes import SafeFn, SafeCodePortal
7
7
 
8
8
 
9
9
  class safe(logging):
10
- """A decorator that converts a Python function into a SafeFn object.
10
+ """Decorator that wraps a callable into a SafeFn for portal execution.
11
+
12
+ Usage:
13
+ @safe()
14
+ def my_fn(x: int) -> int:
15
+ return x + 1
16
+
17
+ Notes:
18
+ This decorator configures only logging-related behavior for now. Actual
19
+ safety/sandboxing is not yet implemented.
11
20
  """
12
21
 
13
22
  def __init__(self
14
23
  , excessive_logging: bool|None|Joker = KEEP_CURRENT
15
24
  , portal: SafeCodePortal | None = None):
25
+ """Create a safe decorator bound to an optional portal.
26
+
27
+ Args:
28
+ excessive_logging: Whether to enable verbose logging for wrapped
29
+ calls. KEEP_CURRENT inherits from current context.
30
+ portal: The SafeCodePortal to attach the resulting SafeFn to. If
31
+ None, the active portal (if any) may be used by lower layers.
32
+ """
16
33
  assert isinstance(portal, SafeCodePortal) or portal is None
17
34
  logging.__init__(self=self
18
35
  , portal=portal
@@ -20,6 +37,15 @@ class safe(logging):
20
37
 
21
38
 
22
39
  def __call__(self,fn:Callable)->SafeFn:
40
+ """Wrap a Python callable into a SafeFn.
41
+
42
+ Args:
43
+ fn: The function to wrap.
44
+
45
+ Returns:
46
+ SafeFn: The wrapped function that can be executed via a portal and
47
+ will record logging information.
48
+ """
23
49
  wrapper = SafeFn(fn
24
50
  , portal=self._portal
25
51
  , excessive_logging=self._excessive_logging)
@@ -13,20 +13,43 @@ It will be done soon by integrating https://pypi.org/project/RestrictedPython/
13
13
 
14
14
  from __future__ import annotations
15
15
 
16
- from typing import Callable
17
-
18
- # from parameterizable import register_parameterizable_class
19
- from persidict import PersiDict, Joker, KEEP_CURRENT
20
-
21
16
  from .._040_logging_code_portals.logging_portal_core_classes import *
22
17
 
23
18
 
24
19
  class SafeCodePortal(LoggingCodePortal):
20
+ """A portal that executes functions with logging under a "safe" contract.
21
+
22
+ Currently, SafeCodePortal inherits all behavior from LoggingCodePortal.
23
+ True sandboxing/isolation has not yet been implemented and will be
24
+ introduced in the future (see Notes).
25
+
26
+ Notes:
27
+ The actual safety guarantees (prohibiting access to external
28
+ filesystem, network, process state, etc.) are not yet enforced.
29
+ The plan is to integrate RestrictedPython to implement a proper
30
+ sandbox. Until then, SafeCodePortal behaves like LoggingCodePortal
31
+ but keeps the API intended for safe execution.
32
+ """
33
+
25
34
  def __init__(self
26
35
  , root_dict: PersiDict|str|None = None
27
36
  , p_consistency_checks: float|Joker = KEEP_CURRENT
28
37
  , excessive_logging: bool|Joker = KEEP_CURRENT
29
38
  ):
39
+ """Initialize a SafeCodePortal.
40
+
41
+ Args:
42
+ root_dict: Root persistent dictionary or its path used by the
43
+ underlying data portal for storing execution artifacts. If a
44
+ string is provided, it is treated as a path on disk. If None,
45
+ an in-memory structure may be used (depending on configuration).
46
+ p_consistency_checks: Probability in [0, 1] of running additional
47
+ consistency checks on persistent state mutations. Use
48
+ KEEP_CURRENT to inherit the active setting from parent context.
49
+ excessive_logging: Whether to enable verbose logging of execution
50
+ attempts, results, outputs and events. Use KEEP_CURRENT to
51
+ inherit the active setting from parent context.
52
+ """
30
53
  LoggingCodePortal.__init__(self
31
54
  , root_dict=root_dict
32
55
  , p_consistency_checks=p_consistency_checks
@@ -34,26 +57,60 @@ class SafeCodePortal(LoggingCodePortal):
34
57
 
35
58
 
36
59
  class SafeFnCallSignature(LoggingFnCallSignature):
37
- """A signature of a call to a safe function"""
60
+ """A signature object describing a call to a SafeFn.
61
+
62
+ This specialization only narrows the types returned by some accessors
63
+ (e.g., fn) to Safe* counterparts. All logging behavior and storage layout
64
+ are inherited from LoggingFnCallSignature.
65
+ """
38
66
  _fn_cache: SafeFn | None
39
67
 
40
68
  def __init__(self, fn: SafeFn, arguments: dict):
69
+ """Construct a signature for a specific SafeFn call.
70
+
71
+ Args:
72
+ fn: The safe function object to be called.
73
+ arguments: The keyword arguments to use for the call.
74
+ """
41
75
  assert isinstance(fn, SafeFn)
42
76
  assert isinstance(arguments, dict)
43
77
  super().__init__(fn, arguments)
44
78
 
45
79
  @property
46
80
  def fn(self) -> SafeFn:
47
- """Return the function object referenced by the signature."""
81
+ """Return the SafeFn referenced by this signature.
82
+
83
+ Returns:
84
+ SafeFn: The underlying safe function instance.
85
+ """
48
86
  return super().fn
49
87
 
50
88
 
51
89
  class SafeFn(LoggingFn):
90
+ """A function wrapper intended for safe execution within a portal.
91
+
92
+ SafeFn currently behaves like LoggingFn, adding only type-narrowed
93
+ accessors for convenience. Future versions will enforce sandboxed
94
+ execution (see Notes).
95
+
96
+ Notes:
97
+ No actual sandboxing is performed yet. Behavior equals LoggingFn.
98
+ """
99
+
52
100
  def __init__(self
53
101
  , fn: Callable|str
54
102
  , portal: LoggingCodePortal|None = None
55
103
  , excessive_logging: bool|Joker = KEEP_CURRENT
56
104
  ):
105
+ """Create a SafeFn wrapper.
106
+
107
+ Args:
108
+ fn: The Python callable to wrap or its import string.
109
+ portal: The portal to associate with this function. If None, the
110
+ active portal (if any) may be used by the underlying layers.
111
+ excessive_logging: Whether to enable verbose logging for this fn.
112
+ Use KEEP_CURRENT to inherit from the surrounding context.
113
+ """
57
114
  LoggingFn.__init__(self
58
115
  , fn = fn
59
116
  , portal=portal
@@ -61,23 +118,42 @@ class SafeFn(LoggingFn):
61
118
 
62
119
 
63
120
  def __getstate__(self):
64
- """This method is called when the object is pickled."""
121
+ """Return picklable state.
122
+
123
+ Returns:
124
+ dict: The state returned by the parent LoggingFn for pickling.
125
+ """
65
126
  state = super().__getstate__()
66
127
  return state
67
128
 
68
129
 
69
130
  def __setstate__(self, state):
70
- """This method is called when the object is unpickled."""
131
+ """Restore object state after unpickling.
132
+
133
+ Args:
134
+ state: The state previously produced by __getstate__.
135
+ """
71
136
  super().__setstate__(state)
72
137
 
73
138
 
74
139
  @property
75
140
  def portal(self) -> SafeCodePortal:
141
+ """Return the associated SafeCodePortal.
142
+
143
+ Returns:
144
+ SafeCodePortal: The portal that owns this function.
145
+ """
76
146
  return super().portal
77
147
 
78
148
 
79
149
  def get_signature(self, arguments:dict) -> SafeFnCallSignature:
80
- return SafeFnCallSignature(fn=self, arguments=arguments)
150
+ """Create a SafeFnCallSignature for a given call.
81
151
 
152
+ Args:
153
+ arguments: The keyword arguments for the call.
82
154
 
83
- # register_parameterizable_class(SafeCodePortal)
155
+ Returns:
156
+ SafeFnCallSignature: A typed call signature suitable for execution
157
+ and logging through the portal.
158
+ """
159
+ return SafeFnCallSignature(fn=self, arguments=arguments)
@@ -43,11 +43,16 @@ from persidict import Joker, KEEP_CURRENT
43
43
 
44
44
 
45
45
  class autonomous(safe):
46
- """Decorator for enforcing autonomicity requirements for functions.
46
+ """Decorator that turns a regular function into an autonomous one.
47
47
 
48
- An autonomous function is only allowed to use the built-in objects
49
- (functions, types, variables), as well as global objects,
50
- accessible via import statements inside the function body.
48
+ An autonomous function is a self-contained function: it
49
+ can only use built-ins and any names it imports inside its own body. This
50
+ decorator wraps the target callable into an AutonomousFn and enforces both
51
+ static and runtime autonomy checks via the selected portal.
52
+
53
+ Notes:
54
+ - Only regular (non-async) functions are supported.
55
+ - Methods, closures, lambdas, and coroutines are not considered autonomous.
51
56
  """
52
57
  _fixed_args: dict|None
53
58
 
@@ -56,6 +61,19 @@ class autonomous(safe):
56
61
  , excessive_logging: bool|Joker = KEEP_CURRENT
57
62
  , portal: AutonomousCodePortal | None = None
58
63
  ):
64
+ """Initialize the decorator.
65
+
66
+ Args:
67
+ fixed_kwargs: Keyword arguments to pre-bind (partially apply) to the
68
+ decorated function. These will be merged into every call.
69
+ excessive_logging: If True, enables verbose logging within the
70
+ selected portal. KEEP_CURRENT leaves the portal's setting as-is.
71
+ portal: Portal instance to use for autonomy and safety checks.
72
+
73
+ Raises:
74
+ AssertionError: If portal is not an AutonomousCodePortal or None, or
75
+ if fixed_kwargs is not a dict or None.
76
+ """
59
77
  assert isinstance(portal, AutonomousCodePortal) or portal is None
60
78
  assert isinstance(fixed_kwargs, dict) or fixed_kwargs is None
61
79
  safe.__init__(self=self
@@ -65,6 +83,15 @@ class autonomous(safe):
65
83
 
66
84
 
67
85
  def __call__(self, fn: Callable|str) -> AutonomousFn:
86
+ """Wrap the function with autonomy enforcement.
87
+
88
+ Args:
89
+ fn: The function object to decorate.
90
+
91
+ Returns:
92
+ AutonomousFn: A wrapper that enforces autonomy at decoration and at
93
+ execution time, with any fixed keyword arguments pre-applied.
94
+ """
68
95
  wrapper = AutonomousFn(fn
69
96
  ,portal=self._portal
70
97
  ,fixed_kwargs=self._fixed_kwargs
@@ -1,14 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import builtins
4
- from typing import Callable, Any
5
-
6
- from persidict import PersiDict, Joker, KEEP_CURRENT
7
-
8
- from .._010_basic_portals import PortalAwareClass
9
- from .._010_basic_portals.basic_portal_core_classes import _visit_portal
10
4
  from .._020_ordinary_code_portals.code_normalizer import _pythagoras_decorator_names
11
- from .._030_data_portals import DataPortal
12
5
  from .._040_logging_code_portals import KwArgs
13
6
 
14
7
  from .._060_autonomous_code_portals.names_usage_analyzer import (
@@ -17,12 +10,27 @@ from .._060_autonomous_code_portals.names_usage_analyzer import (
17
10
  from .._050_safe_code_portals.safe_portal_core_classes import *
18
11
 
19
12
  class AutonomousCodePortal(SafeCodePortal):
20
-
13
+ """Portal configured for enforcing autonomy constraints.
14
+
15
+ This portal behaves like SafeCodePortal but is specialized for autonomous
16
+ functions. It controls logging and consistency checks for operations related
17
+ to AutonomousFn instances.
18
+ """
21
19
  def __init__(self
22
20
  , root_dict: PersiDict | str | None = None
23
21
  , p_consistency_checks: float | Joker = KEEP_CURRENT
24
22
  , excessive_logging: bool|Joker = KEEP_CURRENT
25
23
  ):
24
+ """Create an autonomous code portal.
25
+
26
+ Args:
27
+ root_dict: Persistence root backing the portal state. Can be a
28
+ PersiDict instance, a path string, or None for defaults.
29
+ p_consistency_checks: Probability [0..1] to run extra consistency
30
+ checks on operations. KEEP_CURRENT uses the existing setting.
31
+ excessive_logging: Whether to enable verbose logging. KEEP_CURRENT
32
+ preserves the existing portal setting.
33
+ """
26
34
  SafeCodePortal.__init__(self
27
35
  , root_dict=root_dict
28
36
  , p_consistency_checks=p_consistency_checks
@@ -30,10 +38,19 @@ class AutonomousCodePortal(SafeCodePortal):
30
38
 
31
39
 
32
40
  class AutonomousFnCallSignature(SafeFnCallSignature):
33
- """A signature of a call to an autonomous function"""
41
+ """A signature of a call to an autonomous function.
42
+
43
+ This extends SafeFnCallSignature to reference AutonomousFn instances.
44
+ """
34
45
  _fn_cache: AutonomousFn | None
35
46
 
36
47
  def __init__(self, fn: AutonomousFn, arguments: dict):
48
+ """Create a call signature for an autonomous function.
49
+
50
+ Args:
51
+ fn: The autonomous function being called.
52
+ arguments: The call-time arguments mapping (already validated).
53
+ """
37
54
  assert isinstance(fn, AutonomousFn)
38
55
  assert isinstance(arguments, dict)
39
56
  super().__init__(fn, arguments)
@@ -45,7 +62,13 @@ class AutonomousFnCallSignature(SafeFnCallSignature):
45
62
 
46
63
 
47
64
  class AutonomousFn(SafeFn):
65
+ """A SafeFn wrapper that enforces function autonomy rules.
48
66
 
67
+ AutonomousFn performs static validation at construction time to ensure that
68
+ the wrapped function uses only built-ins or names imported inside its body,
69
+ has no yield statements, and does not reference nonlocal variables.
70
+ It also supports partial application via fixed keyword arguments.
71
+ """
49
72
  _fixed_kwargs_cache: KwArgs | None
50
73
  _fixed_kwargs_packed: KwArgs | None
51
74
 
@@ -53,6 +76,20 @@ class AutonomousFn(SafeFn):
53
76
  , fixed_kwargs: dict[str,Any]|None = None
54
77
  , excessive_logging: bool|Joker = KEEP_CURRENT
55
78
  , portal: AutonomousCodePortal|None = None):
79
+ """Construct an AutonomousFn and validate autonomy constraints.
80
+
81
+ Args:
82
+ fn: The function object, a string with the function's source code,
83
+ or an existing SafeFn to wrap. If an AutonomousFn is provided,
84
+ fixed_kwargs are merged.
85
+ fixed_kwargs: Keyword arguments to pre-bind (partially apply).
86
+ excessive_logging: Verbose logging flag or KEEP_CURRENT.
87
+ portal: AutonomousCodePortal to use; may be None to defer.
88
+
89
+ Raises:
90
+ AssertionError: If static analysis detects violations of autonomy
91
+ (nonlocal/global unbound names, missing imports, or yield usage).
92
+ """
56
93
  super().__init__(fn=fn
57
94
  , portal = portal
58
95
  , excessive_logging = excessive_logging)
@@ -105,6 +142,11 @@ class AutonomousFn(SafeFn):
105
142
 
106
143
  @property
107
144
  def fixed_kwargs(self) -> KwArgs:
145
+ """KwArgs of pre-bound keyword arguments for this function.
146
+
147
+ Returns:
148
+ KwArgs: The fixed keyword arguments.
149
+ """
108
150
  if not hasattr(self, "_fixed_kwargs_cache"):
109
151
  with self.portal:
110
152
  self._fixed_kwargs_cache = self._fixed_kwargs_packed.unpack()
@@ -112,6 +154,19 @@ class AutonomousFn(SafeFn):
112
154
 
113
155
 
114
156
  def execute(self, **kwargs) -> Any:
157
+ """Execute the function within the portal, applying fixed kwargs.
158
+
159
+ Any kwargs provided here must not overlap with pre-bound fixed kwargs.
160
+
161
+ Args:
162
+ **kwargs: Call-time keyword arguments.
163
+
164
+ Returns:
165
+ Any: Result of the wrapped function call.
166
+
167
+ Raises:
168
+ AssertionError: If provided kwargs overlap with fixed kwargs.
169
+ """
115
170
  with self.portal:
116
171
  overlapping_keys = set(kwargs.keys()) & set(self.fixed_kwargs.keys())
117
172
  assert len(overlapping_keys) == 0
@@ -120,16 +175,33 @@ class AutonomousFn(SafeFn):
120
175
 
121
176
 
122
177
  def get_signature(self, arguments:dict) -> AutonomousFnCallSignature:
178
+ """Build a call signature object for this function.
179
+
180
+ Args:
181
+ arguments: Mapping of argument names to values for this call.
182
+
183
+ Returns:
184
+ AutonomousFnCallSignature: The signature representing this call.
185
+ """
123
186
  return AutonomousFnCallSignature(fn=self, arguments=arguments)
124
187
 
125
188
 
126
189
  def fix_kwargs(self, **kwargs) -> AutonomousFn:
127
- """Create a new function by pre-filling some arguments.
190
+ """Create a new autonomous function with some kwargs pre-filled.
128
191
 
129
- This is called a partial application in functional programming
130
- It allows creating specialized functions from general ones by
131
- transforming a function with multiple parameters
132
- into another function with fewer parameters by fixing some arguments.
192
+ This is partial application: it creates a function with fewer parameters
193
+ by fixing a subset of keyword arguments.
194
+
195
+ Args:
196
+ **kwargs: Keyword arguments to fix for the new function.
197
+
198
+ Returns:
199
+ AutonomousFn: A new wrapper that will always apply the provided
200
+ keyword arguments in addition to already fixed ones.
201
+
202
+ Raises:
203
+ AssertionError: If any of the provided kwargs overlap with already
204
+ fixed kwargs.
133
205
  """
134
206
 
135
207
  overlapping_keys = set(kwargs.keys()) & set(self.fixed_kwargs.keys())
@@ -140,6 +212,13 @@ class AutonomousFn(SafeFn):
140
212
 
141
213
 
142
214
  def _first_visit_to_portal(self, portal: DataPortal) -> None:
215
+ """Hook called on the first visit to a data portal.
216
+
217
+ Ensures that fixed kwargs are materialized (packed) within the portal.
218
+
219
+ Args:
220
+ portal: The data portal being visited for the first time.
221
+ """
143
222
  super()._first_visit_to_portal(portal)
144
223
  with portal:
145
224
  _ = self.fixed_kwargs.pack()
@@ -160,6 +239,7 @@ class AutonomousFn(SafeFn):
160
239
 
161
240
  @property
162
241
  def portal(self) -> AutonomousCodePortal:
242
+ """Return the autonomous portal associated with this function."""
163
243
  return super().portal
164
244
 
165
245