将任意的原BUBFF消息对象转换为可以与谷歌数据存储一起使用的实体原型BooBF对象的库。
protobuf-cloud-datastore-translator的Python项目详细描述
protobuf消息到google数据存储实体protobuf消息转换器
这个库允许您在google数据存储中存储任意protobuf消息对象。
它公开了将任意protobuf消息对象转换为实体protobuf对象的方法。 它们被谷歌数据存储使用,反之亦然。
它支持谷歌数据存储支持的所有本机程序。
为什么,动机
如果您使用的是单一编程语言的google数据存储,则可以利用 该编程语言的多个数据存储格式之一。这些orms允许您定义 为您的数据库模型建立架构,并使用本地编程语言类型对其进行操作。
当您希望使用来自 多种编程语言。
这个问题有多种解决方案,但一种方法是定义某种模型 编程语言不可知的模式。
而这个图书馆正试图做到这一点。它使用原生protobuf消息定义作为模式 对于数据库模型。这样,这些定义就可以被多个编程语言和 每种语言只需要一个轻量级的翻译库(比如这个库),它知道如何翻译 将任意protobuf对象转换为实体protobuf对象,反之亦然。
功能
现在,库支持以下protobuf字段类型和功能:
所有简单类型(string、int32、int64、double、float、bytes、bool、enum)
标量/容器类型(映射,重复)
protobuf标准库中的复杂类型(
google.protobuf.timestamp
,google.protobuf.struct
,google.types.latlng
)使用来自不同protobuf定义文件的导入和引用类型。例如, 您可以将protobuf消息定义称为
model1db
文件内部model1.proto 有一个引用
model2db
frommodel2.proto
文件的字段。为此,您需要确保包含所有生成的 protobuf python文件位于
pythonpath
例如,如果生成的文件写入
my_app/generated/
,my_app/generated/
需要 要进入pythonpath,这个目录需要是一个python包(它需要包含初始化文件。
有关google数据存储支持的实际类型的更多信息,请参阅 https://cloud.google.com/datastore/docs/concepts/entities properties_and_value_types
支持的Python版本:
- python 2.7版
- python 3.6
- 巨蟒3.7
它可能也适用于Python3.4和3.5,但我们不针对这些版本进行测试。
用法
这个库公开了三种主要的公共方法。
model_pb_to_entity_pb(model_pb,exclude_falsy_values=false,exclude_from_index=none)
此方法将任意protobuf消息对象转换为实体protobuf对象,后者可以 与谷歌数据存储一起使用。
例如:
fromgoogle.cloudimportdatastorefromgoogle.protobuf.timestamp_pb2importTimestampfromprotobuf_cloud_datastore_translatorimportmodel_pb_to_entity_pbfromgenerated.protobuf.modelsimportmy_model_pb2# 1. Store your database model object which is represented using a custom Protobuf message class# instance inside Google Datastore# Create database model Protobuf instancemodel_pb=my_model_pb2.MyModelDB()# Other entity attributesmodel_pb.key1='value1'model_pb.key2=200model_pb.parameters['foo']='bar'model_pb.parameters['bar']='baz'start_time_timestamp=Timestamp()start_time_timestamp.GetCurrentTime()model_pb.start_time=start_time_timestamp# Convert it to Entity Protobuf object which can be used with Google Datastoreentity_pb=model_pb_to_entity_pb(model_pb)# Store it in the datastoreclient=Client(...)key=self.client.key('MyModelDB','some_primary_key')entity_pb_translated.key.CopyFrom(key.to_protobuf())entity=datastore.helpers.entity_from_protobuf(entity_pb)client.put(entity)
带"U键"到"实体"的"U PB"模型(客户端,模型"U PB",exclude"falsy"值=false,exclude"from"索引=none)
为了方便起见,该库还将model_pb_暴露给了实体_pb
方法。这种方法假定
protobuf消息中有一个特殊的键
主键。
下面,这个方法推断实体组合的project\u id
和namespace\u id
部分
传递给此方法的客户端
对象的主键。推断出实体种类
从protobuf消息模型名称。例如,如果protobuf消息模型名是
userinfodb
,实体类型将设置为userinfodb
例如:
fromgoogle.cloudimportdatastorefromprotobuf_cloud_datastore_translatorimportmodel_pb_to_entity_pbmodel_pb=my_model_pb2.MyModelDB()model_pb.key='key-1234'# set model fields# ...client=Client(project='my-project',namespace='my-namespace')entity_pb=model_pb_to_entity_pb(model_pb)# Store it in the datastoreentity=datastore.helpers.entity_from_protobuf(entity_pb)client.put(entity)# In this scenario, actual key would look the same if you manually constructed it like this:key=client.key('MyModelDB','key-1234',project='my-project',namespace='my-namespace')
实体PB到模型PB(模型PB类,实体PB,strict=false)
此方法将google数据存储返回的原始实体protobuf对象转换为提供的 protobuf消息类。
默认情况下,在数据存储实体protobuf对象上找到的字段,但在
protobuf消息类被忽略。如果希望在这种情况下引发异常,则
可以将strict=true
参数传递给方法。
例如:
key=client.key('MyModelDB','some_primary_key')entity=client.get(key)entity_pb=datastore.helpers.entity_to_protobuf(entity)model_pb=entity_pb_to_model_pb(my_model_pb2.MyModelPB,entity_pb)print(model_pb)
从索引中排除protobuf模型字段
默认情况下,google cloud datstore会自动索引每个实体(模型)属性。
为每个字段(实体属性)编制索引通常是不需要的。它也有一些
限制(例如,要索引的简单字段的大小限制为1500
字节等)。此外,不必要的索引还会增加存储空间的消耗。
此库允许您根据字段定义要从索引中排除的模型字段 利用protobuf字段选项扩展。
例如:
syntax="proto3";import"google/protobuf/descriptor.proto";// Custom Protobuf option which specifies which model fields should be excluded// from index// NOTE: Keep in mind that it's important not to change the option name// ("exclude_from_index") since this library uses that special option name to// determine if a field should be excluded from index.extendgoogle.protobuf.FieldOptions{boolexclude_from_index=50000;}messageExampleDBModelWithOptions1{stringstring_key_one=1[(exclude_from_index)=true];stringstring_key_two=2;stringstring_key_three=3[(exclude_from_index)=true];stringstring_key_four=4;int32int32_field_one=5;int32int32_field_two=6[(exclude_from_index)=true];}
在本例中,字段string_key_one
,string_key_three
和int32_field_two
将不会是
索引(https://cloud.google.com/datastore/docs/concepts/index未索引的属性)。
在本例中,字段选项扩展名在定义模型的同一文件中定义,但在
实际上,您可能会在自定义protobuf文件(例如
field_options.proto
)并将该文件包含在包含数据库模型的其他文件中
定义。
请记住,如果在在ide包中,该包需要与 存放模型的包装。
例如:
protobuf/models/field\u options.proto
:
syntax="proto3";packagemodels;import"google/protobuf/descriptor.proto";// Custom Protobuf option which specifies which model fields should be excluded// from index// NOTE: Keep in mind that it's important not to change the option name// ("exclude_from_index") since this library uses that special option name to// determine if a field should be excluded from index.extendgoogle.protobuf.FieldOptions{boolexclude_from_index=50000;}
protobuf/models/my_model.proto
:
syntax="proto3";packagemodels;import"models/field_options.proto";messageExampleDBModelWithOptions1{stringstring_key_one=1[(exclude_from_index)=true];stringstring_key_two=2;stringstring_key_three=3[(exclude_from_index)=true];stringstring_key_four=4;int32int32_field_one=5;int32int32_field_two=6[(exclude_from_index)=true];}
有问题
在protobuf语法版本3中,字段被设置的概念已经被删除,并与 默认值的概念。这意味着即使没有设置字段,默认值 将返回特定于该字段类型的。
就这个库而言,这意味着在转换/翻译protobuf时 对象,转换后的对象仍将包含以下字段的默认值 未设置。
例如,这两个调用的输出/最终结果将相同:
# Field values are explicitly provided, but they match default valuesexample_pb=example_pb2.ExampleDBModel()example_pb.bool_key=Falseexample_pb.string_key=''example_pb.int32_key=0example_pb.int64_key=0example_pb.double_key=0.0example_pb.float_key=0.0example_pb.enum_key=example_pb2.ExampleEnumModel.ENUM0example_pb.bool_key=Falseexample_pb.bytes_key=b''example_pb.null_key=1entity_pb_translated=model_pb_to_entity_pb(example_pb)print(entity_pb_translated)# No field values are provided, implicit default values are used during serializationexample_pb=example_pb2.ExampleDBModel()entity_pb_translated=model_pb_to_entity_pb(example_pb)print(entity_pb_translated)
如果不希望在转换的实体protobuf对象上设置默认值并存储
在数据存储中,您可以将exclude\u falsy\u values=true
参数传递给
模式PB到实体PB
方法。
有关详细信息,请参见:
- https://developers.google.com/protocol buffers/docs/reference/python-generated
- https://github.com/protocolbuffers/protobuf/issues/1606
- https://github.com/googleapis/google cloud python/issues/1402
- https://github.com/googleapis/google cloud python/pull/1450
- https://github.com/googleapis/google cloud python/pull/1329
示例
例如protobuf消息定义,请参见protobuf/
目录。
示例用法:
fromgoogle.cloudimportdatastorefromprotobuf_cloud_datastore_translatorimportmodel_pb_to_entity_pbfromprotobuf_cloud_datastore_translatorimportentity_pb_to_model_pbfromgenerated.protobuf.modelsimportmy_model_pb2# 1. Store your database model object which is represented using a custom Protobuf message class# instance inside Google Datastore# Create database model Protobuf instancemodel_pb=my_model_pb2.MyModelDB()model_pb.key1='value1'model_pb.key2=200# Convert it to Entity Protobuf object which can be used with Google Datastoreentity_pb=model_pb_to_entity_pb(model_pb)# Store it in the datastore# To avoid conversion back and forth you can also use lower level client methods which# work directly with the Entity Protobuf objects# For information on the low level client usage, see# https://github.com/GoogleCloudPlatform/google-cloud-datastore/blob/master/python/demos/trivial/adams.py#L66client=Client(...)key=self.client.key('MyModelDB','some_primary_key')entity_pb_translated.key.CopyFrom(key.to_protobuf())entity=datastore.helpers.entity_from_protobuf(entity_pb)client.put(entity)# 2. Retrieve entity from the datastore and convert it to your Protobuf DB model instance class# Same here - you can also use low level client to retrieve Entity protobuf object directly and# avoid unnecessary conversion round tripkey=client.key('MyModelDB','some_primary_key')entity=client.get(key)entity_pb=datastore.helpers.entity_to_protobuf(entity)model_pb=entity_pb_to_model_pb(my_model_pb2.MyModelPB,entity_pb)print(model_pb)
其他编程语言的转换程序库
本节包含其他编程语言的翻译库列表,这些语言提供 同样的功能。
测试
单元和集成测试可以在tests/
目录中找到。
您可以使用tox运行单元和集成测试以及其他lint检查。
# Run all tox targets tox # Run only lint checks tox -e lint # Run unit tests under Python 2.7 tox -e py2.7-unit-tests # Run Integration tests under Python 3.7 tox -e py3.7-integration-tests # Run unit and integration tests and generate and display code coverage report tox -e coverage
注1:集成测试依赖于要运行的google云数据存储模拟器
(/scripts/run datastore emulator.sh
)。
注2:集成测试也运行跨编程语言兼容性测试 验证python和go翻译库是否产生完全相同的输出。像这样的, 这些测试还要求在系统上安装golang>;=1.12。
许可证
版权所有2019 Tomaz Muraus
根据apache许可证2.0版(以下简称"许可证")授权;您不得使用本作品,除非 符合许可证。您可以在许可证文件中获取许可证的副本, 或在:
http://www.apache.org/licenses/license-2.0
通过供款,您同意这些供款是您自己(或由您的雇主批准)的,并且 您向 根据项目许可证,当前和未来的项目。