Skip to content

Commit 5dae209

Browse files
committed
Add OneOf support, rework field detection
1 parent 477e9cd commit 5dae209

File tree

5 files changed

+253
-88
lines changed

5 files changed

+253
-88
lines changed

README.md

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,19 +168,75 @@ Both serializing and parsing are supported to/from JSON and Python dictionaries
168168

169169
Sometimes it is useful to be able to determine whether a message has been sent on the wire. This is how the Google wrapper types work to let you know whether a value is unset, set as the default (zero value), or set as something else, for example.
170170

171-
Use `Message().serialized_on_wire` to determine if it was sent. This is a little bit different from the official Google generated Python code:
171+
Use `betterproto.serialized_on_wire(message)` to determine if it was sent. This is a little bit different from the official Google generated Python code, and it lives outside the generated `Message` class to prevent name clashes. Note that it **only** supports Proto 3 and thus can **only** be used to check if `Message` fields are set. You cannot check if a scalar was sent on the wire.
172172

173173
```py
174174
# Old way (official Google Protobuf package)
175175
>>> mymessage.HasField('myfield')
176176

177177
# New way (this project)
178-
>>> mymessage.myfield.serialized_on_wire
178+
>>> betterproto.serialized_on_wire(mymessage.myfield)
179+
```
180+
181+
### One-of Support
182+
183+
Protobuf supports grouping fields in a `oneof` clause. Only one of the fields in the group may be set at a given time. For example, given the proto:
184+
185+
```protobuf
186+
syntax = "proto3";
187+
188+
message Test {
189+
oneof foo {
190+
bool on = 1;
191+
int32 count = 2;
192+
string name = 3;
193+
}
194+
}
195+
```
196+
197+
You can use `betterproto.which_one_of(message, group_name)` to determine which of the fields was set. It returns a tuple of the field name and value, or a blank string and `None` if unset.
198+
199+
```py
200+
>>> test = Test()
201+
>>> betterproto.which_one_of(test, "foo")
202+
["", None]
203+
204+
>>> test.on = True
205+
>>> betterproto.which_one_of(test, "foo")
206+
["on", True]
207+
208+
# Setting one member of the group resets the others.
209+
>>> test.count = 57
210+
>>> betterproto.which_one_of(test, "foo")
211+
["count", 57]
212+
>>> test.on
213+
False
214+
215+
# Default (zero) values also work.
216+
>>> test.name = ""
217+
>>> betterproto.which_one_of(test, "foo")
218+
["name", ""]
219+
>>> test.count
220+
0
221+
>>> test.on
222+
False
223+
```
224+
225+
Again this is a little different than the official Google code generator:
226+
227+
```py
228+
# Old way (official Google protobuf package)
229+
>>> message.WhichOneof("group")
230+
"foo"
231+
232+
# New way (this project)
233+
>>> betterproto.which_one_of(message, "group")
234+
["foo", "foo's value"]
179235
```
180236

181237
## Development
182238

183-
First, make sure you have Python 3.7+ and `pipenv` installed:
239+
First, make sure you have Python 3.7+ and `pipenv` installed, along with the official [Protobuf Compiler](https://github.com/protocolbuffers/protobuf/releases) for your platform. Then:
184240

185241
```sh
186242
# Get set up with the virtual env & dependencies
@@ -224,10 +280,10 @@ $ pipenv run tests
224280
- [x] Refs to nested types
225281
- [x] Imports in proto files
226282
- [x] Well-known Google types
227-
- [ ] OneOf support
283+
- [x] OneOf support
228284
- [x] Basic support on the wire
229-
- [ ] Check which was set from the group
230-
- [ ] Setting one unsets the others
285+
- [x] Check which was set from the group
286+
- [x] Setting one unsets the others
231287
- [ ] JSON that isn't completely naive.
232288
- [x] 64-bit ints as strings
233289
- [x] Maps
@@ -236,14 +292,15 @@ $ pipenv run tests
236292
- [ ] Any support
237293
- [x] Enum strings
238294
- [ ] Well known types support (timestamp, duration, wrappers)
295+
- [ ] Support different casing (orig vs. camel vs. others?)
239296
- [ ] Async service stubs
240297
- [x] Unary-unary
241298
- [x] Server streaming response
242299
- [ ] Client streaming request
243300
- [ ] Renaming messages and fields to conform to Python name standards
244301
- [ ] Renaming clashes with language keywords and standard library top-level packages
245302
- [x] Python package
246-
- [ ] Automate running tests
303+
- [x] Automate running tests
247304
- [ ] Cleanup!
248305

249306
## License

0 commit comments

Comments
 (0)