pydantic-rpc 0.5.0__tar.gz → 0.6.1__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 (59) hide show
  1. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/PKG-INFO +337 -8
  2. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/README.md +335 -6
  3. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/README.md +1 -1
  4. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/agent_aio_grpc.py +11 -8
  5. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/agent_connecpy.py +11 -8
  6. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_connecpy.py +30 -0
  7. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeting_connecpy.py +44 -46
  8. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicslocationagent_connecpy.py +30 -0
  9. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/pyproject.toml +10 -3
  10. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/src/pydantic_rpc/core.py +108 -1
  11. pydantic_rpc-0.6.1/tests/asyncechoservice.proto +33 -0
  12. pydantic_rpc-0.6.1/tests/asyncechoservice_connecpy.py +109 -0
  13. pydantic_rpc-0.6.1/tests/asyncechoservice_pb2.py +37 -0
  14. pydantic_rpc-0.6.1/tests/asyncechoservice_pb2.pyi +17 -0
  15. pydantic_rpc-0.6.1/tests/asyncechoservice_pb2_grpc.py +121 -0
  16. pydantic_rpc-0.6.1/tests/echoservice.proto +33 -0
  17. pydantic_rpc-0.6.1/tests/echoservice_connecpy.py +109 -0
  18. pydantic_rpc-0.6.1/tests/echoservice_pb2.py +37 -0
  19. pydantic_rpc-0.6.1/tests/echoservice_pb2.pyi +17 -0
  20. pydantic_rpc-0.6.1/tests/echoservice_pb2_grpc.py +119 -0
  21. pydantic_rpc-0.6.1/tests/test_apps.py +190 -0
  22. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/uv.lock +69 -19
  23. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/.gitignore +0 -0
  24. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/.python-version +0 -0
  25. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/LICENSE +0 -0
  26. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/asyncio_greeting.py +0 -0
  27. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/barservice.proto +0 -0
  28. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/barservice_pb2.py +0 -0
  29. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/barservice_pb2.pyi +0 -0
  30. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/barservice_pb2_grpc.py +0 -0
  31. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/foobar.py +0 -0
  32. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/foobar_client.py +0 -0
  33. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/fooservice.proto +0 -0
  34. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/fooservice_pb2.py +0 -0
  35. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/fooservice_pb2.pyi +0 -0
  36. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/fooservice_pb2_grpc.py +0 -0
  37. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/google/protobuf/duration.proto +0 -0
  38. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/google/protobuf/timestamp.proto +0 -0
  39. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter.proto +0 -0
  40. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_client.py +0 -0
  41. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_connecpy_client.py +0 -0
  42. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_pb2.py +0 -0
  43. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_pb2.pyi +0 -0
  44. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_pb2_grpc.py +0 -0
  45. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeter_sonora_client.py +0 -0
  46. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeting.py +0 -0
  47. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeting_asgi.py +0 -0
  48. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeting_using_exsiting_pb2_modules.py +0 -0
  49. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/greeting_wsgi.py +0 -0
  50. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicsagent.proto +0 -0
  51. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicsagent_pb2.py +0 -0
  52. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicsagent_pb2.pyi +0 -0
  53. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicsagent_pb2_grpc.py +0 -0
  54. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicslocationagent.proto +0 -0
  55. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicslocationagent_pb2.py +0 -0
  56. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicslocationagent_pb2.pyi +0 -0
  57. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/examples/olympicslocationagent_pb2_grpc.py +0 -0
  58. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/src/pydantic_rpc/__init__.py +0 -0
  59. {pydantic_rpc-0.5.0 → pydantic_rpc-0.6.1}/src/pydantic_rpc/py.typed +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydantic-rpc
3
- Version: 0.5.0
3
+ Version: 0.6.1
4
4
  Summary: A Python library for building gRPC/ConnectRPC services with Pydantic models.
5
5
  Author: Yasushi Itoh
6
6
  License-File: LICENSE
7
7
  Requires-Python: >=3.11
8
- Requires-Dist: connecpy>=1.2.1
8
+ Requires-Dist: connecpy>=1.4.1
9
9
  Requires-Dist: grpcio-health-checking>=1.56.2
10
10
  Requires-Dist: grpcio-reflection>=1.56.2
11
11
  Requires-Dist: grpcio-tools>=1.56.2
@@ -23,7 +23,9 @@ Below is an example of a simple gRPC service that exposes a [PydanticAI](https:/
23
23
  ```python
24
24
  import asyncio
25
25
 
26
+ from openai import AsyncOpenAI
26
27
  from pydantic_ai import Agent
28
+ from pydantic_ai.models.openai import OpenAIModel
27
29
  from pydantic_rpc import AsyncIOServer, Message
28
30
 
29
31
 
@@ -42,7 +44,15 @@ class Olympics(Message):
42
44
 
43
45
  class OlympicsLocationAgent:
44
46
  def __init__(self):
45
- self._agent = Agent("ollama:llama3.2", result_type=CityLocation)
47
+ client = AsyncOpenAI(
48
+ base_url="http://localhost:11434/v1",
49
+ api_key="ollama_api_key",
50
+ )
51
+ ollama_model = OpenAIModel(
52
+ model_name="llama3.2",
53
+ openai_client=client,
54
+ )
55
+ self._agent = Agent(ollama_model)
46
56
 
47
57
  async def ask(self, req: Olympics) -> CityLocation:
48
58
  result = await self._agent.run(req.prompt())
@@ -60,7 +70,9 @@ And here is an example of a simple Connect RPC service that exposes the same age
60
70
  ```python
61
71
  import asyncio
62
72
 
73
+ from openai import AsyncOpenAI
63
74
  from pydantic_ai import Agent
75
+ from pydantic_ai.models.openai import OpenAIModel
64
76
  from pydantic_rpc import ConnecpyASGIApp, Message
65
77
 
66
78
 
@@ -78,7 +90,15 @@ class Olympics(Message):
78
90
 
79
91
  class OlympicsLocationAgent:
80
92
  def __init__(self):
81
- self._agent = Agent("ollama:llama3.2", result_type=CityLocation)
93
+ client = AsyncOpenAI(
94
+ base_url="http://localhost:11434/v1",
95
+ api_key="ollama_api_key",
96
+ )
97
+ ollama_model = OpenAIModel(
98
+ model_name="llama3.2",
99
+ openai_client=client,
100
+ )
101
+ self._agent = Agent(ollama_model, result_type=CityLocation)
82
102
 
83
103
  async def ask(self, req: Olympics) -> CityLocation:
84
104
  result = await self._agent.run(req.prompt())
@@ -104,6 +124,7 @@ app.mount(OlympicsLocationAgent())
104
124
  - 🌐 **WSGI/ASGI Support:** Create gRPC-Web services that can run as WSGI or ASGI applications powered by `Sonora`.
105
125
  - **For Connect-RPC:**
106
126
  - 🌐 **Connecpy Support:** Partially supports Connect-RPC via `Connecpy`.
127
+ - 🛠️ **Pre-generated Protobuf Files and Code:** Pre-generate proto files and corresponding code via the CLI. By setting the environment variable (PYDANTIC_RPC_SKIP_GENERATION), you can skip runtime generation.
107
128
 
108
129
  ## 📦 Installation
109
130
 
@@ -257,7 +278,9 @@ When this variable is set to "true", PydanticRPC will load existing pre-generate
257
278
  ## 💎 Advanced Features
258
279
 
259
280
  ### 🌊 Response Streaming
260
- PydanticRPC supports streaming for responses in asynchronous gRPC and gRPC-Web services only.
281
+ PydanticRPC supports streaming responses only for asynchronous gRPC and gRPC-Web services.
282
+ If a service class method’s return type is `typing.AsyncIterator[T]`, the method is considered a streaming method.
283
+
261
284
 
262
285
  Please see the sample code below:
263
286
 
@@ -265,8 +288,10 @@ Please see the sample code below:
265
288
  import asyncio
266
289
  from typing import Annotated, AsyncIterator
267
290
 
291
+ from openai import AsyncOpenAI
268
292
  from pydantic import Field
269
293
  from pydantic_ai import Agent
294
+ from pydantic_ai.models.openai import OpenAIModel
270
295
  from pydantic_rpc import AsyncIOServer, Message
271
296
 
272
297
 
@@ -299,7 +324,15 @@ class StreamingResult(Message):
299
324
 
300
325
  class OlympicsAgent:
301
326
  def __init__(self):
302
- self._agent = Agent("ollama:llama3.2")
327
+ client = AsyncOpenAI(
328
+ base_url='http://localhost:11434/v1',
329
+ api_key='ollama_api_key',
330
+ )
331
+ ollama_model = OpenAIModel(
332
+ model_name='llama3.2',
333
+ openai_client=client,
334
+ )
335
+ self._agent = Agent(ollama_model)
303
336
 
304
337
  async def ask(self, req: OlympicsQuery) -> CityLocation:
305
338
  result = await self._agent.run(req.prompt(), result_type=CityLocation)
@@ -319,6 +352,302 @@ if __name__ == "__main__":
319
352
  loop.run_until_complete(s.run(OlympicsAgent()))
320
353
  ```
321
354
 
355
+ In the example above, the `ask_stream` method returns an `AsyncIterator[StreamingResult]` object, which is considered a streaming method. The `StreamingResult` class is a Pydantic model that defines the response type of the streaming method. You can use any Pydantic model as the response type.
356
+
357
+ Now, you can call the `ask_stream` method of the server described above using your preferred gRPC client tool. The example below uses `buf curl`.
358
+
359
+
360
+ ```console
361
+ % buf curl --data '{"start": 1980, "end": 2024}' -v http://localhost:50051/olympicsagent.v1.OlympicsAgent/AskStream --protocol grpc --http2-prior-knowledge
362
+
363
+ buf: * Using server reflection to resolve "olympicsagent.v1.OlympicsAgent"
364
+ buf: * Dialing (tcp) localhost:50051...
365
+ buf: * Connected to [::1]:50051
366
+ buf: > (#1) POST /grpc.reflection.v1.ServerReflection/ServerReflectionInfo
367
+ buf: > (#1) Accept-Encoding: identity
368
+ buf: > (#1) Content-Type: application/grpc+proto
369
+ buf: > (#1) Grpc-Accept-Encoding: gzip
370
+ buf: > (#1) Grpc-Timeout: 119997m
371
+ buf: > (#1) Te: trailers
372
+ buf: > (#1) User-Agent: grpc-go-connect/1.12.0 (go1.21.4) buf/1.28.1
373
+ buf: > (#1)
374
+ buf: } (#1) [5 bytes data]
375
+ buf: } (#1) [32 bytes data]
376
+ buf: < (#1) HTTP/2.0 200 OK
377
+ buf: < (#1) Content-Type: application/grpc
378
+ buf: < (#1) Grpc-Message: Method not found!
379
+ buf: < (#1) Grpc-Status: 12
380
+ buf: < (#1)
381
+ buf: * (#1) Call complete
382
+ buf: > (#2) POST /grpc.reflection.v1alpha.ServerReflection/ServerReflectionInfo
383
+ buf: > (#2) Accept-Encoding: identity
384
+ buf: > (#2) Content-Type: application/grpc+proto
385
+ buf: > (#2) Grpc-Accept-Encoding: gzip
386
+ buf: > (#2) Grpc-Timeout: 119967m
387
+ buf: > (#2) Te: trailers
388
+ buf: > (#2) User-Agent: grpc-go-connect/1.12.0 (go1.21.4) buf/1.28.1
389
+ buf: > (#2)
390
+ buf: } (#2) [5 bytes data]
391
+ buf: } (#2) [32 bytes data]
392
+ buf: < (#2) HTTP/2.0 200 OK
393
+ buf: < (#2) Content-Type: application/grpc
394
+ buf: < (#2) Grpc-Accept-Encoding: identity, deflate, gzip
395
+ buf: < (#2)
396
+ buf: { (#2) [5 bytes data]
397
+ buf: { (#2) [434 bytes data]
398
+ buf: * Server reflection has resolved file "olympicsagent.proto"
399
+ buf: * Invoking RPC olympicsagent.v1.OlympicsAgent.AskStream
400
+ buf: > (#3) POST /olympicsagent.v1.OlympicsAgent/AskStream
401
+ buf: > (#3) Accept-Encoding: identity
402
+ buf: > (#3) Content-Type: application/grpc+proto
403
+ buf: > (#3) Grpc-Accept-Encoding: gzip
404
+ buf: > (#3) Grpc-Timeout: 119947m
405
+ buf: > (#3) Te: trailers
406
+ buf: > (#3) User-Agent: grpc-go-connect/1.12.0 (go1.21.4) buf/1.28.1
407
+ buf: > (#3)
408
+ buf: } (#3) [5 bytes data]
409
+ buf: } (#3) [6 bytes data]
410
+ buf: * (#3) Finished upload
411
+ buf: < (#3) HTTP/2.0 200 OK
412
+ buf: < (#3) Content-Type: application/grpc
413
+ buf: < (#3) Grpc-Accept-Encoding: identity, deflate, gzip
414
+ buf: < (#3)
415
+ buf: { (#3) [5 bytes data]
416
+ buf: { (#3) [25 bytes data]
417
+ {
418
+ "answer": "Here's a list of Summer"
419
+ }
420
+ buf: { (#3) [5 bytes data]
421
+ buf: { (#3) [31 bytes data]
422
+ {
423
+ "answer": " and Winter Olympics from 198"
424
+ }
425
+ buf: { (#3) [5 bytes data]
426
+ buf: { (#3) [29 bytes data]
427
+ {
428
+ "answer": "0 to 2024:\n\nSummer Olympics"
429
+ }
430
+ buf: { (#3) [5 bytes data]
431
+ buf: { (#3) [20 bytes data]
432
+ {
433
+ "answer": ":\n1. 1980 - Moscow"
434
+ }
435
+ buf: { (#3) [5 bytes data]
436
+ buf: { (#3) [20 bytes data]
437
+ {
438
+ "answer": ", Soviet Union\n2. "
439
+ }
440
+ buf: { (#3) [5 bytes data]
441
+ buf: { (#3) [32 bytes data]
442
+ {
443
+ "answer": "1984 - Los Angeles, California"
444
+ }
445
+ buf: { (#3) [5 bytes data]
446
+ buf: { (#3) [15 bytes data]
447
+ {
448
+ "answer": ", USA\n3. 1988"
449
+ }
450
+ buf: { (#3) [5 bytes data]
451
+ buf: { (#3) [26 bytes data]
452
+ {
453
+ "answer": " - Seoul, South Korea\n4."
454
+ }
455
+ buf: { (#3) [5 bytes data]
456
+ buf: { (#3) [27 bytes data]
457
+ {
458
+ "answer": " 1992 - Barcelona, Spain\n"
459
+ }
460
+ buf: { (#3) [5 bytes data]
461
+ buf: { (#3) [20 bytes data]
462
+ {
463
+ "answer": "5. 1996 - Atlanta,"
464
+ }
465
+ buf: { (#3) [5 bytes data]
466
+ buf: { (#3) [22 bytes data]
467
+ {
468
+ "answer": " Georgia, USA\n6. 200"
469
+ }
470
+ buf: { (#3) [5 bytes data]
471
+ buf: { (#3) [26 bytes data]
472
+ {
473
+ "answer": "0 - Sydney, Australia\n7."
474
+ }
475
+ buf: { (#3) [5 bytes data]
476
+ buf: { (#3) [25 bytes data]
477
+ {
478
+ "answer": " 2004 - Athens, Greece\n"
479
+ }
480
+ buf: { (#3) [5 bytes data]
481
+ buf: { (#3) [20 bytes data]
482
+ {
483
+ "answer": "8. 2008 - Beijing,"
484
+ }
485
+ buf: { (#3) [5 bytes data]
486
+ buf: { (#3) [18 bytes data]
487
+ {
488
+ "answer": " China\n9. 2012 -"
489
+ }
490
+ buf: { (#3) [5 bytes data]
491
+ buf: { (#3) [29 bytes data]
492
+ {
493
+ "answer": " London, United Kingdom\n10."
494
+ }
495
+ buf: { (#3) [5 bytes data]
496
+ buf: { (#3) [24 bytes data]
497
+ {
498
+ "answer": " 2016 - Rio de Janeiro"
499
+ }
500
+ buf: { (#3) [5 bytes data]
501
+ buf: { (#3) [18 bytes data]
502
+ {
503
+ "answer": ", Brazil\n11. 202"
504
+ }
505
+ buf: { (#3) [5 bytes data]
506
+ buf: { (#3) [24 bytes data]
507
+ {
508
+ "answer": "0 - Tokyo, Japan (held"
509
+ }
510
+ buf: { (#3) [5 bytes data]
511
+ buf: { (#3) [21 bytes data]
512
+ {
513
+ "answer": " in 2021 due to the"
514
+ }
515
+ buf: { (#3) [5 bytes data]
516
+ buf: { (#3) [26 bytes data]
517
+ {
518
+ "answer": " COVID-19 pandemic)\n12. "
519
+ }
520
+ buf: { (#3) [5 bytes data]
521
+ buf: { (#3) [28 bytes data]
522
+ {
523
+ "answer": "2024 - Paris, France\n\nNote"
524
+ }
525
+ buf: { (#3) [5 bytes data]
526
+ buf: { (#3) [41 bytes data]
527
+ {
528
+ "answer": ": The Olympics were held without a host"
529
+ }
530
+ buf: { (#3) [5 bytes data]
531
+ buf: { (#3) [26 bytes data]
532
+ {
533
+ "answer": " city for one year (2022"
534
+ }
535
+ buf: { (#3) [5 bytes data]
536
+ buf: { (#3) [42 bytes data]
537
+ {
538
+ "answer": ", due to the Russian invasion of Ukraine"
539
+ }
540
+ buf: { (#3) [5 bytes data]
541
+ buf: { (#3) [29 bytes data]
542
+ {
543
+ "answer": ").\n\nWinter Olympics:\n1. 198"
544
+ }
545
+ buf: { (#3) [5 bytes data]
546
+ buf: { (#3) [27 bytes data]
547
+ {
548
+ "answer": "0 - Lake Placid, New York"
549
+ }
550
+ buf: { (#3) [5 bytes data]
551
+ buf: { (#3) [15 bytes data]
552
+ {
553
+ "answer": ", USA\n2. 1984"
554
+ }
555
+ buf: { (#3) [5 bytes data]
556
+ buf: { (#3) [27 bytes data]
557
+ {
558
+ "answer": " - Sarajevo, Yugoslavia ("
559
+ }
560
+ buf: { (#3) [5 bytes data]
561
+ buf: { (#3) [30 bytes data]
562
+ {
563
+ "answer": "now Bosnia and Herzegovina)\n"
564
+ }
565
+ buf: { (#3) [5 bytes data]
566
+ buf: { (#3) [20 bytes data]
567
+ {
568
+ "answer": "3. 1988 - Calgary,"
569
+ }
570
+ buf: { (#3) [5 bytes data]
571
+ buf: { (#3) [25 bytes data]
572
+ {
573
+ "answer": " Alberta, Canada\n4. 199"
574
+ }
575
+ buf: { (#3) [5 bytes data]
576
+ buf: { (#3) [26 bytes data]
577
+ {
578
+ "answer": "2 - Albertville, France\n"
579
+ }
580
+ buf: { (#3) [5 bytes data]
581
+ buf: { (#3) [13 bytes data]
582
+ {
583
+ "answer": "5. 1994 - L"
584
+ }
585
+ buf: { (#3) [5 bytes data]
586
+ buf: { (#3) [24 bytes data]
587
+ {
588
+ "answer": "illehammer, Norway\n6. "
589
+ }
590
+ buf: { (#3) [5 bytes data]
591
+ buf: { (#3) [23 bytes data]
592
+ {
593
+ "answer": "1998 - Nagano, Japan\n"
594
+ }
595
+ buf: { (#3) [5 bytes data]
596
+ buf: { (#3) [16 bytes data]
597
+ {
598
+ "answer": "7. 2002 - Salt"
599
+ }
600
+ buf: { (#3) [5 bytes data]
601
+ buf: { (#3) [24 bytes data]
602
+ {
603
+ "answer": " Lake City, Utah, USA\n"
604
+ }
605
+ buf: { (#3) [5 bytes data]
606
+ buf: { (#3) [18 bytes data]
607
+ {
608
+ "answer": "8. 2006 - Torino"
609
+ }
610
+ buf: { (#3) [5 bytes data]
611
+ buf: { (#3) [17 bytes data]
612
+ {
613
+ "answer": ", Italy\n9. 2010"
614
+ }
615
+ buf: { (#3) [5 bytes data]
616
+ buf: { (#3) [40 bytes data]
617
+ {
618
+ "answer": " - Vancouver, British Columbia, Canada"
619
+ }
620
+ buf: { (#3) [5 bytes data]
621
+ buf: { (#3) [13 bytes data]
622
+ {
623
+ "answer": "\n10. 2014 -"
624
+ }
625
+ buf: { (#3) [5 bytes data]
626
+ buf: { (#3) [20 bytes data]
627
+ {
628
+ "answer": " Sochi, Russia\n11."
629
+ }
630
+ buf: { (#3) [5 bytes data]
631
+ buf: { (#3) [16 bytes data]
632
+ {
633
+ "answer": " 2018 - Pyeong"
634
+ }
635
+ buf: { (#3) [5 bytes data]
636
+ buf: { (#3) [24 bytes data]
637
+ {
638
+ "answer": "chang, South Korea\n12."
639
+ }
640
+ buf: < (#3)
641
+ buf: < (#3) Grpc-Message:
642
+ buf: < (#3) Grpc-Status: 0
643
+ buf: * (#3) Call complete
644
+ buf: < (#2)
645
+ buf: < (#2) Grpc-Message:
646
+ buf: < (#2) Grpc-Status: 0
647
+ buf: * (#2) Call complete
648
+ %
649
+ ```
650
+
322
651
  ### 🔗 Multiple Services with Custom Interceptors
323
652
 
324
653
  PydanticRPC supports defining and running multiple services in a single server:
@@ -404,9 +733,9 @@ if __name__ == "__main__":
404
733
 
405
734
  TODO
406
735
 
407
- ### 🗄️ Protobuf file and code (Python files) generation
736
+ ### 🗄️ Protobuf file and code (Python files) generation using CLI
408
737
 
409
- Youcan genereate protobuf files and code for a given module and a specified class using `pydantic-rpc` CLI command:
738
+ You can genereate protobuf files and code for a given module and a specified class using `pydantic-rpc` CLI command:
410
739
 
411
740
  ```bash
412
741
  pydantic-rpc a_module.py aClassName