hypha-rpc 0.20.91__py3-none-any.whl → 0.20.93__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.
hypha_rpc/VERSION CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.20.91"
2
+ "version": "0.20.93"
3
3
  }
hypha_rpc/__init__.py CHANGED
@@ -15,8 +15,13 @@ from .sync import login as login_sync
15
15
  from .sync import logout as logout_sync
16
16
  from .sync import register_rtc_service as register_rtc_service_sync
17
17
  from .webrtc_client import get_rtc_service, register_rtc_service
18
- from .client import connect_to_server, get_remote_service
19
- from .websocket_client import login, logout, setup_local_client
18
+ from .websocket_client import (
19
+ connect_to_server,
20
+ get_remote_service,
21
+ login,
22
+ logout,
23
+ setup_local_client,
24
+ )
20
25
  from .http_client import HTTPStreamingRPCConnection
21
26
 
22
27
  # read the version from the VERSION file; but get the path from the __file__
hypha_rpc/http_client.py CHANGED
@@ -174,15 +174,26 @@ class HTTPStreamingRPCConnection:
174
174
  elif self._ssl is not None:
175
175
  verify = self._ssl
176
176
 
177
+ # Try to enable HTTP/2 if h2 is available
178
+ try:
179
+ import h2 # noqa
180
+ http2_enabled = True
181
+ logger.info("HTTP/2 enabled for improved performance")
182
+ except ImportError:
183
+ http2_enabled = False
184
+ logger.debug("HTTP/2 not available (install httpx[http2] for better performance)")
185
+
177
186
  return httpx.AsyncClient(
178
187
  timeout=httpx.Timeout(self._timeout, connect=30.0),
179
188
  verify=verify,
180
- # Connection pooling for better performance with many requests
189
+ # Optimized connection pooling for high-performance RPC
181
190
  limits=httpx.Limits(
182
- max_connections=100, # Max total connections
183
- max_keepalive_connections=20, # Keep-alive connections for reuse
184
- keepalive_expiry=30.0, # Keep connections alive for 30 seconds
191
+ max_connections=200, # Max total connections (increased for parallel requests)
192
+ max_keepalive_connections=50, # More reusable connections (up from 20)
193
+ keepalive_expiry=300.0, # Keep connections alive longer (5 minutes)
185
194
  ),
195
+ # Enable HTTP/2 for better multiplexing if available
196
+ http2=http2_enabled,
186
197
  )
187
198
 
188
199
  async def open(self):
@@ -418,7 +429,11 @@ class HTTPStreamingRPCConnection:
418
429
  self._handle_message(data)
419
430
 
420
431
  async def emit_message(self, data: bytes):
421
- """Send a message to the server via HTTP POST."""
432
+ """Send a message to the server via HTTP POST.
433
+
434
+ Uses optimized connection pooling with keep-alive for better performance.
435
+ HTTP client automatically handles efficient transfer for all payload sizes.
436
+ """
422
437
  if self._closed:
423
438
  raise ConnectionError("Connection is closed")
424
439
 
@@ -430,6 +445,7 @@ class HTTPStreamingRPCConnection:
430
445
  params = {"client_id": self._client_id}
431
446
 
432
447
  try:
448
+ # httpx handles large payloads efficiently with connection pooling
433
449
  response = await self._http_client.post(
434
450
  url,
435
451
  content=data,
@@ -511,7 +527,7 @@ def connect_to_server_http(config=None, **kwargs):
511
527
  Returns:
512
528
  ServerContextManager that can be used as async context manager
513
529
  """
514
- from .client import connect_to_server
530
+ from .websocket_client import connect_to_server
515
531
  config = config or {}
516
532
  config.update(kwargs)
517
533
  config["transport"] = "http"
@@ -625,7 +641,7 @@ def get_remote_service_http(service_uri: str, config=None, **kwargs):
625
641
  This is a convenience function that sets transport="http" automatically.
626
642
  For a unified interface, use get_remote_service with transport="http" instead.
627
643
  """
628
- from .client import get_remote_service
644
+ from .websocket_client import get_remote_service
629
645
  config = config or {}
630
646
  config.update(kwargs)
631
647
  config["transport"] = "http"
@@ -738,10 +738,6 @@ async def logout(config):
738
738
  await server.disconnect()
739
739
 
740
740
 
741
- # Re-export from client.py for backwards compatibility
742
- from .client import ServerContextManager, connect_to_server, get_remote_service
743
-
744
-
745
741
  async def webrtc_get_service(wm, rtc_service_id, query, config=None, **kwargs):
746
742
  config = config or {}
747
743
  config.update(kwargs)
@@ -1151,6 +1147,118 @@ async def _connect_to_server(config):
1151
1147
  return wm
1152
1148
 
1153
1149
 
1150
+ class ServerContextManager:
1151
+ """Server context manager.
1152
+
1153
+ Supports multiple transport types:
1154
+ - "websocket" (default): Traditional WebSocket connection
1155
+ - "http": HTTP streaming connection (more resilient to network issues)
1156
+ """
1157
+
1158
+ def __init__(self, config=None, service_id=None, **kwargs):
1159
+ self.config = config or {}
1160
+ self.config.update(kwargs)
1161
+
1162
+ if not self.config:
1163
+ # try to load from env
1164
+ if not os.environ.get("HYPHA_SERVER_URL"):
1165
+ try:
1166
+ from dotenv import load_dotenv, find_dotenv
1167
+ load_dotenv(dotenv_path=find_dotenv(usecwd=True))
1168
+ # use info from .env file
1169
+ print("✅ Loaded connection configuration from .env file.")
1170
+ except ImportError:
1171
+ pass
1172
+ self.config = {
1173
+ "server_url": os.getenv("HYPHA_SERVER_URL"),
1174
+ "token": os.getenv("HYPHA_TOKEN"),
1175
+ "client_id": os.getenv("HYPHA_CLIENT_ID"),
1176
+ "workspace": os.getenv("HYPHA_WORKSPACE"),
1177
+ }
1178
+ if not self.config["server_url"]:
1179
+ raise ValueError(
1180
+ "Please set the HYPHA_SERVER_URL, HYPHA_TOKEN, "
1181
+ "HYPHA_CLIENT_ID, and HYPHA_WORKSPACE environment variables"
1182
+ )
1183
+ self._service_id = service_id
1184
+ self._transport = self.config.pop("transport", "websocket")
1185
+ self.wm = None
1186
+
1187
+ async def __aenter__(self):
1188
+ if self._transport == "http":
1189
+ from .http_client import _connect_to_server_http
1190
+ self.wm = await _connect_to_server_http(self.config)
1191
+ else:
1192
+ self.wm = await _connect_to_server(self.config)
1193
+ if self._service_id:
1194
+ return await self.wm.get_service(
1195
+ self._service_id,
1196
+ {"case_conversion": self.config.get("case_conversion")},
1197
+ )
1198
+ return self.wm
1199
+
1200
+ async def __aexit__(self, exc_type, exc, tb):
1201
+ await self.wm.disconnect()
1202
+
1203
+ def __await__(self):
1204
+ return self.__aenter__().__await__()
1205
+
1206
+
1207
+ def connect_to_server(config=None, **kwargs):
1208
+ """Connect to a Hypha server.
1209
+
1210
+ Args:
1211
+ config: Configuration dict with connection options
1212
+ **kwargs: Additional configuration options
1213
+
1214
+ Configuration options:
1215
+ server_url: The server URL (required)
1216
+ workspace: Target workspace (optional)
1217
+ token: Authentication token (optional)
1218
+ client_id: Unique client identifier (optional, auto-generated if not provided)
1219
+ transport: Transport type - "websocket" (default) or "http"
1220
+ method_timeout: Timeout for RPC method calls
1221
+ ssl: SSL configuration (True/False/SSLContext)
1222
+
1223
+ Returns:
1224
+ ServerContextManager that can be used as async context manager
1225
+
1226
+ Example:
1227
+ async with connect_to_server({"server_url": "https://hypha.aicell.io"}) as server:
1228
+ await server.register_service({"id": "my-service", ...})
1229
+ """
1230
+ return ServerContextManager(config=config, **kwargs)
1231
+
1232
+
1233
+ def get_remote_service(service_uri, config=None, **kwargs):
1234
+ """Get a remote service by URI.
1235
+
1236
+ Args:
1237
+ service_uri: Service URI in format "server_url/workspace/client_id:service_id"
1238
+ config: Additional configuration options
1239
+ **kwargs: Additional configuration options
1240
+
1241
+ Returns:
1242
+ ServerContextManager that resolves to the service when awaited
1243
+
1244
+ Example:
1245
+ async with get_remote_service("https://hypha.aicell.io/public/client:service") as svc:
1246
+ result = await svc.some_method()
1247
+ """
1248
+ server_url, workspace, client_id, service_id, app_id = parse_service_url(
1249
+ service_uri
1250
+ )
1251
+ full_service_id = f"{workspace}/{client_id}:{service_id}@{app_id}"
1252
+ config = config or {}
1253
+ config.update(kwargs)
1254
+ if "server_url" in config:
1255
+ assert (
1256
+ config["server_url"] == server_url
1257
+ ), "server_url in config does not match the server_url in the url"
1258
+ config["server_url"] = server_url
1259
+ return ServerContextManager(config, service_id=full_service_id)
1260
+
1261
+
1154
1262
  def setup_local_client(enable_execution=False, on_ready=None):
1155
1263
  """Set up a local client."""
1156
1264
  fut = safe_create_future()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hypha_rpc
3
- Version: 0.20.91
3
+ Version: 0.20.93
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
@@ -1,20 +1,19 @@
1
- hypha_rpc/VERSION,sha256=j1kFO_lywKnDlLe-woiBFEziTNuwai-qeVyGIhLgkhY,26
2
- hypha_rpc/__init__.py,sha256=Nm01vho0uIMXET8-lqxaWTRgoKQD-0SEhpmS9odRed0,4721
3
- hypha_rpc/client.py,sha256=9c3Qd1bboNiEc_5P4jRLi233VFHyyME8alZYZ5ZZq6s,4551
4
- hypha_rpc/http_client.py,sha256=z1fbomvF9wk7ZxFmzfw8qnheE_ueXrg1C4c8Ss5hgWU,23545
1
+ hypha_rpc/VERSION,sha256=oQt6CaFAJvGH-g-tZewKKFq1_1EOjSExWvGzeFGpmac,26
2
+ hypha_rpc/__init__.py,sha256=kWNHbAl-a0RhgKgWm5r0cvs-qd1ujlpmPbXV_0QWuQQ,4727
3
+ hypha_rpc/http_client.py,sha256=9ni8yx_2ZwJ5ibhN4tD8EMtfmvzTEm4UcRRggJ8pnRY,24307
5
4
  hypha_rpc/pyodide_sse.py,sha256=o1-6Bqb7bcplSy7pwkmtQb6vKeJsyxex_RebqNd3wX8,2960
6
5
  hypha_rpc/pyodide_websocket.py,sha256=XjrgKYySUSNYma-rXjHrSv08YCxj5t4hYEQnK15D6cE,18749
7
6
  hypha_rpc/rpc.py,sha256=lnNiPAm_BNT5JjDhAPFRlxs6HioXw77TelUtYd_blYk,115579
8
7
  hypha_rpc/sync.py,sha256=HcQwpGHsZjDNcSnDRuyxGu7bquOi5_jWrVL5vTwraZY,12268
9
8
  hypha_rpc/webrtc_client.py,sha256=JVbSTWr6Y6vMaeoAPsfecD2SuCtXOuoBVuhpwG5-Qm0,11944
10
- hypha_rpc/websocket_client.py,sha256=haH-SKxaAWNnest3doBVhp7H5XlgqVFjFOW-KnFqxPo,48914
9
+ hypha_rpc/websocket_client.py,sha256=tk8mID_zd0SaKTnwCHMTDIIeWvmatDbr5LHXbo6WwJ8,52920
11
10
  hypha_rpc/utils/__init__.py,sha256=1UWExsUWzNRFkuYa7RSDXH3welrelIxOmGLtzdJ2oIA,20042
12
11
  hypha_rpc/utils/launch.py,sha256=GB1Ranb5E_oNFBLw2ARfT78SbqGEwUmWwfMo3E82kAM,3976
13
12
  hypha_rpc/utils/mcp.py,sha256=AW48yjCovc0jyekRLeD_1U8mRaA8-nEqh4DotSE_s3Y,17348
14
13
  hypha_rpc/utils/pydantic.py,sha256=a09_ys4BSXc4Yi6OgZjdspbtLvQVoRCChr6uInY4fN4,5144
15
14
  hypha_rpc/utils/schema.py,sha256=WabBJiDheMKRXUroVe9JRlI5P4Wlv6kc0roxVNQZHH8,22110
16
15
  hypha_rpc/utils/serve.py,sha256=xr_3oAQDyignQbz1fcm4kuRMBOb52-i0VSYCjZou51c,11882
17
- hypha_rpc-0.20.91.dist-info/METADATA,sha256=rIb0SqctYBNrj2IrRKSUBj2UBhAP1VFFECVRsScmAeg,924
18
- hypha_rpc-0.20.91.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
19
- hypha_rpc-0.20.91.dist-info/top_level.txt,sha256=uShPbaPGP-Ig8OVnQcT6sEzV0Qhb6wfxSJ3uCmYaB58,10
20
- hypha_rpc-0.20.91.dist-info/RECORD,,
16
+ hypha_rpc-0.20.93.dist-info/METADATA,sha256=HHPwYXpCX8PcZFYANkT5KTuDUPQ3S6-c_i2OCyIY2BI,924
17
+ hypha_rpc-0.20.93.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
18
+ hypha_rpc-0.20.93.dist-info/top_level.txt,sha256=uShPbaPGP-Ig8OVnQcT6sEzV0Qhb6wfxSJ3uCmYaB58,10
19
+ hypha_rpc-0.20.93.dist-info/RECORD,,
hypha_rpc/client.py DELETED
@@ -1,123 +0,0 @@
1
- """Hypha RPC client - unified connection interface.
2
-
3
- This module provides the main entry point for connecting to Hypha servers.
4
- It supports multiple transport types:
5
- - "websocket" (default): Traditional WebSocket connection
6
- - "http": HTTP streaming connection (more resilient to network issues)
7
- """
8
-
9
- import os
10
- from .utils import parse_service_url
11
-
12
-
13
- class ServerContextManager:
14
- """Server context manager.
15
-
16
- Supports multiple transport types:
17
- - "websocket" (default): Traditional WebSocket connection
18
- - "http": HTTP streaming connection (more resilient to network issues)
19
- """
20
-
21
- def __init__(self, config=None, service_id=None, **kwargs):
22
- self.config = config or {}
23
- self.config.update(kwargs)
24
-
25
- if not self.config:
26
- # try to load from env
27
- if not os.environ.get("HYPHA_SERVER_URL"):
28
- try:
29
- from dotenv import load_dotenv, find_dotenv
30
- load_dotenv(dotenv_path=find_dotenv(usecwd=True))
31
- # use info from .env file
32
- print("✅ Loaded connection configuration from .env file.")
33
- except ImportError:
34
- pass
35
- self.config = {
36
- "server_url": os.getenv("HYPHA_SERVER_URL"),
37
- "token": os.getenv("HYPHA_TOKEN"),
38
- "client_id": os.getenv("HYPHA_CLIENT_ID"),
39
- "workspace": os.getenv("HYPHA_WORKSPACE"),
40
- }
41
- if not self.config["server_url"]:
42
- raise ValueError(
43
- "Please set the HYPHA_SERVER_URL, HYPHA_TOKEN, "
44
- "HYPHA_CLIENT_ID, and HYPHA_WORKSPACE environment variables"
45
- )
46
- self._service_id = service_id
47
- self._transport = self.config.pop("transport", "websocket")
48
- self.wm = None
49
-
50
- async def __aenter__(self):
51
- if self._transport == "http":
52
- from .http_client import _connect_to_server_http
53
- self.wm = await _connect_to_server_http(self.config)
54
- else:
55
- from .websocket_client import _connect_to_server
56
- self.wm = await _connect_to_server(self.config)
57
- if self._service_id:
58
- return await self.wm.get_service(
59
- self._service_id,
60
- {"case_conversion": self.config.get("case_conversion")},
61
- )
62
- return self.wm
63
-
64
- async def __aexit__(self, exc_type, exc, tb):
65
- await self.wm.disconnect()
66
-
67
- def __await__(self):
68
- return self.__aenter__().__await__()
69
-
70
-
71
- def connect_to_server(config=None, **kwargs):
72
- """Connect to a Hypha server.
73
-
74
- Args:
75
- config: Configuration dict with connection options
76
- **kwargs: Additional configuration options
77
-
78
- Configuration options:
79
- server_url: The server URL (required)
80
- workspace: Target workspace (optional)
81
- token: Authentication token (optional)
82
- client_id: Unique client identifier (optional, auto-generated if not provided)
83
- transport: Transport type - "websocket" (default) or "http"
84
- method_timeout: Timeout for RPC method calls
85
- ssl: SSL configuration (True/False/SSLContext)
86
-
87
- Returns:
88
- ServerContextManager that can be used as async context manager
89
-
90
- Example:
91
- async with connect_to_server({"server_url": "https://hypha.aicell.io"}) as server:
92
- await server.register_service({"id": "my-service", ...})
93
- """
94
- return ServerContextManager(config=config, **kwargs)
95
-
96
-
97
- def get_remote_service(service_uri, config=None, **kwargs):
98
- """Get a remote service by URI.
99
-
100
- Args:
101
- service_uri: Service URI in format "server_url/workspace/client_id:service_id"
102
- config: Additional configuration options
103
- **kwargs: Additional configuration options
104
-
105
- Returns:
106
- ServerContextManager that resolves to the service when awaited
107
-
108
- Example:
109
- async with get_remote_service("https://hypha.aicell.io/public/client:service") as svc:
110
- result = await svc.some_method()
111
- """
112
- server_url, workspace, client_id, service_id, app_id = parse_service_url(
113
- service_uri
114
- )
115
- full_service_id = f"{workspace}/{client_id}:{service_id}@{app_id}"
116
- config = config or {}
117
- config.update(kwargs)
118
- if "server_url" in config:
119
- assert (
120
- config["server_url"] == server_url
121
- ), "server_url in config does not match the server_url in the url"
122
- config["server_url"] = server_url
123
- return ServerContextManager(config, service_id=full_service_id)