hypha-rpc 0.20.93__tar.gz → 0.20.94__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 (35) hide show
  1. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/PKG-INFO +1 -1
  2. hypha_rpc-0.20.94/hypha_rpc/VERSION +3 -0
  3. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/__init__.py +18 -7
  4. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/http_client.py +25 -12
  5. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/rpc.py +231 -136
  6. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/__init__.py +15 -9
  7. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/websocket_client.py +42 -8
  8. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc.egg-info/PKG-INFO +1 -1
  9. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/pyproject.toml +1 -1
  10. hypha_rpc-0.20.94/tests/test_http_rpc.py +728 -0
  11. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_reconnection_runner.py +57 -46
  12. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_reconnection_stability.py +296 -194
  13. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_websocket_rpc.py +859 -627
  14. hypha_rpc-0.20.93/hypha_rpc/VERSION +0 -3
  15. hypha_rpc-0.20.93/tests/test_http_rpc.py +0 -422
  16. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/MANIFEST.in +0 -0
  17. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/README.md +0 -0
  18. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/pyodide_sse.py +0 -0
  19. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/pyodide_websocket.py +0 -0
  20. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/sync.py +0 -0
  21. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/launch.py +0 -0
  22. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/mcp.py +0 -0
  23. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/pydantic.py +0 -0
  24. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/schema.py +0 -0
  25. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/utils/serve.py +0 -0
  26. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc/webrtc_client.py +0 -0
  27. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc.egg-info/SOURCES.txt +0 -0
  28. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc.egg-info/dependency_links.txt +0 -0
  29. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc.egg-info/requires.txt +0 -0
  30. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/hypha_rpc.egg-info/top_level.txt +0 -0
  31. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/setup.cfg +0 -0
  32. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_mcp.py +0 -0
  33. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_schema.py +0 -0
  34. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_server_compatibility.py +0 -0
  35. {hypha_rpc-0.20.93 → hypha_rpc-0.20.94}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypha_rpc
3
- Version: 0.20.93
3
+ Version: 0.20.94
4
4
  Summary: Hypha RPC client for connecting to Hypha server for data management and AI model serving
5
5
  Author-email: Wei Ouyang <oeway007@gmail.com>
6
6
  Requires-Python: >=3.9
@@ -0,0 +1,3 @@
1
+ {
2
+ "version": "0.20.94"
3
+ }
@@ -28,11 +28,12 @@ from .http_client import HTTPStreamingRPCConnection
28
28
  with open(os.path.join(os.path.dirname(__file__), "VERSION"), "r") as f:
29
29
  __version__ = json.load(f)["version"]
30
30
 
31
+
31
32
  def is_user_defined_class_instance(obj):
32
33
  return (
33
- not isinstance(obj, type) and # not a class itself
34
- hasattr(obj, "__class__") and
35
- obj.__class__.__module__ != "builtins" # not a built-in type
34
+ not isinstance(obj, type) # not a class itself
35
+ and hasattr(obj, "__class__")
36
+ and obj.__class__.__module__ != "builtins" # not a built-in type
36
37
  )
37
38
 
38
39
 
@@ -41,23 +42,34 @@ class API(ObjectProxy):
41
42
  super().__init__(*args, **kwargs)
42
43
  self._registry = {}
43
44
  self._export_handler = self._default_export_handler
44
-
45
+
45
46
  async def _register_services(self, obj, config=None, **kwargs):
46
47
  if not os.environ.get("HYPHA_SERVER_URL"):
47
48
  try:
48
49
  from dotenv import load_dotenv, find_dotenv
50
+
49
51
  load_dotenv(dotenv_path=find_dotenv(usecwd=True))
50
52
  # use info from .env file
51
53
  print("✅ Loaded connection configuration from .env file.")
52
54
  except ImportError:
53
- print("❌ Missing environment variables. Set HYPHA_SERVER_URL, HYPHA_TOKEN, HYPHA_WORKSPACE", file=sys.stderr)
55
+ print(
56
+ "❌ Missing environment variables. Set HYPHA_SERVER_URL, HYPHA_TOKEN, HYPHA_WORKSPACE",
57
+ file=sys.stderr,
58
+ )
54
59
  sys.exit(1)
55
60
  SERVER_URL = os.environ.get("HYPHA_SERVER_URL")
56
61
  TOKEN = os.environ.get("HYPHA_TOKEN")
57
62
  CLIENT_ID = os.environ.get("HYPHA_CLIENT_ID")
58
63
  WORKSPACE = os.environ.get("HYPHA_WORKSPACE")
59
64
 
60
- server = await connect_to_server({"client_id": CLIENT_ID, "server_url": SERVER_URL, "token": TOKEN, "workspace": WORKSPACE})
65
+ server = await connect_to_server(
66
+ {
67
+ "client_id": CLIENT_ID,
68
+ "server_url": SERVER_URL,
69
+ "token": TOKEN,
70
+ "workspace": WORKSPACE,
71
+ }
72
+ )
61
73
  # If obj is a class, instantiate it
62
74
  if isinstance(obj, type):
63
75
  obj = obj()
@@ -96,7 +108,6 @@ class API(ObjectProxy):
96
108
  asyncio.create_task(self._register_services(obj, config, **kwargs))
97
109
  else:
98
110
  asyncio.run(self._register_services(obj, config, **kwargs))
99
-
100
111
 
101
112
  def set_export_handler(self, handler):
102
113
  self._export_handler = handler
@@ -134,7 +134,9 @@ class HTTPStreamingRPCConnection:
134
134
  if response.status_code == 200:
135
135
  logger.debug("Token refresh requested successfully")
136
136
  else:
137
- logger.warning(f"Token refresh request failed: {response.status_code}")
137
+ logger.warning(
138
+ f"Token refresh request failed: {response.status_code}"
139
+ )
138
140
  except Exception as e:
139
141
  logger.warning(f"Failed to send refresh token request: {e}")
140
142
 
@@ -177,11 +179,14 @@ class HTTPStreamingRPCConnection:
177
179
  # Try to enable HTTP/2 if h2 is available
178
180
  try:
179
181
  import h2 # noqa
182
+
180
183
  http2_enabled = True
181
184
  logger.info("HTTP/2 enabled for improved performance")
182
185
  except ImportError:
183
186
  http2_enabled = False
184
- logger.debug("HTTP/2 not available (install httpx[http2] for better performance)")
187
+ logger.debug(
188
+ "HTTP/2 not available (install httpx[http2] for better performance)"
189
+ )
185
190
 
186
191
  return httpx.AsyncClient(
187
192
  timeout=httpx.Timeout(self._timeout, connect=30.0),
@@ -198,14 +203,16 @@ class HTTPStreamingRPCConnection:
198
203
 
199
204
  async def open(self):
200
205
  """Open the streaming connection."""
201
- logger.info(f"Opening HTTP streaming connection to {self._server_url} (format={self._format})")
206
+ logger.info(
207
+ f"Opening HTTP streaming connection to {self._server_url} (format={self._format})"
208
+ )
202
209
 
203
210
  if self._http_client is None:
204
211
  self._http_client = await self._create_http_client()
205
212
 
206
- # Build stream URL
207
- workspace = self._workspace or "public"
208
- stream_url = f"{self._server_url}/{workspace}/rpc"
213
+ # Build stream URL - workspace is part of path, default to "public" for anonymous
214
+ ws = self._workspace or "public"
215
+ stream_url = f"{self._server_url}/{ws}/rpc"
209
216
  params = {"client_id": self._client_id}
210
217
  if self._format == "msgpack":
211
218
  params["format"] = "msgpack"
@@ -357,15 +364,15 @@ class HTTPStreamingRPCConnection:
357
364
  # Process complete frames from buffer
358
365
  while len(buffer) >= 4:
359
366
  # Read 4-byte length prefix (big-endian)
360
- length = int.from_bytes(buffer[:4], 'big')
367
+ length = int.from_bytes(buffer[:4], "big")
361
368
 
362
369
  if len(buffer) < 4 + length:
363
370
  # Incomplete frame, wait for more data
364
371
  break
365
372
 
366
373
  # Extract the frame
367
- frame_data = buffer[4:4 + length]
368
- buffer = buffer[4 + length:]
374
+ frame_data = buffer[4 : 4 + length]
375
+ buffer = buffer[4 + length :]
369
376
 
370
377
  try:
371
378
  # For msgpack, first check if it's a control message
@@ -440,8 +447,9 @@ class HTTPStreamingRPCConnection:
440
447
  if self._http_client is None:
441
448
  self._http_client = await self._create_http_client()
442
449
 
443
- workspace = self._workspace or "public"
444
- url = f"{self._server_url}/{workspace}/rpc"
450
+ # Build POST URL - workspace is part of path (must be set after connection)
451
+ ws = self._workspace or "public"
452
+ url = f"{self._server_url}/{ws}/rpc"
445
453
  params = {"client_id": self._client_id}
446
454
 
447
455
  try:
@@ -454,7 +462,9 @@ class HTTPStreamingRPCConnection:
454
462
  )
455
463
 
456
464
  if response.status_code != 200:
457
- error = response.json() if response.content else {"detail": "Unknown error"}
465
+ error = (
466
+ response.json() if response.content else {"detail": "Unknown error"}
467
+ )
458
468
  raise ConnectionError(f"POST failed: {error.get('detail', error)}")
459
469
 
460
470
  except httpx.TimeoutException:
@@ -528,6 +538,7 @@ def connect_to_server_http(config=None, **kwargs):
528
538
  ServerContextManager that can be used as async context manager
529
539
  """
530
540
  from .websocket_client import connect_to_server
541
+
531
542
  config = config or {}
532
543
  config.update(kwargs)
533
544
  config["transport"] = "http"
@@ -625,6 +636,7 @@ async def _connect_to_server_http(config: dict):
625
636
 
626
637
  # Handle force-exit from manager
627
638
  if connection.manager_id:
639
+
628
640
  async def handle_disconnect(message):
629
641
  if message.get("from") == "*/" + connection.manager_id:
630
642
  logger.info(f"Disconnecting from server: {message.get('reason')}")
@@ -642,6 +654,7 @@ def get_remote_service_http(service_uri: str, config=None, **kwargs):
642
654
  For a unified interface, use get_remote_service with transport="http" instead.
643
655
  """
644
656
  from .websocket_client import get_remote_service
657
+
645
658
  config = config or {}
646
659
  config.update(kwargs)
647
660
  config["transport"] = "http"