futurehouse-client 0.3.20.dev295__tar.gz → 0.4.0__tar.gz

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.
Files changed (29) hide show
  1. {futurehouse_client-0.3.20.dev295/futurehouse_client.egg-info → futurehouse_client-0.4.0}/PKG-INFO +1 -1
  2. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/clients/rest_client.py +137 -4
  3. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/models/rest.py +14 -0
  4. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/version.py +16 -3
  5. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0/futurehouse_client.egg-info}/PKG-INFO +1 -1
  6. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/tests/test_rest.py +3 -0
  7. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/LICENSE +0 -0
  8. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/README.md +0 -0
  9. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/docs/__init__.py +0 -0
  10. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/docs/client_notebook.ipynb +0 -0
  11. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/__init__.py +0 -0
  12. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/clients/__init__.py +0 -0
  13. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/clients/job_client.py +0 -0
  14. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/models/__init__.py +0 -0
  15. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/models/app.py +0 -0
  16. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/models/client.py +0 -0
  17. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/py.typed +0 -0
  18. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/utils/__init__.py +0 -0
  19. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/utils/auth.py +0 -0
  20. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/utils/general.py +0 -0
  21. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/utils/module_utils.py +0 -0
  22. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client/utils/monitoring.py +0 -0
  23. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client.egg-info/SOURCES.txt +0 -0
  24. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client.egg-info/dependency_links.txt +0 -0
  25. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client.egg-info/requires.txt +0 -0
  26. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/futurehouse_client.egg-info/top_level.txt +0 -0
  27. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/pyproject.toml +0 -0
  28. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/setup.cfg +0 -0
  29. {futurehouse_client-0.3.20.dev295 → futurehouse_client-0.4.0}/tests/test_client.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: futurehouse-client
3
- Version: 0.3.20.dev295
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
@@ -58,6 +58,7 @@ from futurehouse_client.models.app import (
58
58
  TrajectoryQueryParams,
59
59
  )
60
60
  from futurehouse_client.models.rest import (
61
+ DiscoveryResponse,
61
62
  ExecutionStatus,
62
63
  UserAgentRequest,
63
64
  UserAgentRequestPostPayload,
@@ -139,6 +140,14 @@ class ProjectError(RestClientError):
139
140
  """Raised when there's an error with trajectory group operations."""
140
141
 
141
142
 
143
+ class DiscoveryCreationError(RestClientError):
144
+ """Raised when there's an error creating a discovery."""
145
+
146
+
147
+ class DiscoveryFetchError(RestClientError):
148
+ """Raised when there's an error fetching a discovery."""
149
+
150
+
142
151
  class InvalidTaskDescriptionError(Exception):
143
152
  """Raised when the task description is invalid or empty."""
144
153
 
@@ -1737,11 +1746,18 @@ class RestClient:
1737
1746
  wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
1738
1747
  retry=retry_if_connection_error,
1739
1748
  )
1740
- def create_project(self, name: str) -> str:
1749
+ def create_project(
1750
+ self,
1751
+ name: str,
1752
+ shared_with_organizations: list[int] | None = None,
1753
+ shared_with_users: list[str] | None = None,
1754
+ ) -> str:
1741
1755
  """Create a new project.
1742
1756
 
1743
1757
  Args:
1744
1758
  name: The name for the project
1759
+ shared_with_organizations: List of organization IDs to share the project with
1760
+ shared_with_users: List of user emails to share the project with
1745
1761
 
1746
1762
  Returns:
1747
1763
  UUID of the created project
@@ -1750,7 +1766,11 @@ class RestClient:
1750
1766
  ProjectError: If there's an error creating the project
1751
1767
  """
1752
1768
  try:
1753
- data = {"name": name}
1769
+ data = {
1770
+ "name": name,
1771
+ "shared_with_organizations": shared_with_organizations,
1772
+ "shared_with_users": shared_with_users,
1773
+ }
1754
1774
  response = self.client.post("/v0.1/projects", json=data)
1755
1775
  response.raise_for_status()
1756
1776
  return response.json()
@@ -1802,11 +1822,18 @@ class RestClient:
1802
1822
  wait=wait_exponential(multiplier=RETRY_MULTIPLIER, max=MAX_RETRY_WAIT),
1803
1823
  retry=retry_if_connection_error,
1804
1824
  )
1805
- async def acreate_project(self, name: str) -> str:
1825
+ async def acreate_project(
1826
+ self,
1827
+ name: str,
1828
+ shared_with_organizations: list[int] | None = None,
1829
+ shared_with_users: list[str] | None = None,
1830
+ ) -> str:
1806
1831
  """Asynchronously create a new project.
1807
1832
 
1808
1833
  Args:
1809
1834
  name: The name for the project
1835
+ shared_with_organizations: List of organization IDs to share the project with
1836
+ shared_with_users: List of user emails to share the project with
1810
1837
 
1811
1838
  Returns:
1812
1839
  UUID of the created project
@@ -1815,7 +1842,11 @@ class RestClient:
1815
1842
  ProjectError: If there's an error creating the project
1816
1843
  """
1817
1844
  try:
1818
- data = {"name": name}
1845
+ data = {
1846
+ "name": name,
1847
+ "shared_with_organizations": shared_with_organizations,
1848
+ "shared_with_users": shared_with_users,
1849
+ }
1819
1850
  response = await self.async_client.post("/v0.1/projects", json=data)
1820
1851
  response.raise_for_status()
1821
1852
  return response.json()
@@ -2326,6 +2357,108 @@ class RestClient:
2326
2357
  f"An unexpected error occurred while responding to the request: {e!r}."
2327
2358
  ) from e
2328
2359
 
2360
+ def create_discovery(
2361
+ self,
2362
+ project_id: UUID,
2363
+ world_model_id: UUID,
2364
+ dataset_id: UUID,
2365
+ description: str,
2366
+ associated_trajectories: list[UUID],
2367
+ validation_level: int,
2368
+ ) -> UUID:
2369
+ """Create a new discovery.
2370
+
2371
+ Args:
2372
+ project_id: The ID of the project the discovery is associated with.
2373
+ world_model_id: The ID of the world model the discovery is associated with.
2374
+ dataset_id: The ID of the dataset the discovery is associated with.
2375
+ description: The description of the discovery.
2376
+ associated_trajectories: The IDs of the trajectories to associate with the discovery.
2377
+ validation_level: The validation level of the discovery.
2378
+
2379
+ Returns:
2380
+ The ID of the created discovery.
2381
+
2382
+ Raises:
2383
+ DiscoveryCreationError: If there's an error creating the discovery.
2384
+ """
2385
+ try:
2386
+ data = {
2387
+ "project_id": str(project_id),
2388
+ "world_model_id": str(world_model_id),
2389
+ "dataset_id": str(dataset_id),
2390
+ "description": description,
2391
+ "associated_trajectories": [
2392
+ str(trajectory) for trajectory in associated_trajectories
2393
+ ],
2394
+ "validation_level": validation_level,
2395
+ }
2396
+ response = self.client.post("/v0.1/discoveries", json=data)
2397
+ response.raise_for_status()
2398
+ return UUID(response.json())
2399
+ except HTTPStatusError as e:
2400
+ raise DiscoveryCreationError(
2401
+ f"Error creating discovery: {e.response.status_code} - {e.response.text}"
2402
+ ) from e
2403
+ except Exception as e:
2404
+ raise DiscoveryCreationError(f"Error creating discovery: {e!r}") from e
2405
+
2406
+ def get_discovery(self, discovery_id: UUID) -> DiscoveryResponse:
2407
+ """Get a discovery by its ID.
2408
+
2409
+ Args:
2410
+ discovery_id: The ID of the discovery to get.
2411
+
2412
+ Returns:
2413
+ The discovery.
2414
+
2415
+ Raises:
2416
+ DiscoveryFetchError: If there's an error fetching the discovery.
2417
+ """
2418
+ try:
2419
+ response = self.client.get(f"/v0.1/discoveries/{discovery_id}")
2420
+ response.raise_for_status()
2421
+ return DiscoveryResponse.model_validate(response.json())
2422
+ except HTTPStatusError as e:
2423
+ raise DiscoveryFetchError(
2424
+ f"Error fetching discovery: {e.response.status_code} - {e.response.text}"
2425
+ ) from e
2426
+ except Exception as e:
2427
+ raise DiscoveryFetchError(f"Error fetching discovery: {e!r}") from e
2428
+
2429
+ def list_discoveries_for_project(
2430
+ self, project_id: UUID, limit: int = 50, offset: int = 0
2431
+ ) -> list[DiscoveryResponse]:
2432
+ """List discoveries for a specific project.
2433
+
2434
+ Args:
2435
+ project_id: The ID of the project to get discoveries for.
2436
+ limit: The maximum number of discoveries to return.
2437
+ offset: The number of discoveries to skip.
2438
+
2439
+ Returns:
2440
+ A list of discoveries for the specified project.
2441
+
2442
+ Raises:
2443
+ DiscoveryFetchError: If there's an error fetching the discoveries.
2444
+ """
2445
+ try:
2446
+ response = self.client.get(
2447
+ f"/v0.1/projects/{project_id}/discoveries",
2448
+ params={"limit": limit, "offset": offset},
2449
+ )
2450
+ response.raise_for_status()
2451
+ data = response.json()
2452
+ return [DiscoveryResponse.model_validate(d) for d in data]
2453
+ except HTTPStatusError as e:
2454
+ raise DiscoveryFetchError(
2455
+ f"Error fetching discoveries for project: {e.response.status_code} - {e.response.text}"
2456
+ ) from e
2457
+ except Exception as e:
2458
+ raise DiscoveryFetchError(
2459
+ f"Error fetching discoveries for project: {e!r}"
2460
+ ) from e
2461
+
2329
2462
 
2330
2463
  def get_installed_packages() -> dict[str, str]:
2331
2464
  """Returns a dictionary of installed packages and their versions."""
@@ -111,6 +111,7 @@ class UserAgentRequestPostPayload(BaseModel):
111
111
  status: UserAgentRequestStatus = UserAgentRequestStatus.PENDING
112
112
  expires_in_seconds: int | None = None
113
113
  user_response_task: JsonValue | None = None
114
+ notify_user: JsonValue = {"email": True, "sms": False}
114
115
 
115
116
 
116
117
  class UserAgentResponsePayload(BaseModel):
@@ -118,3 +119,16 @@ class UserAgentResponsePayload(BaseModel):
118
119
 
119
120
  response: JsonValue
120
121
  response_world_model_edit_id: UUID | None = None
122
+
123
+
124
+ class DiscoveryResponse(BaseModel):
125
+ """Response model for a discovery request. This model is received from the API."""
126
+
127
+ discovery_id: UUID | str
128
+ project_id: UUID | str
129
+ world_model_id: UUID | str
130
+ dataset_id: UUID | str
131
+ description: str
132
+ associated_trajectories: list[UUID | str]
133
+ validation_level: int
134
+ created_at: datetime
@@ -1,7 +1,14 @@
1
1
  # file generated by setuptools-scm
2
2
  # don't change, don't track in version control
3
3
 
4
- __all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
4
+ __all__ = [
5
+ "__version__",
6
+ "__version_tuple__",
7
+ "version",
8
+ "version_tuple",
9
+ "__commit_id__",
10
+ "commit_id",
11
+ ]
5
12
 
6
13
  TYPE_CHECKING = False
7
14
  if TYPE_CHECKING:
@@ -9,13 +16,19 @@ if TYPE_CHECKING:
9
16
  from typing import Union
10
17
 
11
18
  VERSION_TUPLE = Tuple[Union[int, str], ...]
19
+ COMMIT_ID = Union[str, None]
12
20
  else:
13
21
  VERSION_TUPLE = object
22
+ COMMIT_ID = object
14
23
 
15
24
  version: str
16
25
  __version__: str
17
26
  __version_tuple__: VERSION_TUPLE
18
27
  version_tuple: VERSION_TUPLE
28
+ commit_id: COMMIT_ID
29
+ __commit_id__: COMMIT_ID
19
30
 
20
- __version__ = version = '0.3.20.dev295'
21
- __version_tuple__ = version_tuple = (0, 3, 20, 'dev295')
31
+ __version__ = version = '0.4.0'
32
+ __version_tuple__ = version_tuple = (0, 4, 0)
33
+
34
+ __commit_id__ = commit_id = 'g5229864ab'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: futurehouse-client
3
- Version: 0.3.20.dev295
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
@@ -978,6 +978,7 @@ class TestUserAgentRequestOperations:
978
978
  payload = UserAgentRequestPostPayload(
979
979
  trajectory_id=running_trajectory_id,
980
980
  request={"question": "Do you approve?"},
981
+ notify_user={"email": False, "sms": False}, # avoid sending notifications
981
982
  )
982
983
  request_id = admin_client.create_user_agent_request(payload)
983
984
  assert isinstance(request_id, UUID)
@@ -1045,6 +1046,7 @@ class TestAsyncUserAgentRequestOperations:
1045
1046
  query="Why would I follow up on this query?",
1046
1047
  ).model_dump(mode="json"),
1047
1048
  expires_in_seconds=10,
1049
+ notify_user={"email": False, "sms": False}, # avoid sending notifications
1048
1050
  )
1049
1051
 
1050
1052
  request_id = await admin_client.acreate_user_agent_request(payload)
@@ -1097,6 +1099,7 @@ class TestAsyncUserAgentRequestOperations:
1097
1099
  name=JobNames.from_string("dummy"),
1098
1100
  query="Why would I follow up on this query?",
1099
1101
  ).model_dump(mode="json"),
1102
+ notify_user={"email": False, "sms": False}, # avoid sending notifications
1100
1103
  )
1101
1104
 
1102
1105
  request_id = await admin_client.acreate_user_agent_request(payload)