ephaptic 0.2.1__py3-none-any.whl → 0.2.2__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.
ephaptic/ephaptic.py CHANGED
@@ -51,9 +51,12 @@ class ConnectionManager:
51
51
  for user_id in user_ids:
52
52
  if user_id in self.active:
53
53
  for transport in list(self.active[user_id]):
54
- try:
55
- await transport.send(payload)
56
- except: pass
54
+ asyncio.create_task(self._safe_send(transport, payload))
55
+
56
+ async def _safe_send(self, transport: Transport, payload: bytes):
57
+ try:
58
+ await transport.send(payload)
59
+ except: ...
57
60
 
58
61
  async def start_redis(self):
59
62
  if not self.redis: return
@@ -192,7 +195,7 @@ class Ephaptic:
192
195
 
193
196
  if func_name in self._exposed_functions:
194
197
  target_func = self._exposed_functions[func_name]
195
- sig = inspect.signature(target_func)
198
+ sig = inspect.signature(target_func)
196
199
  try:
197
200
  bound = sig.bind(*args, **kwargs)
198
201
  bound.apply_defaults()
@@ -202,6 +205,8 @@ class Ephaptic:
202
205
 
203
206
  hints = typing.get_type_hints(target_func)
204
207
 
208
+ return_type = hints.get("return", typing.Any)
209
+
205
210
  errors = []
206
211
 
207
212
  for name, val in bound.arguments.items():
@@ -216,7 +221,11 @@ class Ephaptic:
216
221
  if errors:
217
222
  await transport.send(msgpack.dumps({
218
223
  "id": call_id,
219
- "error": errors,
224
+ "error": {
225
+ "code": "VALIDATION_ERROR",
226
+ "message": "Validation failed.",
227
+ "data": errors,
228
+ },
220
229
  }))
221
230
  continue
222
231
 
@@ -225,9 +234,21 @@ class Ephaptic:
225
234
 
226
235
  try:
227
236
  result = await self._async(target_func)(**bound.arguments)
228
- if isinstance(result, pydantic.BaseModel):
229
- result = result.model_dump()
237
+
238
+ if return_type is not inspect.Signature.empty:
239
+ try:
240
+ adapter = pydantic.TypeAdapter(return_type)
241
+ validated = adapter.validate_python(result, from_attributes=True)
242
+ result = adapter.dump_python(validated, mode='json')
243
+ except: ...
244
+ elif isinstance(result, pydantic.BaseModel):
245
+ result = result.model_dump(mode='json')
246
+
230
247
  await transport.send(msgpack.dumps({"id": call_id, "result": result}))
248
+ # except pydantic.ValidationError as e:
249
+ # Should we really treat this separately?
250
+ # For input it's understandable, but for server responses it feels like a server issue.
251
+ # Ok, let's treat this like any other server error.
231
252
  except Exception as e:
232
253
  await transport.send(msgpack.dumps({"id": call_id, "error": str(e)}))
233
254
  finally:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ephaptic
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: The Python client/server package for ephaptic.
5
5
  Author-email: uukelele <robustrobot11@gmail.com>
6
6
  License: MIT License
@@ -132,8 +132,7 @@ async def add(num1: int, num2: int) -> int:
132
132
  return num1 + num2
133
133
  ```
134
134
 
135
- > [!TIP]
136
- > If you're experiencing circular imports, feel free to instead import and use the `expose` function from the library instead of the instance. Please note that if you do this, you must define all exposed functions *before* creating the ephaptic instance - this is mainly for people importing RPC functions from another file. The same thing can be done with the global `identity_loader` decorator.
135
+ ###### If you're trying to expose functions statelessly, e.g. in a different file, feel free to instead import and use the `expose` function from the library instead of the instance. Please note that if you do this, you must define all exposed functions *before* creating the ephaptic instance - easily done by simply placing your import line above the ephaptic constructor. The same thing can be done with the global `identity_loader` decorator.
137
136
 
138
137
  Yep, it's really that simple.
139
138
 
@@ -1,5 +1,5 @@
1
1
  ephaptic/__init__.py,sha256=3GmVqhbye3snH7KfnyqIt8t_w6ULnWOvDw07eB13iDA,126
2
- ephaptic/ephaptic.py,sha256=K9cOUk8guI6IesBACkdUxebI2UXpN-0yJfrhjHUC3iI,9034
2
+ ephaptic/ephaptic.py,sha256=9PKqiUKWl5MWlBvqsVbpsEfBmJmZJFes0RbbeqFkX4I,10224
3
3
  ephaptic/localproxy.py,sha256=fJaaskkiD6C2zaOod0F0HNWIbdKs_JMuHFwd0-sdLIM,19477
4
4
  ephaptic/adapters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  ephaptic/adapters/fastapi_.py,sha256=yfSbJuA7Tgeh9EhZkfIve0Uj-cOZmTBljlBsCRKh2EE,1007
@@ -11,9 +11,9 @@ ephaptic/client/client.py,sha256=YYAlzA40xBvWsiDu0Gsd1EBJaqivLR-bSszepWdNODs,418
11
11
  ephaptic/transports/__init__.py,sha256=kSAlgvm8sV9nHHu61LTjjTpv4bweah90xvFrwQMDQtQ,169
12
12
  ephaptic/transports/fastapi_ws.py,sha256=X0PMRcwM-KDpKA-zXShGTFhD1kHMSqrx3PBBKZtQ1W0,258
13
13
  ephaptic/transports/websocket.py,sha256=jwgclSDSq0lQCvgwjwUXe9MzPk7NH0FdmsLhWxYBh-4,261
14
- ephaptic-0.2.1.dist-info/licenses/LICENSE,sha256=kMpJjLKMj6zsAhf4uHApO4q0r31Ye1VyfBOl9cFW13M,1065
15
- ephaptic-0.2.1.dist-info/METADATA,sha256=9-6m-C21Y01fry6UHDGoQ-2LtUqYpI_rOxJZv_fzaGM,7716
16
- ephaptic-0.2.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
- ephaptic-0.2.1.dist-info/entry_points.txt,sha256=lis9vIDIrMVJM43r9ooFkb07KhrX4946duvYru3VfT4,46
18
- ephaptic-0.2.1.dist-info/top_level.txt,sha256=nNhdhcz2o_IuwZ9I2uWQuLZrRmSW0dQVU3qwGrb35Io,9
19
- ephaptic-0.2.1.dist-info/RECORD,,
14
+ ephaptic-0.2.2.dist-info/licenses/LICENSE,sha256=kMpJjLKMj6zsAhf4uHApO4q0r31Ye1VyfBOl9cFW13M,1065
15
+ ephaptic-0.2.2.dist-info/METADATA,sha256=FvhGA1GURxKF9pygzB9SQ7uuKaDCYq3mxQ6UfLMpZIg,7757
16
+ ephaptic-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
17
+ ephaptic-0.2.2.dist-info/entry_points.txt,sha256=lis9vIDIrMVJM43r9ooFkb07KhrX4946duvYru3VfT4,46
18
+ ephaptic-0.2.2.dist-info/top_level.txt,sha256=nNhdhcz2o_IuwZ9I2uWQuLZrRmSW0dQVU3qwGrb35Io,9
19
+ ephaptic-0.2.2.dist-info/RECORD,,