轻全python3协议缓冲区的实现
lightprotobuf的Python项目详细描述
lightprotobuf
简介
lightprotobuf是一个完整的python 3协议缓冲区实现,如google所描述。
文档
要使用的主要类是lightprotobuf.message
它必须是您定义的每个消息的基类。其余部分遵循.proto设计:
此消息:
enum FooEnum { FIELD = 5; FIELD2 = 6; } message FooMsg { required int32 foo_field = 1; optional FooEnum foo_enum = 2; enum BarEnum { FIELD = 5; BAR = 6; } required BarEnum bar_enum = 3; repeated string foo_rep = 4; repeated int32 foo_pak = 5 [packed=true]; } message BarMsg { required FooMsg.BarEnum bar_enum = 1; }
在python中转换为:
from enum import IntEnum from lightprotobuf import * class FooEnum(IntEnum): FIELD = 5 FIELD2 = 6 class FooMsg(Message): class BarEnum(IntEnum): FIELD = 5 BAR = 6 foo_field = Field(1, Int32, Field.REQUIRED, **{}) bar_enum = Field(3, BarEnum, Field.REQUIRED, **{}) foo_enum = Field(2, FooEnum, Field.OPTIONAL, **{}) class BarMsg(Message): bar_enum = Field(1, FooMsg.BarEnum, Field.REQUIRED, **{})
如您所见,字段遵循此模板
<name> = Field(<tag number>, <type>, Field.<REQUIRED|OPTIONEL|REPEATED>, **{<options as a dict (optional)>}
枚举是python的enum.IntEnum
嵌套类型是真正的python嵌套类型,就像在.proto中引用的那样
api
字段实际上通过描述符转换为属性。因此您可以轻松访问字段:
m = FooMsg() m.foo_field = 5 m.foo_field # returns 5 m.foo_enum = 5 # Error because it expects a FooEnum object m.foo_enum = FooEnum.FIELD # OK m.bar_enum = FooMsg.BarEnum.BAR # OK
重复字段atc,如列表:
m.foo_rep = ["a string", "another"] # OK li = m.foo_rep # Get a reference to the list li.append("a string") # OK, append the string li.append(b'a bytes') # TypeError because there is a check to avoid mistakes
注意:压缩字段可以解码压缩的数据,也可以解码多次出现的字段,例如测试用例:
class Repeated(Message): r = Field(1, Int32, Field.REPEATED, packed="True") nb = [1,150,1,2,3,150] b = io.BytesIO(b'\x0C\x08\x01\x08\x96\x01\x0A\x05\x01\x02\x03\x96\x01') m = Repeated.from_stream(b) self.assertEqual(list(m.r), nb) # 0C (12) bytes following # 08 = 1 << 3 | 0 # varints etc. # 0A = 1 << 3 | 2 # 05 bytes following # concatened varints etc.
为了对消息进行编码,lightprotobuf使用流对象:每个数据类型都有一个to_stream和from_stream类方法。只需从消息中调用它即可对消息进行编码/解码:
import io s = io.BytesIO() Message.to_stream(s, m) s.getvalue() # b'\x06\x08\x05\x10\x05\x18\x06' m = FooMsg() s = io.BytesIO(b'\x06\x08\x05\x10\x05\x18\x06') m = Message.from_stream(s)
注意:如果缺少必需字段,则会引发fieldnotoptional异常
发行说明
1.0.b3
- 警告:模块在顶层移动。使用导入lightprotobuf而不是从lightprotobuf导入lightprotobuf
- 添加对重复字段(打包和未打包)的支持
1.0.b2
- 删除description.rst,因为readme.rst的副本