pydantic-rpc 0.2.1__tar.gz → 0.2.2__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 (45) hide show
  1. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/PKG-INFO +1 -1
  2. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/agent_aio_grpc.py +11 -0
  3. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/agent_connecpy.py +11 -0
  4. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/pyproject.toml +1 -1
  5. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/src/pydantic_rpc/core.py +65 -35
  6. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/.gitignore +0 -0
  7. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/.python-version +0 -0
  8. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/LICENSE +0 -0
  9. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/README.md +0 -0
  10. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/README.md +0 -0
  11. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/asyncio_greeting.py +0 -0
  12. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/barservice.proto +0 -0
  13. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/barservice_pb2.py +0 -0
  14. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/barservice_pb2.pyi +0 -0
  15. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/barservice_pb2_grpc.py +0 -0
  16. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/foobar.py +0 -0
  17. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/foobar_client.py +0 -0
  18. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/fooservice.proto +0 -0
  19. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/fooservice_pb2.py +0 -0
  20. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/fooservice_pb2.pyi +0 -0
  21. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/fooservice_pb2_grpc.py +0 -0
  22. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/google/protobuf/duration.proto +0 -0
  23. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/google/protobuf/timestamp.proto +0 -0
  24. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter.proto +0 -0
  25. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_client.py +0 -0
  26. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_connecpy.py +0 -0
  27. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_connecpy_client.py +0 -0
  28. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_pb2.py +0 -0
  29. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_pb2.pyi +0 -0
  30. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_pb2_grpc.py +0 -0
  31. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeter_sonora_client.py +0 -0
  32. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeting.py +0 -0
  33. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeting_asgi.py +0 -0
  34. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeting_connecpy.py +0 -0
  35. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeting_using_exsiting_pb2_modules.py +0 -0
  36. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/greeting_wsgi.py +0 -0
  37. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/olympicslocationagent.proto +0 -0
  38. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/olympicslocationagent_connecpy.py +0 -0
  39. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/olympicslocationagent_pb2.py +0 -0
  40. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/olympicslocationagent_pb2.pyi +0 -0
  41. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/examples/olympicslocationagent_pb2_grpc.py +0 -0
  42. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/requirements-dev.lock +0 -0
  43. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/requirements.lock +0 -0
  44. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/src/pydantic_rpc/__init__.py +0 -0
  45. {pydantic_rpc-0.2.1 → pydantic_rpc-0.2.2}/src/pydantic_rpc/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: pydantic-rpc
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: A Python library for building gRPC/ConnectRPC services with Pydantic models.
5
5
  Author: Yasushi Itoh
6
6
  Requires-Python: >=3.11
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
 
3
+ from pydantic import field_validator
3
4
  from pydantic_ai import Agent
4
5
  from pydantic_rpc import AsyncIOServer, Message
5
6
 
@@ -16,6 +17,16 @@ class Olympics(Message):
16
17
  def prompt(self):
17
18
  return f"Where were the Olympics held in {self.year}?"
18
19
 
20
+ @field_validator("year")
21
+ def validate_year(cls, value):
22
+ if value < 1896:
23
+ raise ValueError("The first modern Olympics was held in 1896.")
24
+
25
+ if value % 4 != 0:
26
+ raise ValueError("The Olympics are held every 4 years.")
27
+
28
+ return value
29
+
19
30
 
20
31
  class OlympicsLocationAgent:
21
32
  def __init__(self):
@@ -2,6 +2,7 @@ import asyncio
2
2
 
3
3
  from hypercorn.asyncio import serve
4
4
  from hypercorn.config import Config
5
+ from pydantic import field_validator
5
6
  from pydantic_ai import Agent
6
7
  from pydantic_rpc import ConnecpyASGIApp, Message
7
8
 
@@ -17,6 +18,16 @@ class Olympics(Message):
17
18
  def prompt(self):
18
19
  return f"Where were the Olympics held in {self.year}?"
19
20
 
21
+ @field_validator("year")
22
+ def validate_year(cls, value):
23
+ if value < 1896:
24
+ raise ValueError("The first modern Olympics was held in 1896.")
25
+
26
+ if value % 4 != 0:
27
+ raise ValueError("The Olympics are held every 4 years.")
28
+
29
+ return value
30
+
20
31
 
21
32
  class OlympicsLocationAgent:
22
33
  def __init__(self):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "pydantic-rpc"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "A Python library for building gRPC/ConnectRPC services with Pydantic models."
5
5
  authors = [
6
6
  { name = "Yasushi Itoh" }
@@ -24,10 +24,11 @@ from grpc_health.v1 import health_pb2, health_pb2_grpc
24
24
  from grpc_health.v1.health import HealthServicer
25
25
  from grpc_reflection.v1alpha import reflection
26
26
  from grpc_tools import protoc
27
- from pydantic import BaseModel
27
+ from pydantic import BaseModel, ValidationError
28
28
  from sonora.wsgi import grpcWSGI
29
29
  from sonora.asgi import grpcASGI
30
30
  from connecpy.asgi import ConnecpyASGIApp as ConnecpyASGI
31
+ from connecpy.errors import Errors
31
32
 
32
33
  # Protobuf Python modules for Timestamp, Duration (requires protobuf / grpcio)
33
34
  from google.protobuf import timestamp_pb2, duration_pb2
@@ -198,25 +199,35 @@ def connect_obj_with_stub(pb2_grpc_module, pb2_module, service_obj: object) -> t
198
199
  case 1:
199
200
 
200
201
  def stub_method1(self, request, context, method=method):
201
- # Convert request to Python object
202
- arg = converter(request)
203
- # Invoke the actual method
204
- resp_obj = method(arg)
205
- # Convert the returned Python Message to a protobuf message
206
- return convert_python_message_to_proto(
207
- resp_obj, response_type, pb2_module
208
- )
202
+ try:
203
+ # Convert request to Python object
204
+ arg = converter(request)
205
+ # Invoke the actual method
206
+ resp_obj = method(arg)
207
+ # Convert the returned Python Message to a protobuf message
208
+ return convert_python_message_to_proto(
209
+ resp_obj, response_type, pb2_module
210
+ )
211
+ except ValidationError as e:
212
+ return context.abort(grpc.StatusCode.INVALID_ARGUMENT, str(e))
213
+ except Exception as e:
214
+ return context.abort(grpc.StatusCode.INTERNAL, str(e))
209
215
 
210
216
  return stub_method1
211
217
 
212
218
  case 2:
213
219
 
214
220
  def stub_method2(self, request, context, method=method):
215
- arg = converter(request)
216
- resp_obj = method(arg, context)
217
- return convert_python_message_to_proto(
218
- resp_obj, response_type, pb2_module
219
- )
221
+ try:
222
+ arg = converter(request)
223
+ resp_obj = method(arg, context)
224
+ return convert_python_message_to_proto(
225
+ resp_obj, response_type, pb2_module
226
+ )
227
+ except ValidationError as e:
228
+ return context.abort(grpc.StatusCode.INVALID_ARGUMENT, str(e))
229
+ except Exception as e:
230
+ return context.abort(grpc.StatusCode.INTERNAL, str(e))
220
231
 
221
232
  return stub_method2
222
233
 
@@ -255,22 +266,32 @@ def connect_obj_with_stub_async(pb2_grpc_module, pb2_module, obj: object) -> typ
255
266
  case 1:
256
267
 
257
268
  async def stub_method1(self, request, context, method=method):
258
- arg = converter(request)
259
- resp_obj = await method(arg)
260
- return convert_python_message_to_proto(
261
- resp_obj, response_type, pb2_module
262
- )
269
+ try:
270
+ arg = converter(request)
271
+ resp_obj = await method(arg)
272
+ return convert_python_message_to_proto(
273
+ resp_obj, response_type, pb2_module
274
+ )
275
+ except ValidationError as e:
276
+ await context.abort(grpc.StatusCode.INVALID_ARGUMENT, str(e))
277
+ except Exception as e:
278
+ await context.abort(grpc.StatusCode.INTERNAL, str(e))
263
279
 
264
280
  return stub_method1
265
281
 
266
282
  case 2:
267
283
 
268
284
  async def stub_method2(self, request, context, method=method):
269
- arg = converter(request)
270
- resp_obj = await method(arg, context)
271
- return convert_python_message_to_proto(
272
- resp_obj, response_type, pb2_module
273
- )
285
+ try:
286
+ arg = converter(request)
287
+ resp_obj = await method(arg, context)
288
+ return convert_python_message_to_proto(
289
+ resp_obj, response_type, pb2_module
290
+ )
291
+ except ValidationError as e:
292
+ await context.abort(grpc.StatusCode.INVALID_ARGUMENT, str(e))
293
+ except Exception as e:
294
+ await context.abort(grpc.StatusCode.INTERNAL, str(e))
274
295
 
275
296
  return stub_method2
276
297
 
@@ -302,7 +323,6 @@ def connect_obj_with_stub_async_connecpy(
302
323
 
303
324
  def implement_stub_method(method):
304
325
  sig = inspect.signature(method)
305
- print(type(method))
306
326
  arg_type = get_request_arg_type(sig)
307
327
  converter = generate_message_converter(arg_type)
308
328
  response_type = sig.return_annotation
@@ -312,22 +332,32 @@ def connect_obj_with_stub_async_connecpy(
312
332
  case 1:
313
333
 
314
334
  async def stub_method1(self, request, context, method=method):
315
- arg = converter(request)
316
- resp_obj = await method(arg)
317
- return convert_python_message_to_proto(
318
- resp_obj, response_type, pb2_module
319
- )
335
+ try:
336
+ arg = converter(request)
337
+ resp_obj = await method(arg)
338
+ return convert_python_message_to_proto(
339
+ resp_obj, response_type, pb2_module
340
+ )
341
+ except ValidationError as e:
342
+ await context.abort(Errors.InvalidArgument, str(e))
343
+ except Exception as e:
344
+ await context.abort(Errors.Internal, str(e))
320
345
 
321
346
  return stub_method1
322
347
 
323
348
  case 2:
324
349
 
325
350
  async def stub_method2(self, request, context, method=method):
326
- arg = converter(request)
327
- resp_obj = await method(arg, context)
328
- return convert_python_message_to_proto(
329
- resp_obj, response_type, pb2_module
330
- )
351
+ try:
352
+ arg = converter(request)
353
+ resp_obj = await method(arg, context)
354
+ return convert_python_message_to_proto(
355
+ resp_obj, response_type, pb2_module
356
+ )
357
+ except ValidationError as e:
358
+ await context.abort(Errors.InvalidArgument, str(e))
359
+ except Exception as e:
360
+ await context.abort(Errors.Internal, str(e))
331
361
 
332
362
  return stub_method2
333
363
 
File without changes
File without changes
File without changes