futurehouse-client 0.3.20.dev411__py3-none-any.whl → 0.4.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.
- futurehouse_client/__init__.py +0 -8
- futurehouse_client/clients/rest_client.py +29 -110
- futurehouse_client/utils/general.py +0 -34
- futurehouse_client/version.py +2 -2
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.0.dist-info}/METADATA +1 -6
- futurehouse_client-0.4.0.dist-info/RECORD +20 -0
- futurehouse_client/clients/data_storage_methods.py +0 -1867
- futurehouse_client/models/data_storage_methods.py +0 -333
- futurehouse_client/utils/world_model_tools.py +0 -69
- futurehouse_client-0.3.20.dev411.dist-info/RECORD +0 -23
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.0.dist-info}/WHEEL +0 -0
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {futurehouse_client-0.3.20.dev411.dist-info → futurehouse_client-0.4.0.dist-info}/top_level.txt +0 -0
futurehouse_client/__init__.py
CHANGED
@@ -8,11 +8,6 @@ from .models.app import (
|
|
8
8
|
TaskResponse,
|
9
9
|
TaskResponseVerbose,
|
10
10
|
)
|
11
|
-
from .utils.world_model_tools import (
|
12
|
-
create_world_model_tool,
|
13
|
-
make_world_model_tools,
|
14
|
-
search_world_model_tool,
|
15
|
-
)
|
16
11
|
|
17
12
|
__all__ = [
|
18
13
|
"FinchTaskResponse",
|
@@ -24,7 +19,4 @@ __all__ = [
|
|
24
19
|
"TaskRequest",
|
25
20
|
"TaskResponse",
|
26
21
|
"TaskResponseVerbose",
|
27
|
-
"create_world_model_tool",
|
28
|
-
"make_world_model_tools",
|
29
|
-
"search_world_model_tool",
|
30
22
|
]
|
@@ -26,14 +26,21 @@ from httpx import (
|
|
26
26
|
AsyncClient,
|
27
27
|
Client,
|
28
28
|
CloseError,
|
29
|
+
ConnectError,
|
30
|
+
ConnectTimeout,
|
29
31
|
HTTPStatusError,
|
32
|
+
NetworkError,
|
33
|
+
ReadError,
|
34
|
+
ReadTimeout,
|
30
35
|
RemoteProtocolError,
|
31
36
|
codes,
|
32
37
|
)
|
33
38
|
from ldp.agent import AgentConfig
|
39
|
+
from requests.exceptions import RequestException, Timeout
|
34
40
|
from tenacity import (
|
35
41
|
before_sleep_log,
|
36
42
|
retry,
|
43
|
+
retry_if_exception_type,
|
37
44
|
stop_after_attempt,
|
38
45
|
wait_exponential,
|
39
46
|
)
|
@@ -41,7 +48,6 @@ from tqdm import tqdm as sync_tqdm
|
|
41
48
|
from tqdm.asyncio import tqdm
|
42
49
|
|
43
50
|
from futurehouse_client.clients import JobNames
|
44
|
-
from futurehouse_client.clients.data_storage_methods import DataStorageMethods
|
45
51
|
from futurehouse_client.models.app import (
|
46
52
|
AuthType,
|
47
53
|
JobDeploymentConfig,
|
@@ -62,10 +68,7 @@ from futurehouse_client.models.rest import (
|
|
62
68
|
WorldModelResponse,
|
63
69
|
)
|
64
70
|
from futurehouse_client.utils.auth import RefreshingJWT
|
65
|
-
from futurehouse_client.utils.general import
|
66
|
-
create_retry_if_connection_error,
|
67
|
-
gather_with_concurrency,
|
68
|
-
)
|
71
|
+
from futurehouse_client.utils.general import gather_with_concurrency
|
69
72
|
from futurehouse_client.utils.module_utils import (
|
70
73
|
OrganizationSelector,
|
71
74
|
fetch_environment_function_docstring,
|
@@ -133,10 +136,6 @@ class WorldModelCreationError(RestClientError):
|
|
133
136
|
"""Raised when there's an error creating a world model."""
|
134
137
|
|
135
138
|
|
136
|
-
class WorldModelDeletionError(RestClientError):
|
137
|
-
"""Raised when there's an error deleting a world model."""
|
138
|
-
|
139
|
-
|
140
139
|
class ProjectError(RestClientError):
|
141
140
|
"""Raised when there's an error with trajectory group operations."""
|
142
141
|
|
@@ -157,15 +156,28 @@ class FileUploadError(RestClientError):
|
|
157
156
|
"""Raised when there's an error uploading a file."""
|
158
157
|
|
159
158
|
|
160
|
-
retry_if_connection_error =
|
159
|
+
retry_if_connection_error = retry_if_exception_type((
|
160
|
+
# From requests
|
161
|
+
Timeout,
|
162
|
+
ConnectionError,
|
163
|
+
RequestException,
|
164
|
+
# From httpx
|
165
|
+
ConnectError,
|
166
|
+
ConnectTimeout,
|
167
|
+
ReadTimeout,
|
168
|
+
ReadError,
|
169
|
+
NetworkError,
|
170
|
+
RemoteProtocolError,
|
171
|
+
CloseError,
|
172
|
+
FileUploadError,
|
173
|
+
))
|
161
174
|
|
162
175
|
DEFAULT_AGENT_TIMEOUT: int = 2400 # seconds
|
163
176
|
|
164
177
|
|
165
178
|
# pylint: disable=too-many-public-methods
|
166
|
-
class RestClient
|
167
|
-
REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec
|
168
|
-
FILE_UPLOAD_TIMEOUT: ClassVar[float] = 600.0 # 10 minutes - for file uploads
|
179
|
+
class RestClient:
|
180
|
+
REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec
|
169
181
|
MAX_RETRY_ATTEMPTS: ClassVar[int] = 3
|
170
182
|
RETRY_MULTIPLIER: ClassVar[int] = 1
|
171
183
|
MAX_RETRY_WAIT: ClassVar[int] = 10
|
@@ -223,35 +235,11 @@ class RestClient(DataStorageMethods):
|
|
223
235
|
"""Authenticated HTTP client for multipart uploads."""
|
224
236
|
return cast(Client, self.get_client(None, authenticated=True))
|
225
237
|
|
226
|
-
@property
|
227
|
-
def file_upload_client(self) -> Client:
|
228
|
-
"""Authenticated HTTP client with extended timeout for file uploads."""
|
229
|
-
return cast(
|
230
|
-
Client,
|
231
|
-
self.get_client(
|
232
|
-
"application/json", authenticated=True, timeout=self.FILE_UPLOAD_TIMEOUT
|
233
|
-
),
|
234
|
-
)
|
235
|
-
|
236
|
-
@property
|
237
|
-
def async_file_upload_client(self) -> AsyncClient:
|
238
|
-
"""Authenticated async HTTP client with extended timeout for file uploads."""
|
239
|
-
return cast(
|
240
|
-
AsyncClient,
|
241
|
-
self.get_client(
|
242
|
-
"application/json",
|
243
|
-
authenticated=True,
|
244
|
-
async_client=True,
|
245
|
-
timeout=self.FILE_UPLOAD_TIMEOUT,
|
246
|
-
),
|
247
|
-
)
|
248
|
-
|
249
238
|
def get_client(
|
250
239
|
self,
|
251
240
|
content_type: str | None = "application/json",
|
252
241
|
authenticated: bool = True,
|
253
242
|
async_client: bool = False,
|
254
|
-
timeout: float | None = None,
|
255
243
|
) -> Client | AsyncClient:
|
256
244
|
"""Return a cached HTTP client or create one if needed.
|
257
245
|
|
@@ -259,13 +247,12 @@ class RestClient(DataStorageMethods):
|
|
259
247
|
content_type: The desired content type header. Use None for multipart uploads.
|
260
248
|
authenticated: Whether the client should include authentication.
|
261
249
|
async_client: Whether to use an async client.
|
262
|
-
timeout: Custom timeout in seconds. Uses REQUEST_TIMEOUT if not provided.
|
263
250
|
|
264
251
|
Returns:
|
265
252
|
An HTTP client configured with the appropriate headers.
|
266
253
|
"""
|
267
|
-
|
268
|
-
key = f"{content_type or 'multipart'}_{authenticated}_{async_client}
|
254
|
+
# Create a composite key based on content type and auth flag
|
255
|
+
key = f"{content_type or 'multipart'}_{authenticated}_{async_client}"
|
269
256
|
|
270
257
|
if key not in self._clients:
|
271
258
|
headers = copy.deepcopy(self.headers)
|
@@ -291,14 +278,14 @@ class RestClient(DataStorageMethods):
|
|
291
278
|
AsyncClient(
|
292
279
|
base_url=self.base_url,
|
293
280
|
headers=headers,
|
294
|
-
timeout=
|
281
|
+
timeout=self.REQUEST_TIMEOUT,
|
295
282
|
auth=auth,
|
296
283
|
)
|
297
284
|
if async_client
|
298
285
|
else Client(
|
299
286
|
base_url=self.base_url,
|
300
287
|
headers=headers,
|
301
|
-
timeout=
|
288
|
+
timeout=self.REQUEST_TIMEOUT,
|
302
289
|
auth=auth,
|
303
290
|
)
|
304
291
|
)
|
@@ -1606,48 +1593,6 @@ class RestClient(DataStorageMethods):
|
|
1606
1593
|
except Exception as e:
|
1607
1594
|
raise WorldModelFetchError(f"An unexpected error occurred: {e!r}.") from e
|
1608
1595
|
|
1609
|
-
@retry(
|
1610
|
-
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
1611
|
-
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
1612
|
-
retry=retry_if_connection_error,
|
1613
|
-
)
|
1614
|
-
def search_world_models(
|
1615
|
-
self,
|
1616
|
-
query: str,
|
1617
|
-
size: int = 10,
|
1618
|
-
total_search_size: int = 50,
|
1619
|
-
search_all_versions: bool = False,
|
1620
|
-
) -> list[str]:
|
1621
|
-
"""Search for world models.
|
1622
|
-
|
1623
|
-
Args:
|
1624
|
-
query: The search query.
|
1625
|
-
size: The number of results to return.
|
1626
|
-
total_search_size: The number of results to search for.
|
1627
|
-
search_all_versions: Whether to search all versions of the world model or just the latest one.
|
1628
|
-
|
1629
|
-
Returns:
|
1630
|
-
A list of world model names.
|
1631
|
-
"""
|
1632
|
-
try:
|
1633
|
-
response = self.client.get(
|
1634
|
-
"/v0.1/world-models/search/",
|
1635
|
-
params={
|
1636
|
-
"query": query,
|
1637
|
-
"size": size,
|
1638
|
-
"total_search_size": total_search_size,
|
1639
|
-
"search_all_versions": search_all_versions,
|
1640
|
-
},
|
1641
|
-
)
|
1642
|
-
response.raise_for_status()
|
1643
|
-
return response.json()
|
1644
|
-
except HTTPStatusError as e:
|
1645
|
-
raise WorldModelFetchError(
|
1646
|
-
f"Error searching world models: {e.response.status_code} - {e.response.text}"
|
1647
|
-
) from e
|
1648
|
-
except Exception as e:
|
1649
|
-
raise WorldModelFetchError(f"An unexpected error occurred: {e!r}.") from e
|
1650
|
-
|
1651
1596
|
@retry(
|
1652
1597
|
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
1653
1598
|
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
@@ -1723,32 +1668,6 @@ class RestClient(DataStorageMethods):
|
|
1723
1668
|
f"An unexpected error occurred during world model creation: {e!r}."
|
1724
1669
|
) from e
|
1725
1670
|
|
1726
|
-
@retry(
|
1727
|
-
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
1728
|
-
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
1729
|
-
retry=retry_if_connection_error,
|
1730
|
-
)
|
1731
|
-
async def delete_world_model(self, world_model_id: UUID) -> None:
|
1732
|
-
"""Delete a world model snapshot by its ID.
|
1733
|
-
|
1734
|
-
Args:
|
1735
|
-
world_model_id: The unique ID of the world model snapshot to delete.
|
1736
|
-
|
1737
|
-
Raises:
|
1738
|
-
WorldModelDeletionError: If the API call fails.
|
1739
|
-
"""
|
1740
|
-
try:
|
1741
|
-
response = await self.async_client.delete(
|
1742
|
-
f"/v0.1/world-models/{world_model_id}"
|
1743
|
-
)
|
1744
|
-
response.raise_for_status()
|
1745
|
-
except HTTPStatusError as e:
|
1746
|
-
raise WorldModelDeletionError(
|
1747
|
-
f"Error deleting world model: {e.response.status_code} - {e.response.text}"
|
1748
|
-
) from e
|
1749
|
-
except Exception as e:
|
1750
|
-
raise WorldModelDeletionError(f"An unexpected error occurred: {e}") from e
|
1751
|
-
|
1752
1671
|
@retry(
|
1753
1672
|
stop=stop_after_attempt(MAX_RETRY_ATTEMPTS),
|
1754
1673
|
wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
|
@@ -2,45 +2,11 @@ import asyncio
|
|
2
2
|
from collections.abc import Awaitable, Iterable
|
3
3
|
from typing import TypeVar
|
4
4
|
|
5
|
-
from httpx import (
|
6
|
-
CloseError,
|
7
|
-
ConnectError,
|
8
|
-
ConnectTimeout,
|
9
|
-
NetworkError,
|
10
|
-
ReadError,
|
11
|
-
ReadTimeout,
|
12
|
-
RemoteProtocolError,
|
13
|
-
)
|
14
|
-
from requests.exceptions import RequestException, Timeout
|
15
|
-
from tenacity import retry_if_exception_type
|
16
5
|
from tqdm.asyncio import tqdm
|
17
6
|
|
18
7
|
T = TypeVar("T")
|
19
8
|
|
20
9
|
|
21
|
-
_BASE_CONNECTION_ERRORS = (
|
22
|
-
# From requests
|
23
|
-
Timeout,
|
24
|
-
ConnectionError,
|
25
|
-
RequestException,
|
26
|
-
# From httpx
|
27
|
-
ConnectError,
|
28
|
-
ConnectTimeout,
|
29
|
-
ReadTimeout,
|
30
|
-
ReadError,
|
31
|
-
NetworkError,
|
32
|
-
RemoteProtocolError,
|
33
|
-
CloseError,
|
34
|
-
)
|
35
|
-
|
36
|
-
retry_if_connection_error = retry_if_exception_type(_BASE_CONNECTION_ERRORS)
|
37
|
-
|
38
|
-
|
39
|
-
def create_retry_if_connection_error(*additional_exceptions):
|
40
|
-
"""Create a retry condition with base connection errors plus additional exceptions."""
|
41
|
-
return retry_if_exception_type(_BASE_CONNECTION_ERRORS + additional_exceptions)
|
42
|
-
|
43
|
-
|
44
10
|
async def gather_with_concurrency(
|
45
11
|
n: int | asyncio.Semaphore, coros: Iterable[Awaitable[T]], progress: bool = False
|
46
12
|
) -> list[T]:
|
futurehouse_client/version.py
CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '0.
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
31
|
+
__version__ = version = '0.4.0'
|
32
|
+
__version_tuple__ = version_tuple = (0, 4, 0)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: futurehouse-client
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.4.0
|
4
4
|
Summary: A client for interacting with endpoints of the FutureHouse service.
|
5
5
|
Author-email: FutureHouse technical staff <hello@futurehouse.org>
|
6
6
|
License: Apache License
|
@@ -213,22 +213,18 @@ Classifier: Programming Language :: Python
|
|
213
213
|
Requires-Python: <3.14,>=3.11
|
214
214
|
Description-Content-Type: text/markdown
|
215
215
|
License-File: LICENSE
|
216
|
-
Requires-Dist: aiofiles
|
217
216
|
Requires-Dist: cloudpickle
|
218
217
|
Requires-Dist: fhaviary
|
219
|
-
Requires-Dist: google-resumable-media[aiohttp]
|
220
218
|
Requires-Dist: httpx
|
221
219
|
Requires-Dist: ldp>=0.22.0
|
222
220
|
Requires-Dist: litellm
|
223
221
|
Requires-Dist: pydantic
|
224
222
|
Requires-Dist: python-dotenv
|
225
|
-
Requires-Dist: requests
|
226
223
|
Requires-Dist: tenacity
|
227
224
|
Requires-Dist: tqdm>=4.62
|
228
225
|
Provides-Extra: dev
|
229
226
|
Requires-Dist: black; extra == "dev"
|
230
227
|
Requires-Dist: futurehouse-client[monitoring,typing]; extra == "dev"
|
231
|
-
Requires-Dist: ipykernel; extra == "dev"
|
232
228
|
Requires-Dist: jupyter; extra == "dev"
|
233
229
|
Requires-Dist: jupyterlab; extra == "dev"
|
234
230
|
Requires-Dist: mypy; extra == "dev"
|
@@ -248,7 +244,6 @@ Requires-Dist: setuptools_scm; extra == "dev"
|
|
248
244
|
Provides-Extra: monitoring
|
249
245
|
Requires-Dist: newrelic>=8.8.0; extra == "monitoring"
|
250
246
|
Provides-Extra: typing
|
251
|
-
Requires-Dist: types-PyYAML; extra == "typing"
|
252
247
|
Requires-Dist: types-requests; extra == "typing"
|
253
248
|
Requires-Dist: types-tqdm; extra == "typing"
|
254
249
|
Dynamic: license-file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
futurehouse_client/__init__.py,sha256=BztM_ntbgmIEjzvnBWcvPhvLjM8xGDFCK0Upf3-nIn8,488
|
2
|
+
futurehouse_client/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
futurehouse_client/version.py,sha256=2_0GUP7yBCXRus-qiJKxQD62z172WSs1sQ6DVpPsbmM,704
|
4
|
+
futurehouse_client/clients/__init__.py,sha256=-HXNj-XJ3LRO5XM6MZ709iPs29YpApss0Q2YYg1qMZw,280
|
5
|
+
futurehouse_client/clients/job_client.py,sha256=D51_qTxya6g5Wfg_ZfJdP031TV_YDJeXkGMiYAJ1qRc,11962
|
6
|
+
futurehouse_client/clients/rest_client.py,sha256=iGBMTdtSVRA2eaqdLVsHrQoF8ToKOnFfbIVhfibjzFs,97022
|
7
|
+
futurehouse_client/models/__init__.py,sha256=kQ4R7VEuRxO0IQEW_sk9CndBL7zzl8rUKI24ddyYLM0,647
|
8
|
+
futurehouse_client/models/app.py,sha256=TGoAeENNPc5mSBkMHjh-Z8VIlnaUNcoWUJLxUhRIkEE,31868
|
9
|
+
futurehouse_client/models/client.py,sha256=n4HD0KStKLm6Ek9nL9ylP-bkK10yzAaD1uIDF83Qp_A,1828
|
10
|
+
futurehouse_client/models/rest.py,sha256=ybelLsyTsKYud7DYUCF0sFF6u81bl8WmS_wWAnbX-0M,3382
|
11
|
+
futurehouse_client/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
|
+
futurehouse_client/utils/auth.py,sha256=tgWELjKfg8eWme_qdcRmc8TjQN9DVZuHHaVXZNHLchk,2960
|
13
|
+
futurehouse_client/utils/general.py,sha256=A_rtTiYW30ELGEZlWCIArO7q1nEmqi8hUlmBRYkMQ_c,767
|
14
|
+
futurehouse_client/utils/module_utils.py,sha256=aFyd-X-pDARXz9GWpn8SSViUVYdSbuy9vSkrzcVIaGI,4955
|
15
|
+
futurehouse_client/utils/monitoring.py,sha256=UjRlufe67kI3VxRHOd5fLtJmlCbVA2Wqwpd4uZhXkQM,8728
|
16
|
+
futurehouse_client-0.4.0.dist-info/licenses/LICENSE,sha256=oQ9ZHjUi-_6GfP3gs14FlPb0OlGwE1QCCKFGnJ4LD2I,11341
|
17
|
+
futurehouse_client-0.4.0.dist-info/METADATA,sha256=cDJvUHmNJHAFw6kELrjYIOHyIeSeYZuaDwHJskg8wjs,26797
|
18
|
+
futurehouse_client-0.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
19
|
+
futurehouse_client-0.4.0.dist-info/top_level.txt,sha256=TRuLUCt_qBnggdFHCX4O_BoCu1j2X43lKfIZC-ElwWY,19
|
20
|
+
futurehouse_client-0.4.0.dist-info/RECORD,,
|