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.
@@ -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 = create_retry_if_connection_error(FileUploadError)
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(DataStorageMethods):
167
- REQUEST_TIMEOUT: ClassVar[float] = 30.0 # sec - for general API calls
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
- client_timeout = timeout or self.REQUEST_TIMEOUT
268
- key = f"{content_type or 'multipart'}_{authenticated}_{async_client}_{client_timeout}"
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=client_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=client_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]:
@@ -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.3.20.dev411'
32
- __version_tuple__ = version_tuple = (0, 3, 20, 'dev411')
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.20.dev411
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,,