lionagi 0.15.13__py3-none-any.whl → 0.16.0__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.
- lionagi/config.py +1 -0
- lionagi/libs/validate/fuzzy_match_keys.py +5 -182
- lionagi/libs/validate/string_similarity.py +6 -331
- lionagi/ln/__init__.py +56 -66
- lionagi/ln/_async_call.py +13 -10
- lionagi/ln/_hash.py +33 -8
- lionagi/ln/_list_call.py +2 -35
- lionagi/ln/_to_list.py +51 -28
- lionagi/ln/_utils.py +156 -0
- lionagi/ln/concurrency/__init__.py +39 -31
- lionagi/ln/concurrency/_compat.py +65 -0
- lionagi/ln/concurrency/cancel.py +92 -109
- lionagi/ln/concurrency/errors.py +17 -17
- lionagi/ln/concurrency/patterns.py +249 -206
- lionagi/ln/concurrency/primitives.py +257 -216
- lionagi/ln/concurrency/resource_tracker.py +42 -155
- lionagi/ln/concurrency/task.py +55 -73
- lionagi/ln/concurrency/throttle.py +3 -0
- lionagi/ln/concurrency/utils.py +1 -0
- lionagi/ln/fuzzy/__init__.py +15 -0
- lionagi/ln/{_extract_json.py → fuzzy/_extract_json.py} +22 -9
- lionagi/ln/{_fuzzy_json.py → fuzzy/_fuzzy_json.py} +14 -8
- lionagi/ln/fuzzy/_fuzzy_match.py +172 -0
- lionagi/ln/fuzzy/_fuzzy_validate.py +46 -0
- lionagi/ln/fuzzy/_string_similarity.py +332 -0
- lionagi/ln/{_models.py → types.py} +153 -4
- lionagi/operations/flow.py +2 -1
- lionagi/operations/operate/operate.py +26 -16
- lionagi/protocols/contracts.py +46 -0
- lionagi/protocols/generic/event.py +6 -6
- lionagi/protocols/generic/processor.py +9 -5
- lionagi/protocols/ids.py +82 -0
- lionagi/protocols/types.py +10 -12
- lionagi/service/connections/match_endpoint.py +9 -0
- lionagi/service/connections/providers/nvidia_nim_.py +100 -0
- lionagi/utils.py +34 -64
- lionagi/version.py +1 -1
- {lionagi-0.15.13.dist-info → lionagi-0.16.0.dist-info}/METADATA +4 -2
- {lionagi-0.15.13.dist-info → lionagi-0.16.0.dist-info}/RECORD +41 -33
- lionagi/ln/_types.py +0 -146
- {lionagi-0.15.13.dist-info → lionagi-0.16.0.dist-info}/WHEEL +0 -0
- {lionagi-0.15.13.dist-info → lionagi-0.16.0.dist-info}/licenses/LICENSE +0 -0
lionagi/ln/concurrency/cancel.py
CHANGED
@@ -1,134 +1,117 @@
|
|
1
|
-
"""Cancellation
|
1
|
+
"""Cancellation helpers for structured concurrency (anyio-backed)."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
2
4
|
|
3
|
-
import time
|
4
5
|
from collections.abc import Iterator
|
5
6
|
from contextlib import contextmanager
|
6
|
-
from types import TracebackType
|
7
|
-
from typing import TypeVar
|
8
7
|
|
9
8
|
import anyio
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
"""
|
24
|
-
self._scope = None
|
25
|
-
self._deadline = deadline
|
26
|
-
self._shield = shield
|
27
|
-
self.cancel_called = False
|
28
|
-
self.cancelled_caught = False
|
29
|
-
|
30
|
-
def cancel(self) -> None:
|
31
|
-
"""Cancel this scope.
|
32
|
-
|
33
|
-
This will cause all tasks within this scope to be cancelled.
|
34
|
-
"""
|
35
|
-
self.cancel_called = True
|
36
|
-
if self._scope is not None:
|
37
|
-
self._scope.cancel()
|
38
|
-
|
39
|
-
def __enter__(self) -> "CancelScope":
|
40
|
-
"""Enter the cancel scope context.
|
41
|
-
|
42
|
-
Returns:
|
43
|
-
The cancel scope instance.
|
44
|
-
"""
|
45
|
-
# Use math.inf as the default deadline (no timeout)
|
46
|
-
import math
|
47
|
-
|
48
|
-
deadline = self._deadline if self._deadline is not None else math.inf
|
49
|
-
self._scope = anyio.CancelScope(deadline=deadline, shield=self._shield)
|
50
|
-
if self.cancel_called:
|
51
|
-
self._scope.cancel()
|
52
|
-
self._scope.__enter__()
|
53
|
-
return self
|
54
|
-
|
55
|
-
def __exit__(
|
56
|
-
self,
|
57
|
-
exc_type: type[BaseException] | None,
|
58
|
-
exc_val: BaseException | None,
|
59
|
-
exc_tb: TracebackType | None,
|
60
|
-
) -> bool:
|
61
|
-
"""Exit the cancel scope context.
|
62
|
-
|
63
|
-
Returns:
|
64
|
-
True if the exception was handled, False otherwise.
|
65
|
-
"""
|
66
|
-
if self._scope is None:
|
67
|
-
return False
|
68
|
-
|
69
|
-
try:
|
70
|
-
result = self._scope.__exit__(exc_type, exc_val, exc_tb)
|
71
|
-
self.cancelled_caught = self._scope.cancelled_caught
|
72
|
-
return result
|
73
|
-
finally:
|
74
|
-
self._scope = None
|
10
|
+
CancelScope = anyio.CancelScope
|
11
|
+
_INF = float("inf")
|
12
|
+
|
13
|
+
|
14
|
+
__all__ = (
|
15
|
+
"CancelScope",
|
16
|
+
"fail_after",
|
17
|
+
"move_on_after",
|
18
|
+
"fail_at",
|
19
|
+
"move_on_at",
|
20
|
+
"effective_deadline",
|
21
|
+
)
|
75
22
|
|
76
23
|
|
77
24
|
@contextmanager
|
78
|
-
def
|
79
|
-
"""
|
25
|
+
def fail_after(seconds: float | None) -> Iterator[CancelScope]:
|
26
|
+
"""Create a context with a timeout that raises TimeoutError on expiry.
|
80
27
|
|
81
28
|
Args:
|
82
|
-
seconds:
|
29
|
+
seconds: Timeout duration in seconds. None means no timeout
|
30
|
+
(but still cancellable by outer scopes).
|
83
31
|
|
84
|
-
|
85
|
-
|
32
|
+
Yields:
|
33
|
+
CancelScope that can be cancelled after the timeout.
|
86
34
|
|
87
|
-
|
88
|
-
|
89
|
-
await long_running_operation()
|
90
|
-
if scope.cancelled_caught:
|
91
|
-
print("Operation timed out")
|
35
|
+
Raises:
|
36
|
+
TimeoutError: If the timeout expires before the block completes.
|
92
37
|
"""
|
93
|
-
|
94
|
-
|
95
|
-
|
38
|
+
if seconds is None:
|
39
|
+
# No timeout, but still cancellable by outer scopes
|
40
|
+
with CancelScope() as scope:
|
41
|
+
yield scope
|
42
|
+
return
|
43
|
+
with anyio.fail_after(seconds) as scope:
|
96
44
|
yield scope
|
97
45
|
|
98
46
|
|
99
47
|
@contextmanager
|
100
|
-
def
|
101
|
-
"""
|
48
|
+
def move_on_after(seconds: float | None) -> Iterator[CancelScope]:
|
49
|
+
"""Create a context with a timeout that silently cancels on expiry.
|
102
50
|
|
103
51
|
Args:
|
104
|
-
seconds:
|
52
|
+
seconds: Timeout duration in seconds. None means no timeout
|
53
|
+
(but still cancellable by outer scopes).
|
54
|
+
|
55
|
+
Yields:
|
56
|
+
CancelScope with cancelled_caught attribute to check if timeout occurred.
|
57
|
+
"""
|
58
|
+
if seconds is None:
|
59
|
+
# No timeout, but still cancellable by outer scopes
|
60
|
+
with CancelScope() as scope:
|
61
|
+
yield scope
|
62
|
+
return
|
63
|
+
with anyio.move_on_after(seconds) as scope:
|
64
|
+
yield scope
|
105
65
|
|
106
|
-
|
107
|
-
|
66
|
+
|
67
|
+
@contextmanager
|
68
|
+
def fail_at(deadline: float | None) -> Iterator[CancelScope]:
|
69
|
+
"""Create a context that raises TimeoutError at an absolute deadline.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
deadline: Absolute monotonic timestamp for timeout.
|
73
|
+
None means no timeout (but still cancellable).
|
74
|
+
|
75
|
+
Yields:
|
76
|
+
CancelScope that expires at the specified deadline.
|
108
77
|
|
109
78
|
Raises:
|
110
|
-
TimeoutError: If the
|
111
|
-
|
112
|
-
Example:
|
113
|
-
try:
|
114
|
-
with fail_after(5):
|
115
|
-
await long_running_operation()
|
116
|
-
except TimeoutError:
|
117
|
-
print("Operation timed out")
|
79
|
+
TimeoutError: If the deadline is reached before the block completes.
|
118
80
|
"""
|
119
|
-
if
|
120
|
-
# No timeout
|
121
|
-
|
122
|
-
|
81
|
+
if deadline is None:
|
82
|
+
# No timeout, but still cancellable by outer scopes
|
83
|
+
with CancelScope() as scope:
|
84
|
+
yield scope
|
85
|
+
return
|
86
|
+
now = anyio.current_time()
|
87
|
+
seconds = max(0.0, deadline - now)
|
88
|
+
with fail_after(seconds) as scope:
|
89
|
+
yield scope
|
90
|
+
|
91
|
+
|
92
|
+
@contextmanager
|
93
|
+
def move_on_at(deadline: float | None) -> Iterator[CancelScope]:
|
94
|
+
"""Create a context that silently cancels at an absolute deadline.
|
95
|
+
|
96
|
+
Args:
|
97
|
+
deadline: Absolute monotonic timestamp for timeout.
|
98
|
+
None means no timeout (but still cancellable).
|
99
|
+
|
100
|
+
Yields:
|
101
|
+
CancelScope with cancelled_caught attribute to check if deadline was reached.
|
102
|
+
"""
|
103
|
+
if deadline is None:
|
104
|
+
# No timeout, but still cancellable by outer scopes
|
105
|
+
with CancelScope() as scope:
|
123
106
|
yield scope
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
107
|
+
return
|
108
|
+
now = anyio.current_time()
|
109
|
+
seconds = max(0.0, deadline - now)
|
110
|
+
with anyio.move_on_after(seconds) as scope:
|
111
|
+
yield scope
|
112
|
+
|
113
|
+
|
114
|
+
def effective_deadline() -> float | None:
|
115
|
+
"""Return the ambient effective deadline, or None if unlimited."""
|
116
|
+
d = anyio.current_effective_deadline()
|
117
|
+
return None if d == _INF else d
|
lionagi/ln/concurrency/errors.py
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
"""Error
|
1
|
+
"""Error/cancellation utilities with backend-agnostic behavior."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
2
4
|
|
3
5
|
from collections.abc import Awaitable, Callable
|
4
6
|
from typing import Any, TypeVar
|
@@ -8,28 +10,26 @@ import anyio
|
|
8
10
|
T = TypeVar("T")
|
9
11
|
|
10
12
|
|
11
|
-
|
12
|
-
""
|
13
|
+
__all__ = (
|
14
|
+
"get_cancelled_exc_class",
|
15
|
+
"is_cancelled",
|
16
|
+
"shield",
|
17
|
+
)
|
13
18
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
"""
|
19
|
+
|
20
|
+
def get_cancelled_exc_class() -> type[BaseException]:
|
21
|
+
"""Return the backend-native cancellation exception class."""
|
18
22
|
return anyio.get_cancelled_exc_class()
|
19
23
|
|
20
24
|
|
25
|
+
def is_cancelled(exc: BaseException) -> bool:
|
26
|
+
"""True if this is the backend-native cancellation exception."""
|
27
|
+
return isinstance(exc, anyio.get_cancelled_exc_class())
|
28
|
+
|
29
|
+
|
21
30
|
async def shield(
|
22
31
|
func: Callable[..., Awaitable[T]], *args: Any, **kwargs: Any
|
23
32
|
) -> T:
|
24
|
-
"""Run
|
25
|
-
|
26
|
-
Args:
|
27
|
-
func: The coroutine function to call
|
28
|
-
*args: Positional arguments to pass to the function
|
29
|
-
**kwargs: Keyword arguments to pass to the function
|
30
|
-
|
31
|
-
Returns:
|
32
|
-
The return value of the function
|
33
|
-
"""
|
33
|
+
"""Run ``func`` immune to outer cancellation."""
|
34
34
|
with anyio.CancelScope(shield=True):
|
35
35
|
return await func(*args, **kwargs)
|