proto 0.1.0__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.
proto-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 nehz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
proto-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,238 @@
1
+ Metadata-Version: 2.4
2
+ Name: proto
3
+ Version: 0.1.0
4
+ Summary: Schema-first, protobuf wire-compatible binary messages for pure Python, declared with dataclasses.
5
+ Author: nehz
6
+ License-Expression: MIT
7
+ Keywords: protobuf,protocol-buffers,serialization,binary,varint,dataclasses,schema
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: System :: Networking
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest>=7; extra == "test"
25
+ Dynamic: license-file
26
+
27
+ # proto
28
+
29
+ **Protocol Buffers without the toolchain.** `proto` lets you declare binary
30
+ messages as ordinary Python dataclasses and serialize them to bytes that are
31
+ wire-compatible with Google's Protocol Buffers (proto3). No `protoc`, no
32
+ generated code, no C extension, no dependencies: just the standard library.
33
+
34
+ Use it when you need to talk to a protobuf service from a script, persist
35
+ compact records, or prototype a schema in Python first, and still have every
36
+ other protobuf implementation read your bytes.
37
+
38
+ ```python
39
+ import proto
40
+
41
+ @proto.message
42
+ class Point:
43
+ x: int = proto.field(1, "sint32")
44
+ y: int = proto.field(2, "sint32")
45
+
46
+ data = proto.encode(Point(3, -4)) # b'\x08\x06\x10\x07'
47
+ assert proto.decode(Point, data) == Point(3, -4)
48
+ ```
49
+
50
+ ## Features
51
+
52
+ - **Wire-compatible**: varints, zigzag, fixed-width, length-delimited and packed
53
+ encodings match the official protobuf encoding byte for byte. The tests check
54
+ the exact byte strings from the protobuf encoding guide.
55
+ - **Schema-first dataclasses**: field numbers live next to the type annotations.
56
+ Messages are real `dataclasses`, so you keep `==`, `repr`, `replace()` and
57
+ your type checker.
58
+ - **All 15 scalar types**: `int32 int64 uint32 uint64 sint32 sint64 bool
59
+ fixed32 fixed64 sfixed32 sfixed64 float double string bytes`, plus `IntEnum`
60
+ enums, nested and recursive messages, `repeated` fields, and proto3 `optional`.
61
+ - **proto3 semantics**: default values are omitted on the wire, unknown fields are
62
+ skipped, packed and unpacked repeated fields are both accepted, unknown enum
63
+ values are kept as `int` (open enums).
64
+ - **Strict validation**: out-of-range integers, wrong Python types, malformed or
65
+ truncated input raise clear `EncodeError` / `DecodeError` / `SchemaError`.
66
+ - **`.proto` export**: `to_proto()` renders your classes as a `.proto` file, so
67
+ other languages can generate code from the same schema.
68
+ - **Streaming**: length-delimited framing (`writeDelimitedTo` format) for many
69
+ messages in one file or socket.
70
+ - Pure Python 3.10+, fully type-hinted (`py.typed`), zero dependencies.
71
+
72
+ ## Install
73
+
74
+ ```bash
75
+ pip install proto # once published
76
+ pip install -e . # from a checkout
77
+ ```
78
+
79
+ > Note: Google's `proto-plus` package also installs a top-level `proto` module.
80
+ > Don't install both in the same environment.
81
+
82
+ ## Quickstart
83
+
84
+ ```python
85
+ from __future__ import annotations
86
+
87
+ import enum
88
+ import io
89
+
90
+ import proto
91
+
92
+
93
+ class Role(enum.IntEnum):
94
+ ROLE_UNSPECIFIED = 0 # proto3 enums need a zero value
95
+ ADMIN = 1
96
+ MEMBER = 2
97
+
98
+
99
+ @proto.message
100
+ class Address:
101
+ city: str = proto.field(1)
102
+ zip_code: str = proto.field(2)
103
+
104
+
105
+ @proto.message
106
+ class User:
107
+ name: str = proto.field(1) # inferred: string
108
+ id: int = proto.field(2, "uint32") # explicit scalar type
109
+ age: int | None = proto.field(3, "int32") # proto3 `optional`: None = unset
110
+ role: Role = proto.field(4) # enum
111
+ emails: list[str] = proto.field(5) # repeated
112
+ scores: list[int] = proto.field(6, "sint32") # repeated, packed by default
113
+ address: Address | None = proto.field(7) # nested message
114
+ friends: list[User] = proto.field(8) # recursive
115
+
116
+
117
+ ada = User("ada", id=1, role=Role.ADMIN, emails=["ada@example.com"],
118
+ address=Address("London", "N1"))
119
+
120
+ data = ada.to_bytes() # same as proto.encode(ada)
121
+ again = User.from_bytes(data) # same as proto.decode(User, data)
122
+ assert again == ada
123
+
124
+ proto.to_dict(ada)
125
+ # {'name': 'ada', 'id': 1, 'role': 'ADMIN', 'emails': ['ada@example.com'],
126
+ # 'scores': [], 'address': {'city': 'London', 'zip_code': 'N1'}, 'friends': []}
127
+
128
+ # Many messages in one stream
129
+ buf = io.BytesIO()
130
+ for user in (ada, User("bob", id=2)):
131
+ proto.write_delimited(buf, user)
132
+ buf.seek(0)
133
+ names = [u.name for u in proto.iter_delimited(User, buf)] # ['ada', 'bob']
134
+
135
+ print(proto.to_proto(User, package="example.v1"))
136
+ ```
137
+
138
+ The last line prints:
139
+
140
+ ```proto
141
+ syntax = "proto3";
142
+
143
+ package example.v1;
144
+
145
+ enum Role {
146
+ ROLE_UNSPECIFIED = 0;
147
+ ADMIN = 1;
148
+ MEMBER = 2;
149
+ }
150
+
151
+ message Address {
152
+ string city = 1;
153
+ string zip_code = 2;
154
+ }
155
+
156
+ message User {
157
+ string name = 1;
158
+ uint32 id = 2;
159
+ optional int32 age = 3;
160
+ Role role = 4;
161
+ repeated string emails = 5;
162
+ repeated sint32 scores = 6;
163
+ Address address = 7;
164
+ repeated User friends = 8;
165
+ }
166
+ ```
167
+
168
+ ## Declaring fields
169
+
170
+ | Annotation | Inferred `.proto` type | Default when omitted |
171
+ |-------------------------|------------------------|----------------------|
172
+ | `int` | `int64` | `0` |
173
+ | `float` | `double` | `0.0` |
174
+ | `bool` | `bool` | `False` |
175
+ | `str` | `string` | `""` |
176
+ | `bytes` | `bytes` | `b""` |
177
+ | `SomeIntEnum` | `SomeIntEnum` | the member with value `0` |
178
+ | `SomeMessage \| None` | `SomeMessage` | `None` (unset) |
179
+ | `T \| None` (scalar) | `optional T` | `None` (unset) |
180
+ | `list[T]` | `repeated T` | `[]` |
181
+
182
+ Pass `type=` (the second argument of `field`) to choose another scalar
183
+ encoding such as `"sint32"` or `"fixed64"`, or to name an enum/message class
184
+ explicitly.
185
+
186
+ ## API overview
187
+
188
+ Everything is importable from the top-level `proto` package.
189
+
190
+ | Name | Description |
191
+ |------|-------------|
192
+ | `@message` / `@message(name="Wire")` | Class decorator. Turns an annotated class into a dataclass-based message and adds `to_bytes()` and classmethod `from_bytes(data)`. `name` sets the name used by `to_proto` (default: class name). |
193
+ | `field(number, type=None, *, default=..., default_factory=..., packed=None)` | Declares a field. `type` is a scalar name, an `IntEnum` subclass or a message class; it is inferred from the annotation when omitted. `packed=False` disables packed encoding for repeated numeric/enum fields. Every annotated attribute must use `field()`. |
194
+ | `encode(msg) -> bytes` | Serialize a message instance. |
195
+ | `decode(cls, data) -> cls` | Parse `bytes`/`bytearray`/`memoryview` into a new `cls` instance. Absent fields get their proto3 zero value; the last occurrence of a singular field wins. |
196
+ | `fields(cls) -> tuple[FieldInfo, ...]` | Resolved schema of a message class, ordered by field number. |
197
+ | `FieldInfo` | Frozen dataclass: `name`, `number`, `kind` (`"scalar"`/`"enum"`/`"message"`), `type_name`, `repeated`, `optional`, `packed`, `scalar`, `target`, and property `wire_type`. |
198
+ | `is_message(obj) -> bool` | True for `@message` classes and their instances. |
199
+ | `to_dict(msg) -> dict` | Plain-dict view: nested messages become dicts, enums become names, unset optionals are omitted. |
200
+ | `from_dict(cls, data) -> cls` | Inverse of `to_dict`; enums may be given by name or number. |
201
+ | `to_proto(*classes, package=None) -> str` | Render the classes and every enum/message they reference as proto3 source. |
202
+ | `write_delimited(stream, msg) -> int` | Write a varint length prefix plus the message; returns bytes written. |
203
+ | `read_delimited(cls, stream) -> cls \| None` | Read one framed message; `None` at a clean end of stream. |
204
+ | `iter_delimited(cls, stream)` | Iterate framed messages until the stream is exhausted. |
205
+ | `ProtoError` | Base exception. Subclasses: `SchemaError` (also a `TypeError`), `EncodeError` and `DecodeError` (also `ValueError`). |
206
+ | `__version__` | `"0.1.0"` |
207
+
208
+ Low-level primitives live in `proto.wire`:
209
+
210
+ | Name | Description |
211
+ |------|-------------|
212
+ | `WireType` | `IntEnum`: `VARINT`, `I64`, `LEN`, `SGROUP`, `EGROUP`, `I32`. |
213
+ | `MAX_FIELD_NUMBER` | `2**29 - 1`. |
214
+ | `encode_varint(value) -> bytes` | Base-128 varint; negatives use 64-bit two's complement. |
215
+ | `decode_varint(data, pos=0) -> (value, new_pos)` | Decode one varint. |
216
+ | `zigzag_encode(value, bits=64) -> int` / `zigzag_decode(value) -> int` | ZigZag mapping used by `sint32`/`sint64`. |
217
+ | `encode_tag(number, wire_type) -> bytes` | Field key. |
218
+ | `decode_tag(data, pos=0) -> (number, wire_type, new_pos)` | Parse a field key. |
219
+ | `skip_field(data, pos, wire_type, number=None) -> int` | Skip an unknown field's payload, groups included. |
220
+
221
+ ## Limitations
222
+
223
+ `proto` 0.1 covers the core of proto3. Not supported yet: `oneof`, `map<K, V>`
224
+ fields, well-known types (`Timestamp`, `Any`, ...), proto2 groups (they are
225
+ skipped when decoding), services/gRPC, and merging of repeated occurrences of
226
+ a singular message field (the last occurrence wins). Annotations that name
227
+ other classes must be resolvable from the scope where the class is defined.
228
+
229
+ ## Development
230
+
231
+ ```bash
232
+ PYTHONPATH=src python3 -m unittest discover -s tests -v # standard library only
233
+ python3 -m pytest # if pytest is installed
234
+ ```
235
+
236
+ ## License
237
+
238
+ MIT
proto-0.1.0/README.md ADDED
@@ -0,0 +1,212 @@
1
+ # proto
2
+
3
+ **Protocol Buffers without the toolchain.** `proto` lets you declare binary
4
+ messages as ordinary Python dataclasses and serialize them to bytes that are
5
+ wire-compatible with Google's Protocol Buffers (proto3). No `protoc`, no
6
+ generated code, no C extension, no dependencies: just the standard library.
7
+
8
+ Use it when you need to talk to a protobuf service from a script, persist
9
+ compact records, or prototype a schema in Python first, and still have every
10
+ other protobuf implementation read your bytes.
11
+
12
+ ```python
13
+ import proto
14
+
15
+ @proto.message
16
+ class Point:
17
+ x: int = proto.field(1, "sint32")
18
+ y: int = proto.field(2, "sint32")
19
+
20
+ data = proto.encode(Point(3, -4)) # b'\x08\x06\x10\x07'
21
+ assert proto.decode(Point, data) == Point(3, -4)
22
+ ```
23
+
24
+ ## Features
25
+
26
+ - **Wire-compatible**: varints, zigzag, fixed-width, length-delimited and packed
27
+ encodings match the official protobuf encoding byte for byte. The tests check
28
+ the exact byte strings from the protobuf encoding guide.
29
+ - **Schema-first dataclasses**: field numbers live next to the type annotations.
30
+ Messages are real `dataclasses`, so you keep `==`, `repr`, `replace()` and
31
+ your type checker.
32
+ - **All 15 scalar types**: `int32 int64 uint32 uint64 sint32 sint64 bool
33
+ fixed32 fixed64 sfixed32 sfixed64 float double string bytes`, plus `IntEnum`
34
+ enums, nested and recursive messages, `repeated` fields, and proto3 `optional`.
35
+ - **proto3 semantics**: default values are omitted on the wire, unknown fields are
36
+ skipped, packed and unpacked repeated fields are both accepted, unknown enum
37
+ values are kept as `int` (open enums).
38
+ - **Strict validation**: out-of-range integers, wrong Python types, malformed or
39
+ truncated input raise clear `EncodeError` / `DecodeError` / `SchemaError`.
40
+ - **`.proto` export**: `to_proto()` renders your classes as a `.proto` file, so
41
+ other languages can generate code from the same schema.
42
+ - **Streaming**: length-delimited framing (`writeDelimitedTo` format) for many
43
+ messages in one file or socket.
44
+ - Pure Python 3.10+, fully type-hinted (`py.typed`), zero dependencies.
45
+
46
+ ## Install
47
+
48
+ ```bash
49
+ pip install proto # once published
50
+ pip install -e . # from a checkout
51
+ ```
52
+
53
+ > Note: Google's `proto-plus` package also installs a top-level `proto` module.
54
+ > Don't install both in the same environment.
55
+
56
+ ## Quickstart
57
+
58
+ ```python
59
+ from __future__ import annotations
60
+
61
+ import enum
62
+ import io
63
+
64
+ import proto
65
+
66
+
67
+ class Role(enum.IntEnum):
68
+ ROLE_UNSPECIFIED = 0 # proto3 enums need a zero value
69
+ ADMIN = 1
70
+ MEMBER = 2
71
+
72
+
73
+ @proto.message
74
+ class Address:
75
+ city: str = proto.field(1)
76
+ zip_code: str = proto.field(2)
77
+
78
+
79
+ @proto.message
80
+ class User:
81
+ name: str = proto.field(1) # inferred: string
82
+ id: int = proto.field(2, "uint32") # explicit scalar type
83
+ age: int | None = proto.field(3, "int32") # proto3 `optional`: None = unset
84
+ role: Role = proto.field(4) # enum
85
+ emails: list[str] = proto.field(5) # repeated
86
+ scores: list[int] = proto.field(6, "sint32") # repeated, packed by default
87
+ address: Address | None = proto.field(7) # nested message
88
+ friends: list[User] = proto.field(8) # recursive
89
+
90
+
91
+ ada = User("ada", id=1, role=Role.ADMIN, emails=["ada@example.com"],
92
+ address=Address("London", "N1"))
93
+
94
+ data = ada.to_bytes() # same as proto.encode(ada)
95
+ again = User.from_bytes(data) # same as proto.decode(User, data)
96
+ assert again == ada
97
+
98
+ proto.to_dict(ada)
99
+ # {'name': 'ada', 'id': 1, 'role': 'ADMIN', 'emails': ['ada@example.com'],
100
+ # 'scores': [], 'address': {'city': 'London', 'zip_code': 'N1'}, 'friends': []}
101
+
102
+ # Many messages in one stream
103
+ buf = io.BytesIO()
104
+ for user in (ada, User("bob", id=2)):
105
+ proto.write_delimited(buf, user)
106
+ buf.seek(0)
107
+ names = [u.name for u in proto.iter_delimited(User, buf)] # ['ada', 'bob']
108
+
109
+ print(proto.to_proto(User, package="example.v1"))
110
+ ```
111
+
112
+ The last line prints:
113
+
114
+ ```proto
115
+ syntax = "proto3";
116
+
117
+ package example.v1;
118
+
119
+ enum Role {
120
+ ROLE_UNSPECIFIED = 0;
121
+ ADMIN = 1;
122
+ MEMBER = 2;
123
+ }
124
+
125
+ message Address {
126
+ string city = 1;
127
+ string zip_code = 2;
128
+ }
129
+
130
+ message User {
131
+ string name = 1;
132
+ uint32 id = 2;
133
+ optional int32 age = 3;
134
+ Role role = 4;
135
+ repeated string emails = 5;
136
+ repeated sint32 scores = 6;
137
+ Address address = 7;
138
+ repeated User friends = 8;
139
+ }
140
+ ```
141
+
142
+ ## Declaring fields
143
+
144
+ | Annotation | Inferred `.proto` type | Default when omitted |
145
+ |-------------------------|------------------------|----------------------|
146
+ | `int` | `int64` | `0` |
147
+ | `float` | `double` | `0.0` |
148
+ | `bool` | `bool` | `False` |
149
+ | `str` | `string` | `""` |
150
+ | `bytes` | `bytes` | `b""` |
151
+ | `SomeIntEnum` | `SomeIntEnum` | the member with value `0` |
152
+ | `SomeMessage \| None` | `SomeMessage` | `None` (unset) |
153
+ | `T \| None` (scalar) | `optional T` | `None` (unset) |
154
+ | `list[T]` | `repeated T` | `[]` |
155
+
156
+ Pass `type=` (the second argument of `field`) to choose another scalar
157
+ encoding such as `"sint32"` or `"fixed64"`, or to name an enum/message class
158
+ explicitly.
159
+
160
+ ## API overview
161
+
162
+ Everything is importable from the top-level `proto` package.
163
+
164
+ | Name | Description |
165
+ |------|-------------|
166
+ | `@message` / `@message(name="Wire")` | Class decorator. Turns an annotated class into a dataclass-based message and adds `to_bytes()` and classmethod `from_bytes(data)`. `name` sets the name used by `to_proto` (default: class name). |
167
+ | `field(number, type=None, *, default=..., default_factory=..., packed=None)` | Declares a field. `type` is a scalar name, an `IntEnum` subclass or a message class; it is inferred from the annotation when omitted. `packed=False` disables packed encoding for repeated numeric/enum fields. Every annotated attribute must use `field()`. |
168
+ | `encode(msg) -> bytes` | Serialize a message instance. |
169
+ | `decode(cls, data) -> cls` | Parse `bytes`/`bytearray`/`memoryview` into a new `cls` instance. Absent fields get their proto3 zero value; the last occurrence of a singular field wins. |
170
+ | `fields(cls) -> tuple[FieldInfo, ...]` | Resolved schema of a message class, ordered by field number. |
171
+ | `FieldInfo` | Frozen dataclass: `name`, `number`, `kind` (`"scalar"`/`"enum"`/`"message"`), `type_name`, `repeated`, `optional`, `packed`, `scalar`, `target`, and property `wire_type`. |
172
+ | `is_message(obj) -> bool` | True for `@message` classes and their instances. |
173
+ | `to_dict(msg) -> dict` | Plain-dict view: nested messages become dicts, enums become names, unset optionals are omitted. |
174
+ | `from_dict(cls, data) -> cls` | Inverse of `to_dict`; enums may be given by name or number. |
175
+ | `to_proto(*classes, package=None) -> str` | Render the classes and every enum/message they reference as proto3 source. |
176
+ | `write_delimited(stream, msg) -> int` | Write a varint length prefix plus the message; returns bytes written. |
177
+ | `read_delimited(cls, stream) -> cls \| None` | Read one framed message; `None` at a clean end of stream. |
178
+ | `iter_delimited(cls, stream)` | Iterate framed messages until the stream is exhausted. |
179
+ | `ProtoError` | Base exception. Subclasses: `SchemaError` (also a `TypeError`), `EncodeError` and `DecodeError` (also `ValueError`). |
180
+ | `__version__` | `"0.1.0"` |
181
+
182
+ Low-level primitives live in `proto.wire`:
183
+
184
+ | Name | Description |
185
+ |------|-------------|
186
+ | `WireType` | `IntEnum`: `VARINT`, `I64`, `LEN`, `SGROUP`, `EGROUP`, `I32`. |
187
+ | `MAX_FIELD_NUMBER` | `2**29 - 1`. |
188
+ | `encode_varint(value) -> bytes` | Base-128 varint; negatives use 64-bit two's complement. |
189
+ | `decode_varint(data, pos=0) -> (value, new_pos)` | Decode one varint. |
190
+ | `zigzag_encode(value, bits=64) -> int` / `zigzag_decode(value) -> int` | ZigZag mapping used by `sint32`/`sint64`. |
191
+ | `encode_tag(number, wire_type) -> bytes` | Field key. |
192
+ | `decode_tag(data, pos=0) -> (number, wire_type, new_pos)` | Parse a field key. |
193
+ | `skip_field(data, pos, wire_type, number=None) -> int` | Skip an unknown field's payload, groups included. |
194
+
195
+ ## Limitations
196
+
197
+ `proto` 0.1 covers the core of proto3. Not supported yet: `oneof`, `map<K, V>`
198
+ fields, well-known types (`Timestamp`, `Any`, ...), proto2 groups (they are
199
+ skipped when decoding), services/gRPC, and merging of repeated occurrences of
200
+ a singular message field (the last occurrence wins). Annotations that name
201
+ other classes must be resolvable from the scope where the class is defined.
202
+
203
+ ## Development
204
+
205
+ ```bash
206
+ PYTHONPATH=src python3 -m unittest discover -s tests -v # standard library only
207
+ python3 -m pytest # if pytest is installed
208
+ ```
209
+
210
+ ## License
211
+
212
+ MIT
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "proto"
7
+ version = "0.1.0"
8
+ description = "Schema-first, protobuf wire-compatible binary messages for pure Python, declared with dataclasses."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ authors = [{ name = "nehz" }]
13
+ keywords = ["protobuf", "protocol-buffers", "serialization", "binary", "varint", "dataclasses", "schema"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3 :: Only",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries :: Python Modules",
25
+ "Topic :: System :: Networking",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = []
29
+
30
+ [project.optional-dependencies]
31
+ test = ["pytest>=7"]
32
+
33
+ [tool.setuptools.packages.find]
34
+ where = ["src"]
35
+
36
+ [tool.setuptools.package-data]
37
+ proto = ["py.typed"]
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["tests"]
41
+ pythonpath = ["src"]
proto-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,47 @@
1
+ """proto: schema-first, protobuf wire-compatible messages in pure Python.
2
+
3
+ Declare messages as annotated classes, encode them to bytes that any
4
+ Protocol Buffers implementation can read, and decode them back::
5
+
6
+ import proto
7
+
8
+ @proto.message
9
+ class Point:
10
+ x: int = proto.field(1, "sint32")
11
+ y: int = proto.field(2, "sint32")
12
+
13
+ data = proto.encode(Point(3, -4))
14
+ assert proto.decode(Point, data) == Point(3, -4)
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from . import wire
20
+ from .errors import DecodeError, EncodeError, ProtoError, SchemaError
21
+ from .message import FieldInfo, decode, encode, field, fields, from_dict, is_message, message, to_dict
22
+ from .schema import to_proto
23
+ from .stream import iter_delimited, read_delimited, write_delimited
24
+
25
+ __version__ = "0.1.0"
26
+
27
+ __all__ = [
28
+ "message",
29
+ "field",
30
+ "encode",
31
+ "decode",
32
+ "fields",
33
+ "is_message",
34
+ "FieldInfo",
35
+ "to_dict",
36
+ "from_dict",
37
+ "to_proto",
38
+ "write_delimited",
39
+ "read_delimited",
40
+ "iter_delimited",
41
+ "wire",
42
+ "ProtoError",
43
+ "SchemaError",
44
+ "EncodeError",
45
+ "DecodeError",
46
+ "__version__",
47
+ ]
@@ -0,0 +1,21 @@
1
+ """Exception hierarchy for :mod:`proto`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ __all__ = ["ProtoError", "SchemaError", "EncodeError", "DecodeError"]
6
+
7
+
8
+ class ProtoError(Exception):
9
+ """Base class for every error raised by :mod:`proto`."""
10
+
11
+
12
+ class SchemaError(ProtoError, TypeError):
13
+ """A message class is declared incorrectly (bad field number, type, ...)."""
14
+
15
+
16
+ class EncodeError(ProtoError, ValueError):
17
+ """A value cannot be encoded (out of range, wrong Python type, ...)."""
18
+
19
+
20
+ class DecodeError(ProtoError, ValueError):
21
+ """Input bytes are not a valid encoding of the requested message."""