proto-builder 1.5.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.
@@ -0,0 +1,402 @@
1
+ Metadata-Version: 2.4
2
+ Name: proto-builder
3
+ Version: 1.5.2
4
+ Description-Content-Type: text/markdown
5
+
6
+ # Proto Builder
7
+
8
+ ## 📦 Installation
9
+
10
+ Install the package with:
11
+
12
+ ```bash
13
+ pip install proto-builder
14
+ ```
15
+
16
+ A simple compiler that converts an abstract class to Protocol Buffers (`.proto`), built with Python.
17
+
18
+ It can also convert Python `dataclass` or Pydantic models to protobuf messages using a tree-based structure.
19
+
20
+ ## 📚 Contents
21
+
22
+ ### Getting Started
23
+
24
+ - [Overview](#overview)
25
+ - [Example Models](#example-models)
26
+
27
+ ### Service Generation
28
+
29
+ - [Build a Protobuf Service](#build-a-protobuf-service)
30
+ - [Generated Service Output](#generated-service-output)
31
+
32
+ ### Message Generation
33
+
34
+ - [Convert a Dataclass or Pydantic Model](#convert-a-dataclass-or-pydantic-model)
35
+ - [Generated Message Output](#generated-message-output)
36
+
37
+ ### Configuration
38
+
39
+ - [Configuration Options](#configuration-options)
40
+ - [Override](#override)
41
+ - [Remove](#remove)
42
+ - [Optional](#optional)
43
+ - [Optional All](#optional-all)
44
+ - [Configuration Paths](#configuration-paths)
45
+ - [Configuration Example](#configuration-example)
46
+ - [Configured Output](#configured-output)
47
+
48
+ ## Overview
49
+
50
+ A simple compiler that converts an abstract class to protobuf, built with Python.
51
+
52
+ It is also used to convert data classes or Pydantic classes to protobuf messages using a tree structure.
53
+
54
+ ## Example Models
55
+
56
+ Suppose we have this abstract class along with data classes or Pydantic models (here we've used data classes).
57
+
58
+ ```python
59
+ from abc import ABC, abstractmethod
60
+ from dataclasses import dataclass
61
+ from datetime import datetime
62
+ from enum import Enum
63
+
64
+
65
+ class Status(Enum):
66
+ ACTIVE = "active"
67
+ INACTIVE = "inactive"
68
+
69
+
70
+ @dataclass
71
+ class Location:
72
+ city: str
73
+ country: str
74
+
75
+
76
+ @dataclass
77
+ class Address:
78
+ street: str
79
+ postal_code: str
80
+ location: Location
81
+
82
+
83
+ @dataclass
84
+ class Employee:
85
+ id: int
86
+ name: str
87
+ status: Status
88
+ address: Address
89
+
90
+
91
+ @dataclass
92
+ class Department:
93
+ name: str
94
+ manager: Employee
95
+
96
+
97
+ @dataclass
98
+ class Company:
99
+ name: str
100
+ founded: datetime
101
+ department: Department
102
+
103
+
104
+ class CompanyService(ABC):
105
+
106
+ @abstractmethod
107
+ def get_company(self, company_id: int) -> Company:
108
+ pass
109
+
110
+ @abstractmethod
111
+ def get_employee(self, employee_id: int) -> Employee | None:
112
+ pass
113
+
114
+ @abstractmethod
115
+ def find(self, name: str) -> Company | Department | Employee | Status | None:
116
+ pass
117
+
118
+ @abstractmethod
119
+ def summary(self, employee_id: int) -> tuple[Employee | Status | None, str]:
120
+ pass
121
+
122
+ @abstractmethod
123
+ def update(
124
+ self,
125
+ company: Company,
126
+ employees: list[Employee],
127
+ metadata: dict[str, str],
128
+ tags: set[str],
129
+ ) -> list[Department]:
130
+ pass
131
+ ```
132
+
133
+ ## Build a Protobuf Service
134
+
135
+ This is how the protobuf service is generated from the abstract class.
136
+
137
+ ```python
138
+ from proto_builder.utils import ProtoConfig
139
+ from proto_builder.service_builder import ServiceBuilder
140
+
141
+ config = ProtoConfig()
142
+ service_builder = ServiceBuilder(config)
143
+
144
+ proto = service_builder.build(CompanyService, "company_service")
145
+
146
+ print(proto)
147
+ ```
148
+
149
+ ## Generated Service Output
150
+
151
+ ```protobuf
152
+ syntax = "proto3";
153
+ package company_service;
154
+
155
+ import "google/protobuf/timestamp.proto";
156
+
157
+ service CompanyService {
158
+ rpc get_company (GetCompanyRequest) returns (Company);
159
+ rpc get_employee (GetEmployeeRequest) returns (GetEmployeeResponse);
160
+ rpc find (FindRequest) returns (FindResponse);
161
+ rpc summary (SummaryRequest) returns (SummaryResponse);
162
+ rpc update (UpdateRequest) returns (UpdateResponse);
163
+ }
164
+
165
+ enum Status {
166
+ ACTIVE = 0;
167
+ INACTIVE = 1;
168
+ }
169
+
170
+ message Location {
171
+ string city = 1;
172
+ string country = 2;
173
+ }
174
+
175
+ message Address {
176
+ string street = 1;
177
+ string postal_code = 2;
178
+ Location location = 3;
179
+ }
180
+
181
+ message Employee {
182
+ int32 id = 1;
183
+ string name = 2;
184
+ Status status = 3;
185
+ Address address = 4;
186
+ }
187
+
188
+ message Department {
189
+ string name = 1;
190
+ Employee manager = 2;
191
+ }
192
+
193
+ message Company {
194
+ string name = 1;
195
+ google.protobuf.Timestamp founded = 2;
196
+ Department department = 3;
197
+ }
198
+
199
+ message GetCompanyRequest {
200
+ int32 company_id = 1;
201
+ }
202
+
203
+ message GetEmployeeRequest {
204
+ int32 employee_id = 1;
205
+ }
206
+
207
+ message GetEmployeeResponse {
208
+ optional Employee employee = 1;
209
+ }
210
+
211
+ message FindRequest {
212
+ string name = 1;
213
+ }
214
+
215
+ message FindResponse {
216
+ oneof union_var {
217
+ Company company = 1;
218
+ Department department = 2;
219
+ Employee employee = 3;
220
+ Status status = 4;
221
+ }
222
+ }
223
+
224
+ message SummaryRequest {
225
+ int32 employee_id = 1;
226
+ }
227
+
228
+ message SummaryResponse {
229
+ oneof union_var {
230
+ Employee employee = 1;
231
+ Status status = 2;
232
+ }
233
+ string str_var = 3;
234
+ }
235
+
236
+ message UpdateRequest {
237
+ Company company = 1;
238
+ repeated Employee employees = 2;
239
+ map<string, string> metadata = 3;
240
+ repeated string tags = 4;
241
+ }
242
+
243
+ message UpdateResponse {
244
+ repeated Department department = 1;
245
+ }
246
+ ```
247
+
248
+ ## Convert a Dataclass or Pydantic Model
249
+
250
+ Converting a dataclass or Pydantic model to protobuf messages is done using this way.
251
+
252
+ ```python
253
+ from proto_builder.utils import ProtoConfig
254
+ from proto_builder.message_builder import MessageBuilder
255
+
256
+ config = ProtoConfig()
257
+ message_builder = MessageBuilder(config)
258
+
259
+ proto = message_builder.build(Company)
260
+
261
+ print(proto)
262
+ ```
263
+
264
+ ## Generated Message Output
265
+
266
+ ```protobuf
267
+ enum Status {
268
+ ACTIVE = 0;
269
+ INACTIVE = 1;
270
+ }
271
+
272
+ message Location {
273
+ string city = 1;
274
+ string country = 2;
275
+ }
276
+
277
+ message Address {
278
+ string street = 1;
279
+ string postal_code = 2;
280
+ Location location = 3;
281
+ }
282
+
283
+ message Employee {
284
+ int32 id = 1;
285
+ string name = 2;
286
+ Status status = 3;
287
+ Address address = 4;
288
+ }
289
+
290
+ message Department {
291
+ string name = 1;
292
+ Employee manager = 2;
293
+ }
294
+
295
+ message Company {
296
+ string name = 1;
297
+ google.protobuf.Timestamp founded = 2;
298
+ Department department = 3;
299
+ }
300
+ ```
301
+
302
+ ## Configuration Options
303
+
304
+ The changes we can make via configuration:
305
+
306
+ ```python
307
+ config = ProtoConfig(
308
+ override=[
309
+ ...
310
+ ],
311
+ remove=[
312
+ ...
313
+ ],
314
+ optional=[
315
+ ...
316
+ ],
317
+ optional_all=True or False,
318
+ )
319
+ ```
320
+
321
+ ### Override
322
+
323
+ Replace a type or a field's type with another type.
324
+
325
+ ### Remove
326
+
327
+ Remove a type or a field's type.
328
+
329
+ ### Optional
330
+
331
+ Make a field or its type optional (i.e., making its assignment optional).
332
+
333
+ ### Optional All
334
+
335
+ `optional_all` makes the assignment of all fields or field types optional.
336
+
337
+ ### Configuration Paths
338
+
339
+ The paths used in the config can be either relative or absolute.
340
+
341
+ ### Configuration Example
342
+
343
+ ```python
344
+ config = ProtoConfig(
345
+ override=[
346
+ {"Department.manager": list[Employee]},
347
+ # It can be:
348
+ # {"...Department.manager": list[Employee]},
349
+ # or
350
+ # {"...manager": list[Employee]},
351
+
352
+ {"str": int},
353
+ ],
354
+ remove=[
355
+ "Employee.address",
356
+ # It can be:
357
+ # "...Employee.address",
358
+ # or
359
+ # "...address",
360
+ # or
361
+ # "...Address",
362
+ ],
363
+ optional=[
364
+ "Company",
365
+ # It can be:
366
+ # "...Company",
367
+
368
+ "Employee.status",
369
+ # It can be:
370
+ # "...Employee.status",
371
+ # or
372
+ # "...status",
373
+ ],
374
+ # optional_all=True,
375
+ )
376
+ ```
377
+
378
+ ## Configured Output
379
+
380
+ ```protobuf
381
+ enum Status {
382
+ ACTIVE = 0;
383
+ INACTIVE = 1;
384
+ }
385
+
386
+ message Employee {
387
+ int32 id = 1;
388
+ int32 name = 2;
389
+ optional Status status = 3;
390
+ }
391
+
392
+ message Department {
393
+ int32 name = 1;
394
+ repeated Employee manager = 2;
395
+ }
396
+
397
+ message Company {
398
+ optional int32 name = 1;
399
+ optional google.protobuf.Timestamp founded = 2;
400
+ optional Department department = 3;
401
+ }
402
+ ```