15
15
16
16
import asyncio
17
17
from asyncio import AbstractEventLoop
18
+ from concurrent .futures import Future
18
19
from threading import Thread
19
20
from typing import Any , Callable , Coroutine , Mapping , Optional , Union
20
21
@@ -86,6 +87,103 @@ def close(self):
86
87
coro = self .__async_client .close ()
87
88
asyncio .run_coroutine_threadsafe (coro , self .__loop ).result ()
88
89
90
+ def _load_tool_future (
91
+ self ,
92
+ name : str ,
93
+ auth_token_getters : dict [str , Callable [[], str ]] = {},
94
+ bound_params : Mapping [str , Union [Callable [[], Any ], Any ]] = {},
95
+ ) -> Future [ToolboxSyncTool ]:
96
+ """
97
+ Asynchronously initiates the loading of a specific tool from the Toolbox service.
98
+
99
+ This method schedules the tool loading operation on a background event loop
100
+ and immediately returns a `concurrent.futures.Future`. This allows other
101
+ operations to proceed while the tool is being loaded. To get the actual
102
+ `ToolboxSyncTool` instance, call `.result()` on the returned future, which
103
+ will block until the tool is available or an error occurs.
104
+
105
+ Args:
106
+ name: The unique name or identifier of the tool to load.
107
+ auth_token_getters: A mapping of authentication service names to
108
+ callables that return the corresponding authentication token.
109
+ bound_params: A mapping of parameter names to bind to specific values or
110
+ callables that are called to produce values as needed.
111
+
112
+ Returns:
113
+ A `concurrent.futures.Future` that, upon successful completion, will
114
+ yield a `ToolboxSyncTool` instance representing the loaded tool.
115
+
116
+ Raises:
117
+ ValueError: If the background event loop or thread (required for asynchronous
118
+ operations) is not running or properly initialized.
119
+
120
+ """
121
+
122
+ async def async_worker () -> ToolboxSyncTool :
123
+ if not self .__loop or not self .__thread :
124
+ raise ValueError ("Background loop or thread cannot be None." )
125
+ async_tool = await self .__async_client .load_tool (
126
+ name , auth_token_getters , bound_params
127
+ )
128
+ return ToolboxSyncTool (async_tool , self .__loop , self .__thread )
129
+
130
+ if not self .__loop or not self .__thread :
131
+ raise ValueError ("Background loop or thread cannot be None." )
132
+ return asyncio .run_coroutine_threadsafe (async_worker (), self .__loop )
133
+
134
+ def _load_toolset_future (
135
+ self ,
136
+ name : Optional [str ] = None ,
137
+ auth_token_getters : dict [str , Callable [[], str ]] = {},
138
+ bound_params : Mapping [str , Union [Callable [[], Any ], Any ]] = {},
139
+ strict : bool = False ,
140
+ ) -> Future [list [ToolboxSyncTool ]]:
141
+ """
142
+ Asynchronously initiates loading of all tools within a specified toolset.
143
+
144
+ This method schedules the toolset loading operation on a background event
145
+ loop and returns a `concurrent.futures.Future` without blocking.
146
+ The future's result will be a list of `ToolboxSyncTool` instances.
147
+ Call `.result()` on the returned future to wait for completion and get
148
+ the list of tools.
149
+
150
+ Args:
151
+ name: Name of the toolset to load tools.
152
+ auth_token_getters: A mapping of authentication service names to
153
+ callables that return the corresponding authentication token.
154
+ bound_params: A mapping of parameter names to bind to specific values or
155
+ callables that are called to produce values as needed.
156
+ strict: If True, raises an error if *any* loaded tool instance fails
157
+ to utilize at least one provided parameter or auth token (if any
158
+ provided). If False (default), raises an error only if a
159
+ user-provided parameter or auth token cannot be applied to *any*
160
+ loaded tool across the set.
161
+
162
+ Returns:
163
+ A `concurrent.futures.Future` that, upon successful completion, will
164
+ yield a list of `ToolboxSyncTool` instances.
165
+
166
+ Raises:
167
+ ValueError: If the background event loop or thread is not running,
168
+ or if validation fails based on the `strict` flag during
169
+ the underlying asynchronous loading process.
170
+ """
171
+
172
+ async def async_worker () -> list [ToolboxSyncTool ]:
173
+ if not self .__loop or not self .__thread :
174
+ raise ValueError ("Background loop or thread cannot be None." )
175
+ async_tools = await self .__async_client .load_toolset (
176
+ name , auth_token_getters , bound_params , strict
177
+ )
178
+ return [
179
+ ToolboxSyncTool (async_tool , self .__loop , self .__thread )
180
+ for async_tool in async_tools
181
+ ]
182
+
183
+ if not self .__loop or not self .__thread :
184
+ raise ValueError ("Background loop or thread cannot be None." )
185
+ return asyncio .run_coroutine_threadsafe (async_worker (), self .__loop )
186
+
89
187
def load_tool (
90
188
self ,
91
189
name : str ,
@@ -111,13 +209,7 @@ def load_tool(
111
209
for execution. The specific arguments and behavior of the callable
112
210
depend on the tool itself.
113
211
"""
114
- coro = self .__async_client .load_tool (name , auth_token_getters , bound_params )
115
-
116
- if not self .__loop or not self .__thread :
117
- raise ValueError ("Background loop or thread cannot be None." )
118
-
119
- async_tool = asyncio .run_coroutine_threadsafe (coro , self .__loop ).result ()
120
- return ToolboxSyncTool (async_tool , self .__loop , self .__thread )
212
+ return self ._load_tool_future (name , auth_token_getters , bound_params ).result ()
121
213
122
214
def load_toolset (
123
215
self ,
@@ -148,18 +240,9 @@ def load_toolset(
148
240
Raises:
149
241
ValueError: If validation fails based on the `strict` flag.
150
242
"""
151
- coro = self .__async_client . load_toolset (
243
+ return self ._load_toolset_future (
152
244
name , auth_token_getters , bound_params , strict
153
- )
154
-
155
- if not self .__loop or not self .__thread :
156
- raise ValueError ("Background loop or thread cannot be None." )
157
-
158
- async_tools = asyncio .run_coroutine_threadsafe (coro , self .__loop ).result ()
159
- return [
160
- ToolboxSyncTool (async_tool , self .__loop , self .__thread )
161
- for async_tool in async_tools
162
- ]
245
+ ).result ()
163
246
164
247
def add_headers (
165
248
self , headers : Mapping [str , Union [Callable , Coroutine , str ]]
0 commit comments