ommlds 0.0.0.dev440__py3-none-any.whl → 0.0.0.dev480__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.
- ommlds/.omlish-manifests.json +332 -35
- ommlds/__about__.py +15 -9
- ommlds/_hacks/__init__.py +4 -0
- ommlds/_hacks/funcs.py +110 -0
- ommlds/_hacks/names.py +158 -0
- ommlds/_hacks/params.py +73 -0
- ommlds/_hacks/patches.py +0 -3
- ommlds/backends/anthropic/protocol/_marshal.py +2 -2
- ommlds/backends/anthropic/protocol/sse/_marshal.py +1 -1
- ommlds/backends/anthropic/protocol/sse/assemble.py +23 -7
- ommlds/backends/anthropic/protocol/sse/events.py +13 -0
- ommlds/backends/anthropic/protocol/types.py +30 -9
- ommlds/backends/google/protocol/__init__.py +3 -0
- ommlds/backends/google/protocol/_marshal.py +16 -0
- ommlds/backends/google/protocol/types.py +626 -0
- ommlds/backends/groq/_marshal.py +23 -0
- ommlds/backends/groq/protocol.py +249 -0
- ommlds/backends/mlx/generation.py +1 -1
- ommlds/backends/mlx/loading.py +58 -1
- ommlds/backends/ollama/__init__.py +0 -0
- ommlds/backends/ollama/protocol.py +170 -0
- ommlds/backends/openai/protocol/__init__.py +9 -28
- ommlds/backends/openai/protocol/_common.py +18 -0
- ommlds/backends/openai/protocol/_marshal.py +27 -0
- ommlds/backends/openai/protocol/chatcompletion/chunk.py +58 -31
- ommlds/backends/openai/protocol/chatcompletion/contentpart.py +49 -44
- ommlds/backends/openai/protocol/chatcompletion/message.py +55 -43
- ommlds/backends/openai/protocol/chatcompletion/request.py +114 -66
- ommlds/backends/openai/protocol/chatcompletion/response.py +71 -45
- ommlds/backends/openai/protocol/chatcompletion/responseformat.py +27 -20
- ommlds/backends/openai/protocol/chatcompletion/tokenlogprob.py +16 -7
- ommlds/backends/openai/protocol/completionusage.py +24 -15
- ommlds/backends/tavily/__init__.py +0 -0
- ommlds/backends/tavily/protocol.py +301 -0
- ommlds/backends/tinygrad/models/llama3/__init__.py +22 -14
- ommlds/backends/transformers/__init__.py +0 -0
- ommlds/backends/transformers/filecache.py +109 -0
- ommlds/backends/transformers/streamers.py +73 -0
- ommlds/cli/asyncs.py +30 -0
- ommlds/cli/backends/catalog.py +93 -0
- ommlds/cli/backends/configs.py +9 -0
- ommlds/cli/backends/inject.py +31 -36
- ommlds/cli/backends/injection.py +16 -0
- ommlds/cli/backends/types.py +46 -0
- ommlds/cli/content/__init__.py +0 -0
- ommlds/cli/content/messages.py +34 -0
- ommlds/cli/content/strings.py +42 -0
- ommlds/cli/inject.py +15 -32
- ommlds/cli/inputs/__init__.py +0 -0
- ommlds/cli/inputs/asyncs.py +32 -0
- ommlds/cli/inputs/sync.py +75 -0
- ommlds/cli/main.py +270 -110
- ommlds/cli/rendering/__init__.py +0 -0
- ommlds/cli/rendering/configs.py +9 -0
- ommlds/cli/rendering/inject.py +31 -0
- ommlds/cli/rendering/markdown.py +52 -0
- ommlds/cli/rendering/raw.py +73 -0
- ommlds/cli/rendering/types.py +21 -0
- ommlds/cli/secrets.py +21 -0
- ommlds/cli/sessions/base.py +1 -1
- ommlds/cli/sessions/chat/chat/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/ai/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/ai/inject.py +74 -0
- ommlds/cli/sessions/chat/chat/ai/injection.py +14 -0
- ommlds/cli/sessions/chat/chat/ai/rendering.py +70 -0
- ommlds/cli/sessions/chat/chat/ai/services.py +79 -0
- ommlds/cli/sessions/chat/chat/ai/tools.py +44 -0
- ommlds/cli/sessions/chat/chat/ai/types.py +28 -0
- ommlds/cli/sessions/chat/chat/state/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/state/configs.py +11 -0
- ommlds/cli/sessions/chat/chat/state/inject.py +36 -0
- ommlds/cli/sessions/chat/chat/state/inmemory.py +33 -0
- ommlds/cli/sessions/chat/chat/state/storage.py +52 -0
- ommlds/cli/sessions/chat/chat/state/types.py +38 -0
- ommlds/cli/sessions/chat/chat/user/__init__.py +0 -0
- ommlds/cli/sessions/chat/chat/user/configs.py +17 -0
- ommlds/cli/sessions/chat/chat/user/inject.py +62 -0
- ommlds/cli/sessions/chat/chat/user/interactive.py +31 -0
- ommlds/cli/sessions/chat/chat/user/oneshot.py +25 -0
- ommlds/cli/sessions/chat/chat/user/types.py +15 -0
- ommlds/cli/sessions/chat/configs.py +27 -0
- ommlds/cli/sessions/chat/driver.py +43 -0
- ommlds/cli/sessions/chat/inject.py +33 -65
- ommlds/cli/sessions/chat/phases/__init__.py +0 -0
- ommlds/cli/sessions/chat/phases/inject.py +27 -0
- ommlds/cli/sessions/chat/phases/injection.py +14 -0
- ommlds/cli/sessions/chat/phases/manager.py +29 -0
- ommlds/cli/sessions/chat/phases/types.py +29 -0
- ommlds/cli/sessions/chat/session.py +27 -0
- ommlds/cli/sessions/chat/tools/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/configs.py +22 -0
- ommlds/cli/sessions/chat/tools/confirmation.py +46 -0
- ommlds/cli/sessions/chat/tools/execution.py +66 -0
- ommlds/cli/sessions/chat/tools/fs/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/fs/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/fs/inject.py +35 -0
- ommlds/cli/sessions/chat/tools/inject.py +88 -0
- ommlds/cli/sessions/chat/tools/injection.py +44 -0
- ommlds/cli/sessions/chat/tools/rendering.py +58 -0
- ommlds/cli/sessions/chat/tools/todo/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/todo/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/todo/inject.py +31 -0
- ommlds/cli/sessions/chat/tools/weather/__init__.py +0 -0
- ommlds/cli/sessions/chat/tools/weather/configs.py +12 -0
- ommlds/cli/sessions/chat/tools/weather/inject.py +22 -0
- ommlds/cli/{tools/weather.py → sessions/chat/tools/weather/tools.py} +1 -1
- ommlds/cli/sessions/completion/configs.py +21 -0
- ommlds/cli/sessions/completion/inject.py +42 -0
- ommlds/cli/sessions/completion/session.py +35 -0
- ommlds/cli/sessions/embedding/configs.py +21 -0
- ommlds/cli/sessions/embedding/inject.py +42 -0
- ommlds/cli/sessions/embedding/session.py +33 -0
- ommlds/cli/sessions/inject.py +28 -11
- ommlds/cli/state/__init__.py +0 -0
- ommlds/cli/state/inject.py +28 -0
- ommlds/cli/{state.py → state/storage.py} +41 -24
- ommlds/minichain/__init__.py +84 -24
- ommlds/minichain/_marshal.py +49 -9
- ommlds/minichain/_typedvalues.py +2 -4
- ommlds/minichain/backends/catalogs/base.py +20 -1
- ommlds/minichain/backends/catalogs/simple.py +2 -2
- ommlds/minichain/backends/catalogs/strings.py +10 -8
- ommlds/minichain/backends/impls/anthropic/chat.py +65 -27
- ommlds/minichain/backends/impls/anthropic/names.py +10 -8
- ommlds/minichain/backends/impls/anthropic/protocol.py +109 -0
- ommlds/minichain/backends/impls/anthropic/stream.py +111 -43
- ommlds/minichain/backends/impls/duckduckgo/search.py +1 -1
- ommlds/minichain/backends/impls/dummy/__init__.py +0 -0
- ommlds/minichain/backends/impls/dummy/chat.py +69 -0
- ommlds/minichain/backends/impls/google/chat.py +114 -22
- ommlds/minichain/backends/impls/google/search.py +7 -2
- ommlds/minichain/backends/impls/google/stream.py +219 -0
- ommlds/minichain/backends/impls/google/tools.py +149 -0
- ommlds/minichain/backends/impls/groq/__init__.py +0 -0
- ommlds/minichain/backends/impls/groq/chat.py +75 -0
- ommlds/minichain/backends/impls/groq/names.py +48 -0
- ommlds/minichain/backends/impls/groq/protocol.py +143 -0
- ommlds/minichain/backends/impls/groq/stream.py +125 -0
- ommlds/minichain/backends/impls/llamacpp/chat.py +33 -18
- ommlds/minichain/backends/impls/llamacpp/completion.py +1 -1
- ommlds/minichain/backends/impls/llamacpp/format.py +4 -2
- ommlds/minichain/backends/impls/llamacpp/stream.py +37 -20
- ommlds/minichain/backends/impls/mistral.py +20 -5
- ommlds/minichain/backends/impls/mlx/chat.py +96 -22
- ommlds/minichain/backends/impls/ollama/__init__.py +0 -0
- ommlds/minichain/backends/impls/ollama/chat.py +199 -0
- ommlds/minichain/backends/impls/openai/chat.py +18 -8
- ommlds/minichain/backends/impls/openai/completion.py +10 -3
- ommlds/minichain/backends/impls/openai/embedding.py +10 -3
- ommlds/minichain/backends/impls/openai/format.py +131 -106
- ommlds/minichain/backends/impls/openai/names.py +31 -5
- ommlds/minichain/backends/impls/openai/stream.py +43 -25
- ommlds/minichain/backends/impls/tavily.py +66 -0
- ommlds/minichain/backends/impls/tinygrad/chat.py +23 -16
- ommlds/minichain/backends/impls/transformers/sentence.py +1 -1
- ommlds/minichain/backends/impls/transformers/tokens.py +1 -1
- ommlds/minichain/backends/impls/transformers/transformers.py +155 -34
- ommlds/minichain/backends/strings/parsing.py +1 -1
- ommlds/minichain/backends/strings/resolving.py +4 -1
- ommlds/minichain/chat/_marshal.py +16 -9
- ommlds/minichain/chat/choices/adapters.py +4 -4
- ommlds/minichain/chat/choices/services.py +1 -1
- ommlds/minichain/chat/choices/stream/__init__.py +0 -0
- ommlds/minichain/chat/choices/stream/adapters.py +35 -0
- ommlds/minichain/chat/choices/stream/joining.py +31 -0
- ommlds/minichain/chat/choices/stream/services.py +45 -0
- ommlds/minichain/chat/choices/stream/types.py +43 -0
- ommlds/minichain/chat/choices/types.py +2 -2
- ommlds/minichain/chat/history.py +3 -3
- ommlds/minichain/chat/messages.py +55 -19
- ommlds/minichain/chat/services.py +3 -3
- ommlds/minichain/chat/stream/_marshal.py +16 -0
- ommlds/minichain/chat/stream/joining.py +85 -0
- ommlds/minichain/chat/stream/services.py +15 -21
- ommlds/minichain/chat/stream/types.py +32 -19
- ommlds/minichain/chat/tools/execution.py +8 -7
- ommlds/minichain/chat/tools/ids.py +9 -15
- ommlds/minichain/chat/tools/parsing.py +17 -26
- ommlds/minichain/chat/transforms/base.py +29 -38
- ommlds/minichain/chat/transforms/metadata.py +30 -4
- ommlds/minichain/chat/transforms/services.py +9 -11
- ommlds/minichain/content/_marshal.py +44 -20
- ommlds/minichain/content/json.py +13 -0
- ommlds/minichain/content/materialize.py +14 -21
- ommlds/minichain/content/prepare.py +4 -0
- ommlds/minichain/content/transforms/interleave.py +1 -1
- ommlds/minichain/content/transforms/squeeze.py +1 -1
- ommlds/minichain/content/transforms/stringify.py +1 -1
- ommlds/minichain/json.py +20 -0
- ommlds/minichain/lib/code/__init__.py +0 -0
- ommlds/minichain/lib/code/prompts.py +6 -0
- ommlds/minichain/lib/fs/binfiles.py +108 -0
- ommlds/minichain/lib/fs/context.py +126 -0
- ommlds/minichain/lib/fs/errors.py +101 -0
- ommlds/minichain/lib/fs/suggestions.py +36 -0
- ommlds/minichain/lib/fs/tools/__init__.py +0 -0
- ommlds/minichain/lib/fs/tools/edit.py +104 -0
- ommlds/minichain/lib/fs/tools/ls.py +38 -0
- ommlds/minichain/lib/fs/tools/read.py +115 -0
- ommlds/minichain/lib/fs/tools/recursivels/__init__.py +0 -0
- ommlds/minichain/lib/fs/tools/recursivels/execution.py +40 -0
- ommlds/minichain/lib/todo/__init__.py +0 -0
- ommlds/minichain/lib/todo/context.py +54 -0
- ommlds/minichain/lib/todo/tools/__init__.py +0 -0
- ommlds/minichain/lib/todo/tools/read.py +44 -0
- ommlds/minichain/lib/todo/tools/write.py +335 -0
- ommlds/minichain/lib/todo/types.py +60 -0
- ommlds/minichain/llms/_marshal.py +25 -17
- ommlds/minichain/llms/types.py +4 -0
- ommlds/minichain/registries/globals.py +18 -4
- ommlds/minichain/resources.py +66 -43
- ommlds/minichain/search.py +1 -1
- ommlds/minichain/services/_marshal.py +46 -39
- ommlds/minichain/services/facades.py +3 -3
- ommlds/minichain/services/services.py +1 -1
- ommlds/minichain/standard.py +8 -0
- ommlds/minichain/stream/services.py +152 -38
- ommlds/minichain/stream/wrap.py +22 -24
- ommlds/minichain/tools/_marshal.py +1 -1
- ommlds/minichain/tools/execution/catalog.py +2 -1
- ommlds/minichain/tools/execution/context.py +34 -14
- ommlds/minichain/tools/execution/errors.py +15 -0
- ommlds/minichain/tools/execution/executors.py +8 -3
- ommlds/minichain/tools/execution/reflect.py +40 -5
- ommlds/minichain/tools/fns.py +46 -9
- ommlds/minichain/tools/jsonschema.py +14 -5
- ommlds/minichain/tools/reflect.py +54 -18
- ommlds/minichain/tools/types.py +33 -1
- ommlds/minichain/utils.py +27 -0
- ommlds/minichain/vectors/_marshal.py +11 -10
- ommlds/nanochat/LICENSE +21 -0
- ommlds/nanochat/__init__.py +0 -0
- ommlds/nanochat/rustbpe/LICENSE +21 -0
- ommlds/nanochat/tokenizers.py +406 -0
- ommlds/server/server.py +3 -3
- ommlds/specs/__init__.py +0 -0
- ommlds/specs/mcp/__init__.py +0 -0
- ommlds/specs/mcp/_marshal.py +23 -0
- ommlds/specs/mcp/protocol.py +266 -0
- ommlds/tools/git.py +27 -10
- ommlds/tools/ocr.py +8 -9
- ommlds/wiki/analyze.py +2 -2
- ommlds/wiki/text/mfh.py +1 -5
- ommlds/wiki/text/wtp.py +1 -3
- ommlds/wiki/utils/xml.py +5 -5
- {ommlds-0.0.0.dev440.dist-info → ommlds-0.0.0.dev480.dist-info}/METADATA +24 -21
- ommlds-0.0.0.dev480.dist-info/RECORD +427 -0
- ommlds/cli/backends/standard.py +0 -20
- ommlds/cli/sessions/chat/base.py +0 -42
- ommlds/cli/sessions/chat/interactive.py +0 -73
- ommlds/cli/sessions/chat/printing.py +0 -96
- ommlds/cli/sessions/chat/prompt.py +0 -143
- ommlds/cli/sessions/chat/state.py +0 -109
- ommlds/cli/sessions/chat/tools.py +0 -91
- ommlds/cli/sessions/completion/completion.py +0 -44
- ommlds/cli/sessions/embedding/embedding.py +0 -42
- ommlds/cli/tools/config.py +0 -13
- ommlds/cli/tools/inject.py +0 -64
- ommlds/minichain/chat/stream/adapters.py +0 -69
- ommlds/minichain/lib/fs/ls/execution.py +0 -32
- ommlds-0.0.0.dev440.dist-info/RECORD +0 -303
- /ommlds/{cli/tools → backends/google}/__init__.py +0 -0
- /ommlds/{minichain/lib/fs/ls → backends/groq}/__init__.py +0 -0
- /ommlds/{huggingface.py → backends/huggingface.py} +0 -0
- /ommlds/minichain/lib/fs/{ls → tools/recursivels}/rendering.py +0 -0
- /ommlds/minichain/lib/fs/{ls → tools/recursivels}/running.py +0 -0
- {ommlds-0.0.0.dev440.dist-info → ommlds-0.0.0.dev480.dist-info}/WHEEL +0 -0
- {ommlds-0.0.0.dev440.dist-info → ommlds-0.0.0.dev480.dist-info}/entry_points.txt +0 -0
- {ommlds-0.0.0.dev440.dist-info → ommlds-0.0.0.dev480.dist-info}/licenses/LICENSE +0 -0
- {ommlds-0.0.0.dev440.dist-info → ommlds-0.0.0.dev480.dist-info}/top_level.txt +0 -0
ommlds/minichain/resources.py
CHANGED
|
@@ -3,7 +3,6 @@ TODO:
|
|
|
3
3
|
- unify with omlish.sql.api.resources -> omlish.resources
|
|
4
4
|
"""
|
|
5
5
|
import contextlib
|
|
6
|
-
import threading
|
|
7
6
|
import typing as ta
|
|
8
7
|
|
|
9
8
|
from omlish import check
|
|
@@ -32,6 +31,7 @@ class ResourcesRefNotRegisteredError(Exception):
|
|
|
32
31
|
pass
|
|
33
32
|
|
|
34
33
|
|
|
34
|
+
@ta.final
|
|
35
35
|
class Resources(lang.Final, lang.NotPicklable):
|
|
36
36
|
def __init__(
|
|
37
37
|
self,
|
|
@@ -43,26 +43,25 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
43
43
|
|
|
44
44
|
self._no_autoclose = no_autoclose
|
|
45
45
|
|
|
46
|
-
self._lock = threading.RLock()
|
|
47
|
-
|
|
48
46
|
self._closed = False
|
|
49
47
|
|
|
50
48
|
self._refs: ta.MutableSet[ResourcesRef] = col.IdentitySet()
|
|
51
49
|
|
|
52
|
-
self.
|
|
53
|
-
self._es.__enter__()
|
|
50
|
+
self._aes = contextlib.AsyncExitStack()
|
|
54
51
|
|
|
55
52
|
if init_ref is not None:
|
|
56
53
|
self.add_ref(init_ref)
|
|
57
54
|
|
|
55
|
+
async def init(self) -> None:
|
|
56
|
+
await self._aes.__aenter__()
|
|
57
|
+
|
|
58
58
|
@property
|
|
59
59
|
def autoclose(self) -> bool:
|
|
60
60
|
return not self._no_autoclose
|
|
61
61
|
|
|
62
62
|
@property
|
|
63
63
|
def num_refs(self) -> int:
|
|
64
|
-
|
|
65
|
-
return len(self._refs)
|
|
64
|
+
return len(self._refs)
|
|
66
65
|
|
|
67
66
|
@property
|
|
68
67
|
def closed(self) -> bool:
|
|
@@ -77,15 +76,16 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
77
76
|
pass
|
|
78
77
|
|
|
79
78
|
@classmethod
|
|
80
|
-
def new(cls, **kwargs: ta.Any) -> ta.
|
|
81
|
-
@contextlib.
|
|
82
|
-
def inner():
|
|
79
|
+
def new(cls, **kwargs: ta.Any) -> ta.AsyncContextManager['Resources']:
|
|
80
|
+
@contextlib.asynccontextmanager
|
|
81
|
+
async def inner():
|
|
83
82
|
init_ref = Resources._InitRef()
|
|
84
83
|
res = Resources(init_ref=init_ref, **kwargs)
|
|
84
|
+
await res.init()
|
|
85
85
|
try:
|
|
86
86
|
yield res
|
|
87
87
|
finally:
|
|
88
|
-
res.remove_ref(init_ref)
|
|
88
|
+
await res.remove_ref(init_ref)
|
|
89
89
|
|
|
90
90
|
return inner()
|
|
91
91
|
|
|
@@ -93,30 +93,30 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
93
93
|
|
|
94
94
|
def add_ref(self, ref: ResourcesRef) -> None:
|
|
95
95
|
check.isinstance(ref, ResourcesRef)
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
self._refs.add(ref)
|
|
96
|
+
check.state(not self._closed)
|
|
97
|
+
self._refs.add(ref)
|
|
99
98
|
|
|
100
99
|
def has_ref(self, ref: ResourcesRef) -> bool:
|
|
101
|
-
|
|
102
|
-
return ref in self._refs
|
|
100
|
+
return ref in self._refs
|
|
103
101
|
|
|
104
|
-
def remove_ref(self, ref: ResourcesRef) -> None:
|
|
102
|
+
async def remove_ref(self, ref: ResourcesRef) -> None:
|
|
105
103
|
check.isinstance(ref, ResourcesRef)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self.close()
|
|
104
|
+
try:
|
|
105
|
+
self._refs.remove(ref)
|
|
106
|
+
except KeyError:
|
|
107
|
+
raise ResourcesRefNotRegisteredError(ref) from None
|
|
108
|
+
if not self._no_autoclose and not self._refs:
|
|
109
|
+
await self.aclose()
|
|
113
110
|
|
|
114
111
|
#
|
|
115
112
|
|
|
116
113
|
def enter_context(self, cm: ta.ContextManager[T]) -> T:
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
check.state(not self._closed)
|
|
115
|
+
return self._aes.enter_context(cm)
|
|
116
|
+
|
|
117
|
+
async def enter_async_context(self, cm: ta.AsyncContextManager[T]) -> T:
|
|
118
|
+
check.state(not self._closed)
|
|
119
|
+
return await self._aes.enter_async_context(cm)
|
|
120
120
|
|
|
121
121
|
#
|
|
122
122
|
|
|
@@ -125,12 +125,11 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
125
125
|
|
|
126
126
|
#
|
|
127
127
|
|
|
128
|
-
def
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
self._closed = True
|
|
128
|
+
async def aclose(self) -> None:
|
|
129
|
+
try:
|
|
130
|
+
await self._aes.__aexit__(None, None, None)
|
|
131
|
+
finally:
|
|
132
|
+
self._closed = True
|
|
134
133
|
|
|
135
134
|
def __del__(self) -> None:
|
|
136
135
|
if not self._closed:
|
|
@@ -147,24 +146,48 @@ class Resources(lang.Final, lang.NotPicklable):
|
|
|
147
146
|
##
|
|
148
147
|
|
|
149
148
|
|
|
149
|
+
@ta.final
|
|
150
150
|
class ResourceManaged(ResourcesRef, lang.Final, lang.NotPicklable, ta.Generic[T]):
|
|
151
|
+
"""
|
|
152
|
+
A class to 'handoff' a ref to a `Resources`, allowing the `Resources` to temporarily survive being passed from
|
|
153
|
+
instantiation within a callee to being `__aenter__`'d in the caller.
|
|
154
|
+
|
|
155
|
+
The ref to the `Resources` is allocated in the ctor, so the contract is that an instance of this must be immediately
|
|
156
|
+
`__aenter__`'d before doing anything else with the return value of the call. Failure to do so leaks the `Resources`.
|
|
157
|
+
"""
|
|
158
|
+
|
|
151
159
|
def __init__(self, v: T, resources: Resources) -> None:
|
|
152
160
|
super().__init__()
|
|
153
161
|
|
|
154
|
-
self.
|
|
162
|
+
self.__v = v
|
|
155
163
|
self.__resources = resources
|
|
156
164
|
|
|
157
165
|
resources.add_ref(self)
|
|
158
166
|
|
|
167
|
+
__state: ta.Literal['new', 'entered', 'exited'] = 'new'
|
|
168
|
+
|
|
159
169
|
def __repr__(self) -> str:
|
|
160
|
-
return f'{self.__class__.__name__}<{self.
|
|
170
|
+
return f'{self.__class__.__name__}<{self.__v!r}, {self.__state}>'
|
|
161
171
|
|
|
162
|
-
def
|
|
163
|
-
|
|
172
|
+
async def __aenter__(self) -> T:
|
|
173
|
+
check.state(self.__state == 'new')
|
|
174
|
+
self.__state = 'entered'
|
|
175
|
+
return self.__v
|
|
164
176
|
|
|
165
|
-
def
|
|
166
|
-
|
|
177
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
178
|
+
check.state(self.__state == 'entered')
|
|
179
|
+
self.__state = 'exited'
|
|
180
|
+
await self.__resources.remove_ref(self)
|
|
167
181
|
|
|
182
|
+
def __del__(self) -> None:
|
|
183
|
+
if self.__state != 'exited':
|
|
184
|
+
log.error(
|
|
185
|
+
f'{__package__}.{self.__class__.__name__}.__del__: ' # noqa
|
|
186
|
+
f'%r deleted without being entered and exited! '
|
|
187
|
+
f'resources: %s',
|
|
188
|
+
repr(self),
|
|
189
|
+
repr(self.__resources),
|
|
190
|
+
)
|
|
168
191
|
|
|
169
192
|
##
|
|
170
193
|
|
|
@@ -175,11 +198,11 @@ class ResourcesOption(Option, lang.Abstract):
|
|
|
175
198
|
|
|
176
199
|
class UseResources(tv.UniqueScalarTypedValue[Resources], ResourcesOption, lang.Final):
|
|
177
200
|
@classmethod
|
|
178
|
-
@contextlib.
|
|
179
|
-
def or_new(cls, options: ta.Sequence[Option]) -> ta.
|
|
201
|
+
@contextlib.asynccontextmanager
|
|
202
|
+
async def or_new(cls, options: ta.Sequence[Option]) -> ta.AsyncGenerator[Resources]:
|
|
180
203
|
if (ur := tv.as_collection(options).get(UseResources)) is not None:
|
|
181
|
-
with ResourceManaged(ur.v, ur.v) as rs:
|
|
204
|
+
async with ResourceManaged(ur.v, ur.v) as rs:
|
|
182
205
|
yield rs
|
|
183
206
|
else:
|
|
184
|
-
with Resources.new() as rs:
|
|
207
|
+
async with Resources.new() as rs:
|
|
185
208
|
yield rs
|
ommlds/minichain/search.py
CHANGED
|
@@ -40,14 +40,14 @@ class _RequestResponseMarshaler(msh.Marshaler):
|
|
|
40
40
|
def marshal(self, ctx: msh.MarshalContext, o: ta.Any) -> msh.Value:
|
|
41
41
|
tv_types_set = o._typed_values_info().tv_types_set # noqa # FIXME
|
|
42
42
|
tv_ta = tv.TypedValues[ta.Union[*tv_types_set]] # type: ignore
|
|
43
|
-
tv_m = ctx.
|
|
43
|
+
tv_m = ctx.marshal_factory_context.make_marshaler(tv_ta) # FIXME:
|
|
44
44
|
tv_v = check.isinstance(tv_m.marshal(ctx, o._typed_values), ta.Sequence) # noqa
|
|
45
45
|
|
|
46
46
|
if self.v_m is None:
|
|
47
47
|
orty: rfl.Generic = check.isinstance(rfl.type_(rfl.get_orig_class(o)), rfl.Generic)
|
|
48
48
|
check.state(orty.cls in (Request, Response))
|
|
49
49
|
v_rty, tv_rty = orty.args
|
|
50
|
-
v_v = ctx.
|
|
50
|
+
v_v = ctx.marshal_factory_context.make_marshaler(v_rty).marshal(ctx, o.v) # FIXME
|
|
51
51
|
else:
|
|
52
52
|
v_v = self.v_m.marshal(ctx, o.v)
|
|
53
53
|
|
|
@@ -57,26 +57,30 @@ class _RequestResponseMarshaler(msh.Marshaler):
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
|
|
60
|
-
class _RequestResponseMarshalerFactory(msh.
|
|
61
|
-
def
|
|
62
|
-
|
|
60
|
+
class _RequestResponseMarshalerFactory(msh.MarshalerFactory):
|
|
61
|
+
def make_marshaler(self, ctx: msh.MarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Marshaler] | None:
|
|
62
|
+
if not _is_rr_rty(rty):
|
|
63
|
+
return None
|
|
63
64
|
|
|
64
|
-
def fn(self, ctx: msh.MarshalContext, rty: rfl.Type) -> msh.Marshaler:
|
|
65
65
|
if isinstance(rty, type):
|
|
66
66
|
rty = rfl.type_(rfl.get_orig_class(rty))
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
v_m =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
67
|
+
|
|
68
|
+
def inner() -> msh.Marshaler:
|
|
69
|
+
if isinstance(rty, rfl.Generic):
|
|
70
|
+
v_rty, tv_rty = rty.args
|
|
71
|
+
else:
|
|
72
|
+
# FIXME: ...
|
|
73
|
+
raise TypeError(rty)
|
|
74
|
+
v_m: msh.Marshaler | None = None
|
|
75
|
+
if not isinstance(v_rty, ta.TypeVar):
|
|
76
|
+
v_m = ctx.make_marshaler(v_rty)
|
|
77
|
+
return _RequestResponseMarshaler(
|
|
78
|
+
rty,
|
|
79
|
+
_get_tv_fld(rty),
|
|
80
|
+
v_m,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return inner
|
|
80
84
|
|
|
81
85
|
|
|
82
86
|
#
|
|
@@ -108,33 +112,36 @@ class _RequestResponseUnmarshaler(msh.Unmarshaler):
|
|
|
108
112
|
return cty(v, tvs) # type: ignore
|
|
109
113
|
|
|
110
114
|
|
|
111
|
-
class _RequestResponseUnmarshalerFactory(msh.
|
|
112
|
-
def
|
|
113
|
-
|
|
115
|
+
class _RequestResponseUnmarshalerFactory(msh.UnmarshalerFactory):
|
|
116
|
+
def make_unmarshaler(self, ctx: msh.UnmarshalFactoryContext, rty: rfl.Type) -> ta.Callable[[], msh.Unmarshaler] | None: # noqa
|
|
117
|
+
if not _is_rr_rty(rty):
|
|
118
|
+
return None
|
|
114
119
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
120
|
+
def inner() -> msh.Unmarshaler:
|
|
121
|
+
if isinstance(rty, rfl.Generic):
|
|
122
|
+
v_rty, tv_rty = rty.args
|
|
123
|
+
else:
|
|
124
|
+
# FIXME: ...
|
|
125
|
+
raise TypeError(rty)
|
|
126
|
+
tv_types_set = check.isinstance(tv_rty, rfl.Union).args
|
|
127
|
+
tv_ta = tv.TypedValues[ta.Union[*tv_types_set]] # type: ignore
|
|
128
|
+
tv_u = ctx.make_unmarshaler(tv_ta)
|
|
129
|
+
v_u = ctx.make_unmarshaler(v_rty)
|
|
130
|
+
return _RequestResponseUnmarshaler(
|
|
131
|
+
rty,
|
|
132
|
+
_get_tv_fld(rty),
|
|
133
|
+
v_u,
|
|
134
|
+
tv_u,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
return inner
|
|
131
138
|
|
|
132
139
|
|
|
133
140
|
##
|
|
134
141
|
|
|
135
142
|
|
|
136
143
|
@lang.static_init
|
|
137
|
-
def
|
|
144
|
+
def _install_standard_marshaling() -> None:
|
|
138
145
|
msh.install_standard_factories(
|
|
139
146
|
_RequestResponseMarshalerFactory(),
|
|
140
147
|
_RequestResponseUnmarshalerFactory(),
|
|
@@ -44,15 +44,15 @@ class ServiceFacade(
|
|
|
44
44
|
],
|
|
45
45
|
]
|
|
46
46
|
|
|
47
|
-
def invoke(self, request: Request[RequestV, OptionT]) -> Response[ResponseV, OutputT]:
|
|
47
|
+
def invoke(self, request: Request[RequestV, OptionT]) -> ta.Awaitable[Response[ResponseV, OutputT]]:
|
|
48
48
|
return self.service.invoke(request)
|
|
49
49
|
|
|
50
50
|
@ta.overload
|
|
51
|
-
def __call__(self, request: Request[RequestV, OptionT]) -> Response[ResponseV, OutputT]:
|
|
51
|
+
def __call__(self, request: Request[RequestV, OptionT]) -> ta.Awaitable[Response[ResponseV, OutputT]]:
|
|
52
52
|
...
|
|
53
53
|
|
|
54
54
|
@ta.overload
|
|
55
|
-
def __call__(self, v: RequestV, *options: OptionT) -> Response[ResponseV, OutputT]:
|
|
55
|
+
def __call__(self, v: RequestV, *options: OptionT) -> ta.Awaitable[Response[ResponseV, OutputT]]:
|
|
56
56
|
...
|
|
57
57
|
|
|
58
58
|
def __call__(self, o, *args):
|
|
@@ -11,4 +11,4 @@ from .responses import ResponseT_co
|
|
|
11
11
|
|
|
12
12
|
@ta.runtime_checkable
|
|
13
13
|
class Service(lang.ProtocolForbiddenAsBaseClass, ta.Protocol[RequestT_contra, ResponseT_co]):
|
|
14
|
-
def invoke(self, request: RequestT_contra) -> ResponseT_co: ...
|
|
14
|
+
def invoke(self, request: RequestT_contra) -> ta.Awaitable[ResponseT_co]: ...
|
ommlds/minichain/standard.py
CHANGED
|
@@ -25,6 +25,14 @@ class Device(tv.UniqueScalarTypedValue[ta.Any], Config):
|
|
|
25
25
|
##
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
# TODO: ApiEndpointPath, ApiEndpointUrl, ApiBaseUrl, ...
|
|
29
|
+
class ApiUrl(tv.UniqueScalarTypedValue[str], Config):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
##
|
|
34
|
+
|
|
35
|
+
|
|
28
36
|
@dc.dataclass(frozen=True)
|
|
29
37
|
class SecretConfig(Config, lang.Abstract):
|
|
30
38
|
v: sec.SecretRefOrStr = dc.field() | sec.secret_field
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import abc
|
|
2
|
+
import itertools
|
|
3
|
+
import types
|
|
2
4
|
import typing as ta
|
|
3
5
|
|
|
4
6
|
from omlish import check
|
|
@@ -14,6 +16,8 @@ from ..types import Output
|
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
V = ta.TypeVar('V')
|
|
19
|
+
V2 = ta.TypeVar('V2')
|
|
20
|
+
|
|
17
21
|
OutputT = ta.TypeVar('OutputT', bound=Output)
|
|
18
22
|
StreamOutputT = ta.TypeVar('StreamOutputT', bound=Output)
|
|
19
23
|
|
|
@@ -31,44 +35,155 @@ StreamOptions: ta.TypeAlias = StreamOption | ResourcesOption
|
|
|
31
35
|
##
|
|
32
36
|
|
|
33
37
|
|
|
34
|
-
class
|
|
35
|
-
|
|
38
|
+
class StreamResponseSink(lang.Abstract, ta.Generic[V]):
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def emit(self, value: V) -> ta.Awaitable[None]:
|
|
41
|
+
raise NotImplementedError
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class StreamResponseIterator(
|
|
45
|
+
ta.AsyncContextManager['StreamResponseIterator[V, OutputT]'],
|
|
46
|
+
lang.Abstract,
|
|
47
|
+
ta.Generic[V, OutputT],
|
|
48
|
+
):
|
|
49
|
+
@property
|
|
50
|
+
@abc.abstractmethod
|
|
51
|
+
def outputs(self) -> tv.TypedValues[OutputT]:
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
|
|
54
|
+
@ta.final
|
|
55
|
+
def __aiter__(self) -> ta.AsyncIterator[V]:
|
|
56
|
+
return self
|
|
57
|
+
|
|
58
|
+
@abc.abstractmethod
|
|
59
|
+
def __anext__(self) -> ta.Awaitable[V]:
|
|
60
|
+
raise NotImplementedError
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
##
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class StreamServiceCancelledError(BaseException):
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class StreamServiceNotAwaitedError(Exception):
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class _StreamServiceResponse(StreamResponseIterator[V, OutputT]):
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
fn: ta.Callable[[StreamResponseSink[V]], ta.Awaitable[ta.Sequence[OutputT] | None]],
|
|
78
|
+
) -> None:
|
|
36
79
|
super().__init__()
|
|
37
80
|
|
|
38
|
-
self.
|
|
39
|
-
self._is_done = False
|
|
81
|
+
self._fn = fn
|
|
40
82
|
|
|
41
|
-
|
|
42
|
-
|
|
83
|
+
@ta.final
|
|
84
|
+
class _Emit(ta.Generic[V2]):
|
|
85
|
+
def __init__(self, ssr: '_StreamServiceResponse', value: V2) -> None:
|
|
86
|
+
self.ssr, self.value = ssr, value
|
|
43
87
|
|
|
44
|
-
|
|
88
|
+
done: bool = False
|
|
45
89
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
90
|
+
def __await__(self) -> ta.Generator['_StreamServiceResponse._Emit[V2]']:
|
|
91
|
+
if not self.done:
|
|
92
|
+
yield self
|
|
93
|
+
if not self.done:
|
|
94
|
+
raise StreamServiceNotAwaitedError
|
|
95
|
+
|
|
96
|
+
@ta.final
|
|
97
|
+
class _Sink(StreamResponseSink[V2]):
|
|
98
|
+
def __init__(self, ssr: '_StreamServiceResponse') -> None:
|
|
99
|
+
super().__init__()
|
|
100
|
+
|
|
101
|
+
self._ssr = ssr
|
|
102
|
+
|
|
103
|
+
def emit(self, item: V2) -> ta.Awaitable[None]:
|
|
104
|
+
return _StreamServiceResponse._Emit(self._ssr, item)
|
|
105
|
+
|
|
106
|
+
_state: ta.Literal['new', 'running', 'closed'] = 'new'
|
|
107
|
+
_sink: _Sink[V]
|
|
108
|
+
_a: ta.Any
|
|
109
|
+
_cr: ta.Any
|
|
110
|
+
|
|
111
|
+
async def __aenter__(self) -> ta.Self:
|
|
112
|
+
check.state(self._state == 'new')
|
|
113
|
+
self._state = 'running'
|
|
114
|
+
self._sink = _StreamServiceResponse._Sink(self)
|
|
115
|
+
self._cr = self._fn(self._sink)
|
|
116
|
+
self._a = self._cr.__await__()
|
|
117
|
+
self._g = iter(self._a)
|
|
118
|
+
return self
|
|
119
|
+
|
|
120
|
+
@types.coroutine
|
|
121
|
+
def _aexit(self, exc_type, exc_val, exc_tb):
|
|
122
|
+
old_state = self._state
|
|
123
|
+
self._state = 'closed'
|
|
124
|
+
if old_state != 'running':
|
|
125
|
+
return
|
|
126
|
+
if self._cr.cr_running or self._cr.cr_suspended:
|
|
127
|
+
cex = StreamServiceCancelledError()
|
|
128
|
+
i = None
|
|
129
|
+
for n in itertools.count():
|
|
130
|
+
try:
|
|
131
|
+
if not n:
|
|
132
|
+
x = self._g.throw(cex)
|
|
133
|
+
else:
|
|
134
|
+
x = self._g.send(i)
|
|
135
|
+
except StreamServiceCancelledError as cex2:
|
|
136
|
+
if cex2 is cex:
|
|
137
|
+
break
|
|
138
|
+
raise
|
|
139
|
+
i = yield x
|
|
140
|
+
if self._cr.cr_running:
|
|
141
|
+
raise RuntimeError(f'Coroutine {self._cr!r} not terminated')
|
|
142
|
+
if self._g is not self._a:
|
|
143
|
+
self._g.close()
|
|
144
|
+
self._a.close()
|
|
145
|
+
self._cr.close()
|
|
146
|
+
|
|
147
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
148
|
+
return await self._aexit(exc_type, exc_val, exc_tb)
|
|
149
|
+
|
|
150
|
+
_outputs: tv.TypedValues[OutputT]
|
|
49
151
|
|
|
50
152
|
@property
|
|
51
153
|
def outputs(self) -> tv.TypedValues[OutputT]:
|
|
52
154
|
return self._outputs
|
|
53
155
|
|
|
54
|
-
|
|
55
|
-
|
|
156
|
+
@types.coroutine
|
|
157
|
+
def _anext(self):
|
|
158
|
+
check.state(self._state == 'running')
|
|
159
|
+
i = None
|
|
160
|
+
while True:
|
|
161
|
+
try:
|
|
162
|
+
x = self._g.send(i)
|
|
163
|
+
except StopIteration as e:
|
|
164
|
+
if e.value is not None:
|
|
165
|
+
self._outputs = tv.TypedValues(*check.isinstance(e.value, ta.Sequence))
|
|
166
|
+
else:
|
|
167
|
+
self._outputs = tv.TypedValues()
|
|
168
|
+
raise StopAsyncIteration from None
|
|
169
|
+
|
|
170
|
+
if isinstance(x, _StreamServiceResponse._Emit) and x.ssr is self:
|
|
171
|
+
check.state(not x.done)
|
|
172
|
+
x.done = True
|
|
173
|
+
return x.value
|
|
56
174
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
else:
|
|
65
|
-
self._outputs = tv.TypedValues()
|
|
66
|
-
raise
|
|
175
|
+
i = yield x
|
|
176
|
+
|
|
177
|
+
async def __anext__(self) -> V:
|
|
178
|
+
return await self._anext()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
##
|
|
67
182
|
|
|
68
183
|
|
|
69
184
|
StreamResponse: ta.TypeAlias = Response[
|
|
70
185
|
ResourceManaged[
|
|
71
|
-
|
|
186
|
+
StreamResponseIterator[
|
|
72
187
|
V,
|
|
73
188
|
OutputT,
|
|
74
189
|
],
|
|
@@ -77,20 +192,19 @@ StreamResponse: ta.TypeAlias = Response[
|
|
|
77
192
|
]
|
|
78
193
|
|
|
79
194
|
|
|
80
|
-
def new_stream_response(
|
|
195
|
+
async def new_stream_response(
|
|
81
196
|
rs: Resources,
|
|
82
|
-
|
|
197
|
+
fn: ta.Callable[[StreamResponseSink[V]], ta.Awaitable[ta.Sequence[OutputT] | None]],
|
|
83
198
|
outputs: ta.Sequence[StreamOutputT] | None = None,
|
|
84
199
|
) -> StreamResponse[V, OutputT, StreamOutputT]:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
)
|
|
200
|
+
ssr = _StreamServiceResponse(fn)
|
|
201
|
+
|
|
202
|
+
v = rs.new_managed(await rs.enter_async_context(ssr))
|
|
203
|
+
try:
|
|
204
|
+
return StreamResponse(v, outputs or [])
|
|
205
|
+
except BaseException: # noqa
|
|
206
|
+
# The StreamResponse ctor can raise - for example in `_tv_field_coercer` - in which case we need to clean up the
|
|
207
|
+
# resources ref we have already allocated before reraising.
|
|
208
|
+
async with v:
|
|
209
|
+
pass
|
|
210
|
+
raise
|
ommlds/minichain/stream/wrap.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# ruff: noqa: UP028
|
|
2
2
|
import typing as ta
|
|
3
3
|
|
|
4
|
-
from ..resources import
|
|
4
|
+
from ..resources import UseResources
|
|
5
5
|
from ..services import Request
|
|
6
6
|
from ..services import Service
|
|
7
7
|
from ..types import Output
|
|
8
|
-
from .services import ResponseGenerator
|
|
9
8
|
from .services import StreamResponse
|
|
9
|
+
from .services import StreamResponseSink
|
|
10
10
|
from .services import new_stream_response
|
|
11
11
|
|
|
12
12
|
|
|
@@ -29,36 +29,34 @@ class WrappedStreamService(ta.Generic[StreamRequestT, V, OutputT, StreamOutputT]
|
|
|
29
29
|
|
|
30
30
|
#
|
|
31
31
|
|
|
32
|
-
def _process_request(self, request: StreamRequestT) -> StreamRequestT:
|
|
32
|
+
async def _process_request(self, request: StreamRequestT) -> StreamRequestT:
|
|
33
33
|
return request
|
|
34
34
|
|
|
35
|
-
def _process_stream_outputs(self, outputs: ta.Sequence[StreamOutputT]) -> ta.Sequence[StreamOutputT]:
|
|
35
|
+
async def _process_stream_outputs(self, outputs: ta.Sequence[StreamOutputT]) -> ta.Sequence[StreamOutputT]:
|
|
36
36
|
return outputs
|
|
37
37
|
|
|
38
|
-
def
|
|
39
|
-
return
|
|
38
|
+
async def _process_value(self, v: V) -> ta.Iterable[V]:
|
|
39
|
+
return [v]
|
|
40
40
|
|
|
41
|
-
def _process_outputs(self, outputs: ta.Sequence[OutputT]) -> ta.Sequence[OutputT]:
|
|
41
|
+
async def _process_outputs(self, outputs: ta.Sequence[OutputT]) -> ta.Sequence[OutputT]:
|
|
42
42
|
return outputs
|
|
43
43
|
|
|
44
44
|
#
|
|
45
45
|
|
|
46
|
-
def invoke(self, request: StreamRequestT) -> StreamResponse[V, OutputT, StreamOutputT]:
|
|
47
|
-
with
|
|
48
|
-
|
|
49
|
-
in_vs
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
return new_stream_response(
|
|
46
|
+
async def invoke(self, request: StreamRequestT) -> StreamResponse[V, OutputT, StreamOutputT]:
|
|
47
|
+
async with UseResources.or_new(request.options) as rs: # noqa
|
|
48
|
+
in_resp = await self._inner.invoke(await self._process_request(request))
|
|
49
|
+
in_vs = await rs.enter_async_context(in_resp.v)
|
|
50
|
+
|
|
51
|
+
async def inner(sink: StreamResponseSink[V]) -> ta.Sequence[OutputT] | None:
|
|
52
|
+
async for in_v in in_vs:
|
|
53
|
+
for out_v in (await self._process_value(in_v)):
|
|
54
|
+
await sink.emit(out_v)
|
|
55
|
+
|
|
56
|
+
return await self._process_outputs(in_vs.outputs)
|
|
57
|
+
|
|
58
|
+
return await new_stream_response(
|
|
61
59
|
rs,
|
|
62
|
-
|
|
63
|
-
self._process_stream_outputs(
|
|
60
|
+
inner,
|
|
61
|
+
await self._process_stream_outputs(in_resp.outputs),
|
|
64
62
|
)
|