diff --git a/example/example_proto/demo/alias_demo.proto b/example/example_proto/demo/alias_demo.proto new file mode 100644 index 0000000..940bc0a --- /dev/null +++ b/example/example_proto/demo/alias_demo.proto @@ -0,0 +1,30 @@ +// fix issue: #74 https://github.com/so1n/protobuf_to_pydantic/issues/74 +syntax = "proto3"; +package alias_demo; + +import "google/protobuf/timestamp.proto"; + + + +// Annotations are used in runtime mode +// p2p: {"oneof:data": {"required": true}} +// p2p: {"oneof:data": {"oneof_extend": {"optional": ["location_value"]}}} +message ReportData { + // Annotations are used in plugin mode + // p2p: {"required": true, "oneof_extend": {"optional": ["location_value"]}} + oneof data { + GeoLocation location_value = 5; + google.protobuf.Timestamp time_value = 6; + } +} + +message GeoLocation { + float latitude = 1; + float longitude = 2; + optional double altitude_meters = 3; +} + +message Report { + optional string source_id = 2; + ReportData data = 3; +} diff --git a/example/gen_simple_code.py b/example/gen_simple_code.py index 2ac4e93..ac936ce 100644 --- a/example/gen_simple_code.py +++ b/example/gen_simple_code.py @@ -32,7 +32,7 @@ def gen_code() -> None: pydantic_model_to_py_file( str(now_path.parent.joinpath(target_p, "demo_gen_code.py")), - *[msg_to_pydantic_model(model) for model in message_class_list], + *[msg_to_pydantic_model(model) for model in message_class_list if model.__name__ == "OptionalMessage"], ) diff --git a/example/plugin_config.py b/example/plugin_config.py index e792f12..696fa90 100644 --- a/example/plugin_config.py +++ b/example/plugin_config.py @@ -10,7 +10,7 @@ from protobuf_to_pydantic.plugin.config import SubConfigModel from protobuf_to_pydantic.template import Template -from . import all_field_set_option_config, single_config_pkg_plugin_config +from . import all_field_set_option_config, populate_by_name_plugin_config, single_config_pkg_plugin_config logging.basicConfig(format="[%(asctime)s %(levelname)s] %(message)s", datefmt="%y-%m-%d %H:%M:%S", level=logging.INFO) @@ -52,4 +52,5 @@ def exp_time() -> float: pkg_config: Dict[str, SubConfigModel] = { "all_field_set_optional": SubConfigModel(module=all_field_set_option_config, use_root_config=True), "single_config": SubConfigModel(module=single_config_pkg_plugin_config), + "alias_demo": SubConfigModel(module=populate_by_name_plugin_config, use_root_config=True), } diff --git a/example/populate_by_name_plugin_config.py b/example/populate_by_name_plugin_config.py new file mode 100644 index 0000000..c24ba21 --- /dev/null +++ b/example/populate_by_name_plugin_config.py @@ -0,0 +1,31 @@ +from pydantic import BaseModel, ConfigDict + +from protobuf_to_pydantic._pydantic_adapter import VERSION + +try: + from pydantic.alias_generators import to_camel +except ImportError: + + def to_camel(string: str) -> str: # type: ignore[misc] + return "".join(word.capitalize() for word in string.split("_")) + + +if VERSION < "2.6.0": + + class MyBaseSchema(BaseModel): + model_config = ConfigDict( + alias_generator=to_camel, + populate_by_name=True, + ) + +else: + from pydantic import AliasGenerator + + class MyBaseSchema(BaseModel): # type: ignore[no-redef] + model_config = ConfigDict( + alias_generator=AliasGenerator(validation_alias=to_camel), + populate_by_name=True, + ) + + +base_model_class = MyBaseSchema diff --git a/example/proto_3_20_pydanticv1/demo_gen_code.py b/example/proto_3_20_pydanticv1/demo_gen_code.py index 3993aed..5e55120 100644 --- a/example/proto_3_20_pydanticv1/demo_gen_code.py +++ b/example/proto_3_20_pydanticv1/demo_gen_code.py @@ -1,49 +1,13 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing -from datetime import datetime -from enum import IntEnum -from google.protobuf.field_mask_pb2 import FieldMask # type: ignore -from google.protobuf.wrappers_pb2 import DoubleValue # type: ignore from protobuf_to_pydantic.customer_validator.v1 import check_one_of from pydantic import BaseModel, Field, root_validator -class AfterReferMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - - -class AnOtherMessage(BaseModel): - class SubMessage(BaseModel): - text: str = Field(default="") - - field1: str = Field(default="") - field2: SubMessage = Field() - - -class EmptyMessage(BaseModel): - pass - - -class InvoiceItem2(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List["InvoiceItem2"] = Field(default_factory=list) - invoice: "Invoice3" = Field() - - -class Invoice3(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List[InvoiceItem2] = Field(default_factory=list) - - class InvoiceItem(BaseModel): name: str = Field(default="") amount: int = Field(default=0) @@ -51,71 +15,6 @@ class InvoiceItem(BaseModel): items: typing.List["InvoiceItem"] = Field(default_factory=list) -class SexType(IntEnum): - man = 0 - women = 1 - - -class ExampleExampleProtoCommonSingleDemoEnum(IntEnum): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoEnum protobuf path:example/example_proto/common/single.proto""" - - zero = 0 - one = 1 - two = 3 - - -class ExampleExampleProtoCommonSingleDemoMessage(BaseModel): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoMessage protobuf path:example/example_proto/common/single.proto""" - - earth: str = Field(default="") - mercury: str = Field(default="") - mars: str = Field(default="") - - -class UserMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - height: float = Field(default=0.0) - sex: SexType = Field(default=0) - demo: ExampleExampleProtoCommonSingleDemoEnum = Field(default=0) - is_adult: bool = Field(default=False) - user_name: str = Field(default="") - demo_message: ExampleExampleProtoCommonSingleDemoMessage = Field() - - -class MapMessage(BaseModel): - user_map: typing.Dict[str, UserMessage] = Field(default_factory=dict) - user_flag: typing.Dict[str, bool] = Field(default_factory=dict) - - -class RepeatedMessage(BaseModel): - str_list: typing.List[str] = Field(default_factory=list) - int_list: typing.List[int] = Field(default_factory=list) - user_list: typing.List[UserMessage] = Field(default_factory=list) - - -class NestedMessage(BaseModel): - class UserPayMessage(BaseModel): - bank_number: str = Field(default="") - exp: datetime = Field(default_factory=datetime.now) - uuid: str = Field(default="") - - class IncludeEnum(IntEnum): - zero = 0 - one = 1 - two = 2 - - user_list_map: typing.Dict[str, RepeatedMessage] = Field(default_factory=dict) - user_map: typing.Dict[str, MapMessage] = Field(default_factory=dict) - user_pay: UserPayMessage = Field() - include_enum: IncludeEnum = Field(default=0) - not_enable_user_pay: UserPayMessage = Field() - empty: typing.Any = Field() - after_refer: AfterReferMessage = Field() - - class OptionalMessage(BaseModel): _one_of_dict = {"user.OptionalMessage.a": {"fields": {"x", "y"}, "required": False}} @@ -129,17 +28,3 @@ class OptionalMessage(BaseModel): default_template_test: float = Field(default=0.0) one_of_validator = root_validator(pre=True, allow_reuse=True)(check_one_of) - - -class OtherMessage(BaseModel): - class Config: - arbitrary_types_allowed = True - - metadata: typing.Dict[str, typing.Any] = Field(default_factory=dict) - double_value: DoubleValue = Field(default_factory=DoubleValue) - field_mask: typing.Optional[FieldMask] = Field(default_factory=FieldMask) - - -class RootMessage(BaseModel): - field1: str = Field(default="") - field2: AnOtherMessage = Field() diff --git a/example/proto_3_20_pydanticv1/demo_gen_code_by_p2p.py b/example/proto_3_20_pydanticv1/demo_gen_code_by_p2p.py index 9510a01..904db19 100644 --- a/example/proto_3_20_pydanticv1/demo_gen_code_by_p2p.py +++ b/example/proto_3_20_pydanticv1/demo_gen_code_by_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/demo_gen_code_by_pgv.py b/example/proto_3_20_pydanticv1/demo_gen_code_by_pgv.py index f9779fd..1a327b0 100644 --- a/example/proto_3_20_pydanticv1/demo_gen_code_by_pgv.py +++ b/example/proto_3_20_pydanticv1/demo_gen_code_by_pgv.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py b/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py index afd1f40..ba35f55 100644 --- a/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py +++ b/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_pyi.py b/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_pyi.py index afd1f40..ba35f55 100644 --- a/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_pyi.py +++ b/example/proto_3_20_pydanticv1/demo_gen_code_by_text_comment_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/common/single_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/common/single_p2p.py index 4b4763d..863df17 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/common/single_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/common/single_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 from enum import IntEnum diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_p2p.py new file mode 100644 index 0000000..46ff522 --- /dev/null +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_p2p.py @@ -0,0 +1,34 @@ +# This is an automatically generated file, please do not change +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) +# Protobuf Version: 3.20.3 +# Pydantic Version: 1.10.7 +import typing +from datetime import datetime + +from google.protobuf.message import Message # type: ignore +from pydantic import Field, root_validator + +from example.populate_by_name_plugin_config import MyBaseSchema +from protobuf_to_pydantic.customer_validator import check_one_of + + +class GeoLocation(MyBaseSchema): + latitude: float = Field(default=0.0) + longitude: float = Field(default=0.0) + altitude_meters: typing.Optional[float] = Field(default=0.0) + + +class ReportData(MyBaseSchema): + """ + Annotations are used in runtime mode + """ + + _one_of_dict = {"ReportData.data": {"fields": {"location_value", "time_value"}, "required": True}} + one_of_validator = root_validator(pre=True, allow_reuse=True)(check_one_of) + location_value: typing.Optional[GeoLocation] = Field(default=None) + time_value: datetime = Field(default_factory=datetime.now) + + +class Report(MyBaseSchema): + source_id: typing.Optional[str] = Field(default="") + data: ReportData = Field() diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.py b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.py new file mode 100644 index 0000000..28af044 --- /dev/null +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: example/example_proto/demo/alias_demo.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='example/example_proto/demo/alias_demo.proto', + package='alias_demo', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n+example/example_proto/demo/alias_demo.proto\x12\nalias_demo\x1a\x1fgoogle/protobuf/timestamp.proto\"y\n\nReportData\x12\x31\n\x0elocation_value\x18\x05 \x01(\x0b\x32\x17.alias_demo.GeoLocationH\x00\x12\x30\n\ntime_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x42\x06\n\x04\x64\x61ta\"d\n\x0bGeoLocation\x12\x10\n\x08latitude\x18\x01 \x01(\x02\x12\x11\n\tlongitude\x18\x02 \x01(\x02\x12\x1c\n\x0f\x61ltitude_meters\x18\x03 \x01(\x01H\x00\x88\x01\x01\x42\x12\n\x10_altitude_meters\"T\n\x06Report\x12\x16\n\tsource_id\x18\x02 \x01(\tH\x00\x88\x01\x01\x12$\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x16.alias_demo.ReportDataB\x0c\n\n_source_idb\x06proto3' + , + dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + + + + +_REPORTDATA = _descriptor.Descriptor( + name='ReportData', + full_name='alias_demo.ReportData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='location_value', full_name='alias_demo.ReportData.location_value', index=0, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='time_value', full_name='alias_demo.ReportData.time_value', index=1, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='data', full_name='alias_demo.ReportData.data', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=92, + serialized_end=213, +) + + +_GEOLOCATION = _descriptor.Descriptor( + name='GeoLocation', + full_name='alias_demo.GeoLocation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='latitude', full_name='alias_demo.GeoLocation.latitude', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='longitude', full_name='alias_demo.GeoLocation.longitude', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='altitude_meters', full_name='alias_demo.GeoLocation.altitude_meters', index=2, + number=3, type=1, cpp_type=5, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='_altitude_meters', full_name='alias_demo.GeoLocation._altitude_meters', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=215, + serialized_end=315, +) + + +_REPORT = _descriptor.Descriptor( + name='Report', + full_name='alias_demo.Report', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='source_id', full_name='alias_demo.Report.source_id', index=0, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='data', full_name='alias_demo.Report.data', index=1, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='_source_id', full_name='alias_demo.Report._source_id', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=317, + serialized_end=401, +) + +_REPORTDATA.fields_by_name['location_value'].message_type = _GEOLOCATION +_REPORTDATA.fields_by_name['time_value'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_REPORTDATA.oneofs_by_name['data'].fields.append( + _REPORTDATA.fields_by_name['location_value']) +_REPORTDATA.fields_by_name['location_value'].containing_oneof = _REPORTDATA.oneofs_by_name['data'] +_REPORTDATA.oneofs_by_name['data'].fields.append( + _REPORTDATA.fields_by_name['time_value']) +_REPORTDATA.fields_by_name['time_value'].containing_oneof = _REPORTDATA.oneofs_by_name['data'] +_GEOLOCATION.oneofs_by_name['_altitude_meters'].fields.append( + _GEOLOCATION.fields_by_name['altitude_meters']) +_GEOLOCATION.fields_by_name['altitude_meters'].containing_oneof = _GEOLOCATION.oneofs_by_name['_altitude_meters'] +_REPORT.fields_by_name['data'].message_type = _REPORTDATA +_REPORT.oneofs_by_name['_source_id'].fields.append( + _REPORT.fields_by_name['source_id']) +_REPORT.fields_by_name['source_id'].containing_oneof = _REPORT.oneofs_by_name['_source_id'] +DESCRIPTOR.message_types_by_name['ReportData'] = _REPORTDATA +DESCRIPTOR.message_types_by_name['GeoLocation'] = _GEOLOCATION +DESCRIPTOR.message_types_by_name['Report'] = _REPORT +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ReportData = _reflection.GeneratedProtocolMessageType('ReportData', (_message.Message,), { + 'DESCRIPTOR' : _REPORTDATA, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.ReportData) + }) +_sym_db.RegisterMessage(ReportData) + +GeoLocation = _reflection.GeneratedProtocolMessageType('GeoLocation', (_message.Message,), { + 'DESCRIPTOR' : _GEOLOCATION, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.GeoLocation) + }) +_sym_db.RegisterMessage(GeoLocation) + +Report = _reflection.GeneratedProtocolMessageType('Report', (_message.Message,), { + 'DESCRIPTOR' : _REPORT, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.Report) + }) +_sym_db.RegisterMessage(Report) + + +# @@protoc_insertion_point(module_scope) diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi new file mode 100644 index 0000000..5ad47f9 --- /dev/null +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi @@ -0,0 +1,70 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import google.protobuf.timestamp_pb2 +import typing +import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class ReportData(google.protobuf.message.Message): + """Annotations are used in runtime mode + p2p: {"oneof:data": {"required": true}} + p2p: {"oneof:data": {"oneof_extend": {"optional": ["location_value"]}}} + """ + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LOCATION_VALUE_FIELD_NUMBER: builtins.int + TIME_VALUE_FIELD_NUMBER: builtins.int + @property + def location_value(self) -> global___GeoLocation: ... + @property + def time_value(self) -> google.protobuf.timestamp_pb2.Timestamp: ... + def __init__(self, + *, + location_value: typing.Optional[global___GeoLocation] = ..., + time_value: typing.Optional[google.protobuf.timestamp_pb2.Timestamp] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["data",b"data"]) -> typing.Optional[typing_extensions.Literal["location_value","time_value"]]: ... +global___ReportData = ReportData + +class GeoLocation(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LATITUDE_FIELD_NUMBER: builtins.int + LONGITUDE_FIELD_NUMBER: builtins.int + ALTITUDE_METERS_FIELD_NUMBER: builtins.int + latitude: builtins.float + longitude: builtins.float + altitude_meters: builtins.float + def __init__(self, + *, + latitude: builtins.float = ..., + longitude: builtins.float = ..., + altitude_meters: typing.Optional[builtins.float] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters","latitude",b"latitude","longitude",b"longitude"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_altitude_meters",b"_altitude_meters"]) -> typing.Optional[typing_extensions.Literal["altitude_meters"]]: ... +global___GeoLocation = GeoLocation + +class Report(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SOURCE_ID_FIELD_NUMBER: builtins.int + DATA_FIELD_NUMBER: builtins.int + source_id: typing.Text + @property + def data(self) -> global___ReportData: ... + def __init__(self, + *, + source_id: typing.Optional[typing.Text] = ..., + data: typing.Optional[global___ReportData] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_source_id",b"_source_id"]) -> typing.Optional[typing_extensions.Literal["source_id"]]: ... +global___Report = Report diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py index 67c2b26..fc2074e 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/demo/demo_p2p.py index 784f70c..e99f31f 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/demo/demo_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/demo/single_config_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/demo/single_config_p2p.py index 9856c98..c3957a3 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/demo/single_config_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/demo/single_config_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 from google.protobuf.message import Message # type: ignore diff --git a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py index c7632e4..fd1af4a 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py index c0492ab..fa5768f 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py index 0b56371..d429920 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py index 0b56371..d429920 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv1/example/example_proto/validate/demo_p2p.py b/example/proto_3_20_pydanticv1/example/example_proto/validate/demo_p2p.py index c9dfd25..7c4d764 100644 --- a/example/proto_3_20_pydanticv1/example/example_proto/validate/demo_p2p.py +++ b/example/proto_3_20_pydanticv1/example/example_proto/validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_3_20_pydanticv2/demo_gen_code.py b/example/proto_3_20_pydanticv2/demo_gen_code.py index c3f9f97..d883fef 100644 --- a/example/proto_3_20_pydanticv2/demo_gen_code.py +++ b/example/proto_3_20_pydanticv2/demo_gen_code.py @@ -1,47 +1,11 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing -from datetime import datetime -from enum import IntEnum -from google.protobuf.field_mask_pb2 import FieldMask # type: ignore -from google.protobuf.wrappers_pb2 import DoubleValue # type: ignore from protobuf_to_pydantic.customer_validator.v2 import check_one_of -from pydantic import BaseModel, ConfigDict, Field, model_validator - - -class AfterReferMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - - -class AnOtherMessage(BaseModel): - class SubMessage(BaseModel): - text: str = Field(default="") - - field1: str = Field(default="") - field2: SubMessage = Field() - - -class EmptyMessage(BaseModel): - pass - - -class InvoiceItem2(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List["InvoiceItem2"] = Field(default_factory=list) - invoice: "Invoice3" = Field() - - -class Invoice3(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List[InvoiceItem2] = Field(default_factory=list) +from pydantic import BaseModel, Field, model_validator class InvoiceItem(BaseModel): @@ -51,71 +15,6 @@ class InvoiceItem(BaseModel): items: typing.List["InvoiceItem"] = Field(default_factory=list) -class SexType(IntEnum): - man = 0 - women = 1 - - -class ExampleExampleProtoCommonSingleDemoEnum(IntEnum): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoEnum protobuf path:example/example_proto/common/single.proto""" - - zero = 0 - one = 1 - two = 3 - - -class ExampleExampleProtoCommonSingleDemoMessage(BaseModel): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoMessage protobuf path:example/example_proto/common/single.proto""" - - earth: str = Field(default="") - mercury: str = Field(default="") - mars: str = Field(default="") - - -class UserMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - height: float = Field(default=0.0) - sex: SexType = Field(default=0) - demo: ExampleExampleProtoCommonSingleDemoEnum = Field(default=0) - is_adult: bool = Field(default=False) - user_name: str = Field(default="") - demo_message: ExampleExampleProtoCommonSingleDemoMessage = Field() - - -class MapMessage(BaseModel): - user_map: typing.Dict[str, UserMessage] = Field(default_factory=dict) - user_flag: typing.Dict[str, bool] = Field(default_factory=dict) - - -class RepeatedMessage(BaseModel): - str_list: typing.List[str] = Field(default_factory=list) - int_list: typing.List[int] = Field(default_factory=list) - user_list: typing.List[UserMessage] = Field(default_factory=list) - - -class NestedMessage(BaseModel): - class UserPayMessage(BaseModel): - bank_number: str = Field(default="") - exp: datetime = Field(default_factory=datetime.now) - uuid: str = Field(default="") - - class IncludeEnum(IntEnum): - zero = 0 - one = 1 - two = 2 - - user_list_map: typing.Dict[str, RepeatedMessage] = Field(default_factory=dict) - user_map: typing.Dict[str, MapMessage] = Field(default_factory=dict) - user_pay: UserPayMessage = Field() - include_enum: IncludeEnum = Field(default=0) - not_enable_user_pay: UserPayMessage = Field() - empty: typing.Any = Field() - after_refer: AfterReferMessage = Field() - - class OptionalMessage(BaseModel): _one_of_dict = {"user.OptionalMessage.a": {"fields": {"x", "y"}, "required": False}} @@ -129,16 +28,3 @@ class OptionalMessage(BaseModel): default_template_test: float = Field(default=0.0) one_of_validator = model_validator(mode="before")(check_one_of) - - -class OtherMessage(BaseModel): - model_config = ConfigDict(arbitrary_types_allowed=True) - - metadata: typing.Dict[str, typing.Any] = Field(default_factory=dict) - double_value: DoubleValue = Field(default_factory=DoubleValue) - field_mask: typing.Optional[FieldMask] = Field(default_factory=FieldMask) - - -class RootMessage(BaseModel): - field1: str = Field(default="") - field2: AnOtherMessage = Field() diff --git a/example/proto_3_20_pydanticv2/demo_gen_code_by_p2p.py b/example/proto_3_20_pydanticv2/demo_gen_code_by_p2p.py index a793ca6..e76e6d5 100644 --- a/example/proto_3_20_pydanticv2/demo_gen_code_by_p2p.py +++ b/example/proto_3_20_pydanticv2/demo_gen_code_by_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/demo_gen_code_by_pgv.py b/example/proto_3_20_pydanticv2/demo_gen_code_by_pgv.py index 61f41f6..4d976e3 100644 --- a/example/proto_3_20_pydanticv2/demo_gen_code_by_pgv.py +++ b/example/proto_3_20_pydanticv2/demo_gen_code_by_pgv.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py b/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py index b6b1c12..220b01e 100644 --- a/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py +++ b/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_pyi.py b/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_pyi.py index b6b1c12..220b01e 100644 --- a/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_pyi.py +++ b/example/proto_3_20_pydanticv2/demo_gen_code_by_text_comment_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/common/single_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/common/single_p2p.py index fbf9564..9a7adac 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/common/single_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/common/single_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 from enum import IntEnum diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_p2p.py new file mode 100644 index 0000000..7e77004 --- /dev/null +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_p2p.py @@ -0,0 +1,36 @@ +# This is an automatically generated file, please do not change +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) +# Protobuf Version: 3.20.3 +# Pydantic Version: 2.5.3 +import typing +from datetime import datetime + +from google.protobuf.message import Message # type: ignore +from pydantic import Field, model_validator + +from example.populate_by_name_plugin_config import MyBaseSchema +from protobuf_to_pydantic.customer_validator import check_one_of + + +class GeoLocation(MyBaseSchema): + latitude: float = Field(default=0.0) + longitude: float = Field(default=0.0) + altitude_meters: typing.Optional[float] = Field(default=0.0) + + +class ReportData(MyBaseSchema): + """ + Annotations are used in runtime mode + """ + + _one_of_dict = { + "ReportData.data": {"fields": {"locationValue", "location_value", "timeValue", "time_value"}, "required": True} + } + one_of_validator = model_validator(mode="before")(check_one_of) + location_value: typing.Optional[GeoLocation] = Field(default=None) + time_value: datetime = Field(default_factory=datetime.now) + + +class Report(MyBaseSchema): + source_id: typing.Optional[str] = Field(default="") + data: ReportData = Field() diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.py b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.py new file mode 100644 index 0000000..28af044 --- /dev/null +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: example/example_proto/demo/alias_demo.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='example/example_proto/demo/alias_demo.proto', + package='alias_demo', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n+example/example_proto/demo/alias_demo.proto\x12\nalias_demo\x1a\x1fgoogle/protobuf/timestamp.proto\"y\n\nReportData\x12\x31\n\x0elocation_value\x18\x05 \x01(\x0b\x32\x17.alias_demo.GeoLocationH\x00\x12\x30\n\ntime_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x42\x06\n\x04\x64\x61ta\"d\n\x0bGeoLocation\x12\x10\n\x08latitude\x18\x01 \x01(\x02\x12\x11\n\tlongitude\x18\x02 \x01(\x02\x12\x1c\n\x0f\x61ltitude_meters\x18\x03 \x01(\x01H\x00\x88\x01\x01\x42\x12\n\x10_altitude_meters\"T\n\x06Report\x12\x16\n\tsource_id\x18\x02 \x01(\tH\x00\x88\x01\x01\x12$\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x16.alias_demo.ReportDataB\x0c\n\n_source_idb\x06proto3' + , + dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) + + + + +_REPORTDATA = _descriptor.Descriptor( + name='ReportData', + full_name='alias_demo.ReportData', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='location_value', full_name='alias_demo.ReportData.location_value', index=0, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='time_value', full_name='alias_demo.ReportData.time_value', index=1, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='data', full_name='alias_demo.ReportData.data', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=92, + serialized_end=213, +) + + +_GEOLOCATION = _descriptor.Descriptor( + name='GeoLocation', + full_name='alias_demo.GeoLocation', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='latitude', full_name='alias_demo.GeoLocation.latitude', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='longitude', full_name='alias_demo.GeoLocation.longitude', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='altitude_meters', full_name='alias_demo.GeoLocation.altitude_meters', index=2, + number=3, type=1, cpp_type=5, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='_altitude_meters', full_name='alias_demo.GeoLocation._altitude_meters', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=215, + serialized_end=315, +) + + +_REPORT = _descriptor.Descriptor( + name='Report', + full_name='alias_demo.Report', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='source_id', full_name='alias_demo.Report.source_id', index=0, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='data', full_name='alias_demo.Report.data', index=1, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='_source_id', full_name='alias_demo.Report._source_id', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=317, + serialized_end=401, +) + +_REPORTDATA.fields_by_name['location_value'].message_type = _GEOLOCATION +_REPORTDATA.fields_by_name['time_value'].message_type = google_dot_protobuf_dot_timestamp__pb2._TIMESTAMP +_REPORTDATA.oneofs_by_name['data'].fields.append( + _REPORTDATA.fields_by_name['location_value']) +_REPORTDATA.fields_by_name['location_value'].containing_oneof = _REPORTDATA.oneofs_by_name['data'] +_REPORTDATA.oneofs_by_name['data'].fields.append( + _REPORTDATA.fields_by_name['time_value']) +_REPORTDATA.fields_by_name['time_value'].containing_oneof = _REPORTDATA.oneofs_by_name['data'] +_GEOLOCATION.oneofs_by_name['_altitude_meters'].fields.append( + _GEOLOCATION.fields_by_name['altitude_meters']) +_GEOLOCATION.fields_by_name['altitude_meters'].containing_oneof = _GEOLOCATION.oneofs_by_name['_altitude_meters'] +_REPORT.fields_by_name['data'].message_type = _REPORTDATA +_REPORT.oneofs_by_name['_source_id'].fields.append( + _REPORT.fields_by_name['source_id']) +_REPORT.fields_by_name['source_id'].containing_oneof = _REPORT.oneofs_by_name['_source_id'] +DESCRIPTOR.message_types_by_name['ReportData'] = _REPORTDATA +DESCRIPTOR.message_types_by_name['GeoLocation'] = _GEOLOCATION +DESCRIPTOR.message_types_by_name['Report'] = _REPORT +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +ReportData = _reflection.GeneratedProtocolMessageType('ReportData', (_message.Message,), { + 'DESCRIPTOR' : _REPORTDATA, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.ReportData) + }) +_sym_db.RegisterMessage(ReportData) + +GeoLocation = _reflection.GeneratedProtocolMessageType('GeoLocation', (_message.Message,), { + 'DESCRIPTOR' : _GEOLOCATION, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.GeoLocation) + }) +_sym_db.RegisterMessage(GeoLocation) + +Report = _reflection.GeneratedProtocolMessageType('Report', (_message.Message,), { + 'DESCRIPTOR' : _REPORT, + '__module__' : 'example.example_proto.demo.alias_demo_pb2' + # @@protoc_insertion_point(class_scope:alias_demo.Report) + }) +_sym_db.RegisterMessage(Report) + + +# @@protoc_insertion_point(module_scope) diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi new file mode 100644 index 0000000..5ad47f9 --- /dev/null +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi @@ -0,0 +1,70 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import google.protobuf.timestamp_pb2 +import typing +import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class ReportData(google.protobuf.message.Message): + """Annotations are used in runtime mode + p2p: {"oneof:data": {"required": true}} + p2p: {"oneof:data": {"oneof_extend": {"optional": ["location_value"]}}} + """ + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LOCATION_VALUE_FIELD_NUMBER: builtins.int + TIME_VALUE_FIELD_NUMBER: builtins.int + @property + def location_value(self) -> global___GeoLocation: ... + @property + def time_value(self) -> google.protobuf.timestamp_pb2.Timestamp: ... + def __init__(self, + *, + location_value: typing.Optional[global___GeoLocation] = ..., + time_value: typing.Optional[google.protobuf.timestamp_pb2.Timestamp] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["data",b"data"]) -> typing.Optional[typing_extensions.Literal["location_value","time_value"]]: ... +global___ReportData = ReportData + +class GeoLocation(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LATITUDE_FIELD_NUMBER: builtins.int + LONGITUDE_FIELD_NUMBER: builtins.int + ALTITUDE_METERS_FIELD_NUMBER: builtins.int + latitude: builtins.float + longitude: builtins.float + altitude_meters: builtins.float + def __init__(self, + *, + latitude: builtins.float = ..., + longitude: builtins.float = ..., + altitude_meters: typing.Optional[builtins.float] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters","latitude",b"latitude","longitude",b"longitude"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_altitude_meters",b"_altitude_meters"]) -> typing.Optional[typing_extensions.Literal["altitude_meters"]]: ... +global___GeoLocation = GeoLocation + +class Report(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SOURCE_ID_FIELD_NUMBER: builtins.int + DATA_FIELD_NUMBER: builtins.int + source_id: typing.Text + @property + def data(self) -> global___ReportData: ... + def __init__(self, + *, + source_id: typing.Optional[typing.Text] = ..., + data: typing.Optional[global___ReportData] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_source_id",b"_source_id"]) -> typing.Optional[typing_extensions.Literal["source_id"]]: ... +global___Report = Report diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py index 98f8b88..d08294b 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/demo/demo_p2p.py index 37a29e2..5e42a1a 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/demo/demo_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/demo/single_config_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/demo/single_config_p2p.py index 6b56931..9318075 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/demo/single_config_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/demo/single_config_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 from google.protobuf.message import Message # type: ignore diff --git a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py index f96fcd5..30d7a57 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py index 5114ff6..4a178c5 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py index faa6c5d..6b3cd5b 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py index faa6c5d..6b3cd5b 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_3_20_pydanticv2/example/example_proto/validate/demo_p2p.py b/example/proto_3_20_pydanticv2/example/example_proto/validate/demo_p2p.py index d8353a4..a3c0069 100644 --- a/example/proto_3_20_pydanticv2/example/example_proto/validate/demo_p2p.py +++ b/example/proto_3_20_pydanticv2/example/example_proto/validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 3.20.3 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv1/demo_gen_code.py b/example/proto_pydanticv1/demo_gen_code.py index 8ee014e..f68f2ca 100644 --- a/example/proto_pydanticv1/demo_gen_code.py +++ b/example/proto_pydanticv1/demo_gen_code.py @@ -1,49 +1,13 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing -from datetime import datetime -from enum import IntEnum -from google.protobuf.field_mask_pb2 import FieldMask # type: ignore -from google.protobuf.wrappers_pb2 import DoubleValue # type: ignore from protobuf_to_pydantic.customer_validator.v1 import check_one_of from pydantic import BaseModel, Field, root_validator -class AfterReferMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - - -class AnOtherMessage(BaseModel): - class SubMessage(BaseModel): - text: str = Field(default="") - - field1: str = Field(default="") - field2: SubMessage = Field() - - -class EmptyMessage(BaseModel): - pass - - -class InvoiceItem2(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List["InvoiceItem2"] = Field(default_factory=list) - invoice: "Invoice3" = Field() - - -class Invoice3(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List[InvoiceItem2] = Field(default_factory=list) - - class InvoiceItem(BaseModel): name: str = Field(default="") amount: int = Field(default=0) @@ -51,71 +15,6 @@ class InvoiceItem(BaseModel): items: typing.List["InvoiceItem"] = Field(default_factory=list) -class SexType(IntEnum): - man = 0 - women = 1 - - -class ExampleExampleProtoCommonSingleDemoEnum(IntEnum): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoEnum protobuf path:example/example_proto/common/single.proto""" - - zero = 0 - one = 1 - two = 3 - - -class ExampleExampleProtoCommonSingleDemoMessage(BaseModel): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoMessage protobuf path:example/example_proto/common/single.proto""" - - earth: str = Field(default="") - mercury: str = Field(default="") - mars: str = Field(default="") - - -class UserMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - height: float = Field(default=0.0) - sex: SexType = Field(default=0) - demo: ExampleExampleProtoCommonSingleDemoEnum = Field(default=0) - is_adult: bool = Field(default=False) - user_name: str = Field(default="") - demo_message: ExampleExampleProtoCommonSingleDemoMessage = Field() - - -class MapMessage(BaseModel): - user_map: typing.Dict[str, UserMessage] = Field(default_factory=dict) - user_flag: typing.Dict[str, bool] = Field(default_factory=dict) - - -class RepeatedMessage(BaseModel): - str_list: typing.List[str] = Field(default_factory=list) - int_list: typing.List[int] = Field(default_factory=list) - user_list: typing.List[UserMessage] = Field(default_factory=list) - - -class NestedMessage(BaseModel): - class UserPayMessage(BaseModel): - bank_number: str = Field(default="") - exp: datetime = Field(default_factory=datetime.now) - uuid: str = Field(default="") - - class IncludeEnum(IntEnum): - zero = 0 - one = 1 - two = 2 - - user_list_map: typing.Dict[str, RepeatedMessage] = Field(default_factory=dict) - user_map: typing.Dict[str, MapMessage] = Field(default_factory=dict) - user_pay: UserPayMessage = Field() - include_enum: IncludeEnum = Field(default=0) - not_enable_user_pay: UserPayMessage = Field() - empty: typing.Any = Field() - after_refer: AfterReferMessage = Field() - - class OptionalMessage(BaseModel): _one_of_dict = {"user.OptionalMessage.a": {"fields": {"x", "y"}, "required": False}} @@ -129,17 +28,3 @@ class OptionalMessage(BaseModel): default_template_test: float = Field(default=0.0) one_of_validator = root_validator(pre=True, allow_reuse=True)(check_one_of) - - -class OtherMessage(BaseModel): - class Config: - arbitrary_types_allowed = True - - metadata: typing.Dict[str, typing.Any] = Field(default_factory=dict) - double_value: DoubleValue = Field(default_factory=DoubleValue) - field_mask: typing.Optional[FieldMask] = Field(default_factory=FieldMask) - - -class RootMessage(BaseModel): - field1: str = Field(default="") - field2: AnOtherMessage = Field() diff --git a/example/proto_pydanticv1/demo_gen_code_by_p2p.py b/example/proto_pydanticv1/demo_gen_code_by_p2p.py index f3c8dbd..7e1f024 100644 --- a/example/proto_pydanticv1/demo_gen_code_by_p2p.py +++ b/example/proto_pydanticv1/demo_gen_code_by_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/demo_gen_code_by_pgv.py b/example/proto_pydanticv1/demo_gen_code_by_pgv.py index 00ecd04..ada4944 100644 --- a/example/proto_pydanticv1/demo_gen_code_by_pgv.py +++ b/example/proto_pydanticv1/demo_gen_code_by_pgv.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py b/example/proto_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py index 8433545..07d4252 100644 --- a/example/proto_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py +++ b/example/proto_pydanticv1/demo_gen_code_by_text_comment_protobuf_field.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/demo_gen_code_by_text_comment_pyi.py b/example/proto_pydanticv1/demo_gen_code_by_text_comment_pyi.py index 8433545..07d4252 100644 --- a/example/proto_pydanticv1/demo_gen_code_by_text_comment_pyi.py +++ b/example/proto_pydanticv1/demo_gen_code_by_text_comment_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/common/single_p2p.py b/example/proto_pydanticv1/example/example_proto/common/single_p2p.py index 618e1d5..6a92476 100644 --- a/example/proto_pydanticv1/example/example_proto/common/single_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/common/single_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 from enum import IntEnum diff --git a/example/proto_pydanticv1/example/example_proto/demo/alias_demo_p2p.py b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_p2p.py new file mode 100644 index 0000000..32cbba3 --- /dev/null +++ b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_p2p.py @@ -0,0 +1,34 @@ +# This is an automatically generated file, please do not change +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) +# Protobuf Version: 4.24.4 +# Pydantic Version: 1.10.7 +import typing +from datetime import datetime + +from google.protobuf.message import Message # type: ignore +from pydantic import Field, root_validator + +from example.populate_by_name_plugin_config import MyBaseSchema +from protobuf_to_pydantic.customer_validator import check_one_of + + +class GeoLocation(MyBaseSchema): + latitude: float = Field(default=0.0) + longitude: float = Field(default=0.0) + altitude_meters: typing.Optional[float] = Field(default=0.0) + + +class ReportData(MyBaseSchema): + """ + Annotations are used in runtime mode + """ + + _one_of_dict = {"ReportData.data": {"fields": {"location_value", "time_value"}, "required": True}} + one_of_validator = root_validator(pre=True, allow_reuse=True)(check_one_of) + location_value: typing.Optional[GeoLocation] = Field(default=None) + time_value: datetime = Field(default_factory=datetime.now) + + +class Report(MyBaseSchema): + source_id: typing.Optional[str] = Field(default="") + data: ReportData = Field() diff --git a/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.py b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.py new file mode 100644 index 0000000..264b456 --- /dev/null +++ b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: example/example_proto/demo/alias_demo.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n+example/example_proto/demo/alias_demo.proto\x12\nalias_demo\x1a\x1fgoogle/protobuf/timestamp.proto\"y\n\nReportData\x12\x31\n\x0elocation_value\x18\x05 \x01(\x0b\x32\x17.alias_demo.GeoLocationH\x00\x12\x30\n\ntime_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x42\x06\n\x04\x64\x61ta\"d\n\x0bGeoLocation\x12\x10\n\x08latitude\x18\x01 \x01(\x02\x12\x11\n\tlongitude\x18\x02 \x01(\x02\x12\x1c\n\x0f\x61ltitude_meters\x18\x03 \x01(\x01H\x00\x88\x01\x01\x42\x12\n\x10_altitude_meters\"T\n\x06Report\x12\x16\n\tsource_id\x18\x02 \x01(\tH\x00\x88\x01\x01\x12$\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x16.alias_demo.ReportDataB\x0c\n\n_source_idb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'example.example_proto.demo.alias_demo_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _REPORTDATA._serialized_start=92 + _REPORTDATA._serialized_end=213 + _GEOLOCATION._serialized_start=215 + _GEOLOCATION._serialized_end=315 + _REPORT._serialized_start=317 + _REPORT._serialized_end=401 +# @@protoc_insertion_point(module_scope) diff --git a/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi new file mode 100644 index 0000000..5ad47f9 --- /dev/null +++ b/example/proto_pydanticv1/example/example_proto/demo/alias_demo_pb2.pyi @@ -0,0 +1,70 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import google.protobuf.timestamp_pb2 +import typing +import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class ReportData(google.protobuf.message.Message): + """Annotations are used in runtime mode + p2p: {"oneof:data": {"required": true}} + p2p: {"oneof:data": {"oneof_extend": {"optional": ["location_value"]}}} + """ + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LOCATION_VALUE_FIELD_NUMBER: builtins.int + TIME_VALUE_FIELD_NUMBER: builtins.int + @property + def location_value(self) -> global___GeoLocation: ... + @property + def time_value(self) -> google.protobuf.timestamp_pb2.Timestamp: ... + def __init__(self, + *, + location_value: typing.Optional[global___GeoLocation] = ..., + time_value: typing.Optional[google.protobuf.timestamp_pb2.Timestamp] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["data",b"data"]) -> typing.Optional[typing_extensions.Literal["location_value","time_value"]]: ... +global___ReportData = ReportData + +class GeoLocation(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LATITUDE_FIELD_NUMBER: builtins.int + LONGITUDE_FIELD_NUMBER: builtins.int + ALTITUDE_METERS_FIELD_NUMBER: builtins.int + latitude: builtins.float + longitude: builtins.float + altitude_meters: builtins.float + def __init__(self, + *, + latitude: builtins.float = ..., + longitude: builtins.float = ..., + altitude_meters: typing.Optional[builtins.float] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters","latitude",b"latitude","longitude",b"longitude"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_altitude_meters",b"_altitude_meters"]) -> typing.Optional[typing_extensions.Literal["altitude_meters"]]: ... +global___GeoLocation = GeoLocation + +class Report(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SOURCE_ID_FIELD_NUMBER: builtins.int + DATA_FIELD_NUMBER: builtins.int + source_id: typing.Text + @property + def data(self) -> global___ReportData: ... + def __init__(self, + *, + source_id: typing.Optional[typing.Text] = ..., + data: typing.Optional[global___ReportData] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_source_id",b"_source_id"]) -> typing.Optional[typing_extensions.Literal["source_id"]]: ... +global___Report = Report diff --git a/example/proto_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py b/example/proto_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py index 61e430c..f03b2ae 100644 --- a/example/proto_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/demo/demo_p2p.py b/example/proto_pydanticv1/example/example_proto/demo/demo_p2p.py index 8ae6813..5fe1ca8 100644 --- a/example/proto_pydanticv1/example/example_proto/demo/demo_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/demo/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/demo/single_config_p2p.py b/example/proto_pydanticv1/example/example_proto/demo/single_config_p2p.py index 8c6891b..ad2b209 100644 --- a/example/proto_pydanticv1/example/example_proto/demo/single_config_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/demo/single_config_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 from google.protobuf.message import Message # type: ignore diff --git a/example/proto_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py b/example/proto_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py index 055a4c6..36a7791 100644 --- a/example/proto_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/p2p_validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py index 596c902..e97d0e3 100644 --- a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py index 291720d..7337c2f 100644 --- a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py +++ b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py index 291720d..7337c2f 100644 --- a/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py +++ b/example/proto_pydanticv1/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv1/example/example_proto/validate/demo_p2p.py b/example/proto_pydanticv1/example/example_proto/validate/demo_p2p.py index fa6f094..8a1844c 100644 --- a/example/proto_pydanticv1/example/example_proto/validate/demo_p2p.py +++ b/example/proto_pydanticv1/example/example_proto/validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 1.10.7 import typing diff --git a/example/proto_pydanticv2/demo_gen_code.py b/example/proto_pydanticv2/demo_gen_code.py index bd48bce..1d4ce53 100644 --- a/example/proto_pydanticv2/demo_gen_code.py +++ b/example/proto_pydanticv2/demo_gen_code.py @@ -1,47 +1,11 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing -from datetime import datetime -from enum import IntEnum -from google.protobuf.field_mask_pb2 import FieldMask # type: ignore -from google.protobuf.wrappers_pb2 import DoubleValue # type: ignore from protobuf_to_pydantic.customer_validator.v2 import check_one_of -from pydantic import BaseModel, ConfigDict, Field, model_validator - - -class AfterReferMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - - -class AnOtherMessage(BaseModel): - class SubMessage(BaseModel): - text: str = Field(default="") - - field1: str = Field(default="") - field2: SubMessage = Field() - - -class EmptyMessage(BaseModel): - pass - - -class InvoiceItem2(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List["InvoiceItem2"] = Field(default_factory=list) - invoice: "Invoice3" = Field() - - -class Invoice3(BaseModel): - name: str = Field(default="") - amount: int = Field(default=0) - quantity: int = Field(default=0) - items: typing.List[InvoiceItem2] = Field(default_factory=list) +from pydantic import BaseModel, Field, model_validator class InvoiceItem(BaseModel): @@ -51,71 +15,6 @@ class InvoiceItem(BaseModel): items: typing.List["InvoiceItem"] = Field(default_factory=list) -class SexType(IntEnum): - man = 0 - women = 1 - - -class ExampleExampleProtoCommonSingleDemoEnum(IntEnum): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoEnum protobuf path:example/example_proto/common/single.proto""" - - zero = 0 - one = 1 - two = 3 - - -class ExampleExampleProtoCommonSingleDemoMessage(BaseModel): - """Note: The current class does not belong to the package - ExampleExampleProtoCommonSingleDemoMessage protobuf path:example/example_proto/common/single.proto""" - - earth: str = Field(default="") - mercury: str = Field(default="") - mars: str = Field(default="") - - -class UserMessage(BaseModel): - uid: str = Field(default="") - age: int = Field(default=0) - height: float = Field(default=0.0) - sex: SexType = Field(default=0) - demo: ExampleExampleProtoCommonSingleDemoEnum = Field(default=0) - is_adult: bool = Field(default=False) - user_name: str = Field(default="") - demo_message: ExampleExampleProtoCommonSingleDemoMessage = Field() - - -class MapMessage(BaseModel): - user_map: typing.Dict[str, UserMessage] = Field(default_factory=dict) - user_flag: typing.Dict[str, bool] = Field(default_factory=dict) - - -class RepeatedMessage(BaseModel): - str_list: typing.List[str] = Field(default_factory=list) - int_list: typing.List[int] = Field(default_factory=list) - user_list: typing.List[UserMessage] = Field(default_factory=list) - - -class NestedMessage(BaseModel): - class UserPayMessage(BaseModel): - bank_number: str = Field(default="") - exp: datetime = Field(default_factory=datetime.now) - uuid: str = Field(default="") - - class IncludeEnum(IntEnum): - zero = 0 - one = 1 - two = 2 - - user_list_map: typing.Dict[str, RepeatedMessage] = Field(default_factory=dict) - user_map: typing.Dict[str, MapMessage] = Field(default_factory=dict) - user_pay: UserPayMessage = Field() - include_enum: IncludeEnum = Field(default=0) - not_enable_user_pay: UserPayMessage = Field() - empty: typing.Any = Field() - after_refer: AfterReferMessage = Field() - - class OptionalMessage(BaseModel): _one_of_dict = {"user.OptionalMessage.a": {"fields": {"x", "y"}, "required": False}} @@ -129,16 +28,3 @@ class OptionalMessage(BaseModel): default_template_test: float = Field(default=0.0) one_of_validator = model_validator(mode="before")(check_one_of) - - -class OtherMessage(BaseModel): - model_config = ConfigDict(arbitrary_types_allowed=True) - - metadata: typing.Dict[str, typing.Any] = Field(default_factory=dict) - double_value: DoubleValue = Field(default_factory=DoubleValue) - field_mask: typing.Optional[FieldMask] = Field(default_factory=FieldMask) - - -class RootMessage(BaseModel): - field1: str = Field(default="") - field2: AnOtherMessage = Field() diff --git a/example/proto_pydanticv2/demo_gen_code_by_p2p.py b/example/proto_pydanticv2/demo_gen_code_by_p2p.py index 92b7fe0..7767166 100644 --- a/example/proto_pydanticv2/demo_gen_code_by_p2p.py +++ b/example/proto_pydanticv2/demo_gen_code_by_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/demo_gen_code_by_pgv.py b/example/proto_pydanticv2/demo_gen_code_by_pgv.py index 64e5c68..c151691 100644 --- a/example/proto_pydanticv2/demo_gen_code_by_pgv.py +++ b/example/proto_pydanticv2/demo_gen_code_by_pgv.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py b/example/proto_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py index 78dde85..ae640c2 100644 --- a/example/proto_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py +++ b/example/proto_pydanticv2/demo_gen_code_by_text_comment_protobuf_field.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/demo_gen_code_by_text_comment_pyi.py b/example/proto_pydanticv2/demo_gen_code_by_text_comment_pyi.py index 78dde85..ae640c2 100644 --- a/example/proto_pydanticv2/demo_gen_code_by_text_comment_pyi.py +++ b/example/proto_pydanticv2/demo_gen_code_by_text_comment_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/common/single_p2p.py b/example/proto_pydanticv2/example/example_proto/common/single_p2p.py index 32ba63e..9d65fd5 100644 --- a/example/proto_pydanticv2/example/example_proto/common/single_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/common/single_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 from enum import IntEnum diff --git a/example/proto_pydanticv2/example/example_proto/demo/alias_demo_p2p.py b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_p2p.py new file mode 100644 index 0000000..cf0d147 --- /dev/null +++ b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_p2p.py @@ -0,0 +1,36 @@ +# This is an automatically generated file, please do not change +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) +# Protobuf Version: 4.24.4 +# Pydantic Version: 2.5.3 +import typing +from datetime import datetime + +from google.protobuf.message import Message # type: ignore +from pydantic import Field, model_validator + +from example.populate_by_name_plugin_config import MyBaseSchema +from protobuf_to_pydantic.customer_validator import check_one_of + + +class GeoLocation(MyBaseSchema): + latitude: float = Field(default=0.0) + longitude: float = Field(default=0.0) + altitude_meters: typing.Optional[float] = Field(default=0.0) + + +class ReportData(MyBaseSchema): + """ + Annotations are used in runtime mode + """ + + _one_of_dict = { + "ReportData.data": {"fields": {"locationValue", "location_value", "timeValue", "time_value"}, "required": True} + } + one_of_validator = model_validator(mode="before")(check_one_of) + location_value: typing.Optional[GeoLocation] = Field(default=None) + time_value: datetime = Field(default_factory=datetime.now) + + +class Report(MyBaseSchema): + source_id: typing.Optional[str] = Field(default="") + data: ReportData = Field() diff --git a/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.py b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.py new file mode 100644 index 0000000..264b456 --- /dev/null +++ b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: example/example_proto/demo/alias_demo.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n+example/example_proto/demo/alias_demo.proto\x12\nalias_demo\x1a\x1fgoogle/protobuf/timestamp.proto\"y\n\nReportData\x12\x31\n\x0elocation_value\x18\x05 \x01(\x0b\x32\x17.alias_demo.GeoLocationH\x00\x12\x30\n\ntime_value\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.TimestampH\x00\x42\x06\n\x04\x64\x61ta\"d\n\x0bGeoLocation\x12\x10\n\x08latitude\x18\x01 \x01(\x02\x12\x11\n\tlongitude\x18\x02 \x01(\x02\x12\x1c\n\x0f\x61ltitude_meters\x18\x03 \x01(\x01H\x00\x88\x01\x01\x42\x12\n\x10_altitude_meters\"T\n\x06Report\x12\x16\n\tsource_id\x18\x02 \x01(\tH\x00\x88\x01\x01\x12$\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x16.alias_demo.ReportDataB\x0c\n\n_source_idb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'example.example_proto.demo.alias_demo_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _REPORTDATA._serialized_start=92 + _REPORTDATA._serialized_end=213 + _GEOLOCATION._serialized_start=215 + _GEOLOCATION._serialized_end=315 + _REPORT._serialized_start=317 + _REPORT._serialized_end=401 +# @@protoc_insertion_point(module_scope) diff --git a/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi new file mode 100644 index 0000000..5ad47f9 --- /dev/null +++ b/example/proto_pydanticv2/example/example_proto/demo/alias_demo_pb2.pyi @@ -0,0 +1,70 @@ +""" +@generated by mypy-protobuf. Do not edit manually! +isort:skip_file +""" +import builtins +import google.protobuf.descriptor +import google.protobuf.message +import google.protobuf.timestamp_pb2 +import typing +import typing_extensions + +DESCRIPTOR: google.protobuf.descriptor.FileDescriptor + +class ReportData(google.protobuf.message.Message): + """Annotations are used in runtime mode + p2p: {"oneof:data": {"required": true}} + p2p: {"oneof:data": {"oneof_extend": {"optional": ["location_value"]}}} + """ + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LOCATION_VALUE_FIELD_NUMBER: builtins.int + TIME_VALUE_FIELD_NUMBER: builtins.int + @property + def location_value(self) -> global___GeoLocation: ... + @property + def time_value(self) -> google.protobuf.timestamp_pb2.Timestamp: ... + def __init__(self, + *, + location_value: typing.Optional[global___GeoLocation] = ..., + time_value: typing.Optional[google.protobuf.timestamp_pb2.Timestamp] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data",b"data","location_value",b"location_value","time_value",b"time_value"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["data",b"data"]) -> typing.Optional[typing_extensions.Literal["location_value","time_value"]]: ... +global___ReportData = ReportData + +class GeoLocation(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + LATITUDE_FIELD_NUMBER: builtins.int + LONGITUDE_FIELD_NUMBER: builtins.int + ALTITUDE_METERS_FIELD_NUMBER: builtins.int + latitude: builtins.float + longitude: builtins.float + altitude_meters: builtins.float + def __init__(self, + *, + latitude: builtins.float = ..., + longitude: builtins.float = ..., + altitude_meters: typing.Optional[builtins.float] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_altitude_meters",b"_altitude_meters","altitude_meters",b"altitude_meters","latitude",b"latitude","longitude",b"longitude"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_altitude_meters",b"_altitude_meters"]) -> typing.Optional[typing_extensions.Literal["altitude_meters"]]: ... +global___GeoLocation = GeoLocation + +class Report(google.protobuf.message.Message): + DESCRIPTOR: google.protobuf.descriptor.Descriptor + SOURCE_ID_FIELD_NUMBER: builtins.int + DATA_FIELD_NUMBER: builtins.int + source_id: typing.Text + @property + def data(self) -> global___ReportData: ... + def __init__(self, + *, + source_id: typing.Optional[typing.Text] = ..., + data: typing.Optional[global___ReportData] = ..., + ) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_source_id",b"_source_id","data",b"data","source_id",b"source_id"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_source_id",b"_source_id"]) -> typing.Optional[typing_extensions.Literal["source_id"]]: ... +global___Report = Report diff --git a/example/proto_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py b/example/proto_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py index 79bb773..851b670 100644 --- a/example/proto_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/demo/all_feidl_set_optional_demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/demo/demo_p2p.py b/example/proto_pydanticv2/example/example_proto/demo/demo_p2p.py index 59fd087..9375bb3 100644 --- a/example/proto_pydanticv2/example/example_proto/demo/demo_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/demo/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/demo/single_config_p2p.py b/example/proto_pydanticv2/example/example_proto/demo/single_config_p2p.py index 01458c3..7d63638 100644 --- a/example/proto_pydanticv2/example/example_proto/demo/single_config_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/demo/single_config_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 from google.protobuf.message import Message # type: ignore diff --git a/example/proto_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py b/example/proto_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py index df61b21..c3fc2b4 100644 --- a/example/proto_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/p2p_validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py index 0732958..d47b97b 100644 --- a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py index 90abd92..9069134 100644 --- a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py +++ b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_protobuf.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py index 90abd92..9069134 100644 --- a/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py +++ b/example/proto_pydanticv2/example/example_proto/p2p_validate_by_comment/demo_pb2_by_pyi.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/example/proto_pydanticv2/example/example_proto/validate/demo_p2p.py b/example/proto_pydanticv2/example/example_proto/validate/demo_p2p.py index f96f401..cfd3521 100644 --- a/example/proto_pydanticv2/example/example_proto/validate/demo_p2p.py +++ b/example/proto_pydanticv2/example/example_proto/validate/demo_p2p.py @@ -1,5 +1,5 @@ # This is an automatically generated file, please do not change -# gen by protobuf_to_pydantic[v0.2.7](https://github.com/so1n/protobuf_to_pydantic) +# gen by protobuf_to_pydantic[v0.3.0](https://github.com/so1n/protobuf_to_pydantic) # Protobuf Version: 4.24.4 # Pydantic Version: 2.5.3 import typing diff --git a/protobuf_to_pydantic/field_info_rule/protobuf_option_to_field_info/types.py b/protobuf_to_pydantic/field_info_rule/protobuf_option_to_field_info/types.py index e64270f..8131af3 100644 --- a/protobuf_to_pydantic/field_info_rule/protobuf_option_to_field_info/types.py +++ b/protobuf_to_pydantic/field_info_rule/protobuf_option_to_field_info/types.py @@ -63,8 +63,11 @@ def __get_pydantic_json_schema__( return field_schema @classmethod - def __get_pydantic_core_schema__( - cls, source: Type[Any] + def __get_pydantic_core_schema__( # type: ignore[no-untyped-def] + cls, + source: Type[Any], + *args, + **kwargs, # fix https://github.com/pydantic/pydantic/issues/6506 ) -> _pydantic_adapter.CoreSchema: # type: ignore[name-defined,valid-type] def _validate( __input_value: Any, _: _pydantic_adapter.core_schema.ValidationInfo # type: ignore[name-defined] @@ -108,9 +111,11 @@ def __get_pydantic_json_schema__( return field_schema @classmethod - def __get_pydantic_core_schema__( + def __get_pydantic_core_schema__( # type: ignore[no-untyped-def] cls, source: Type[Any], + *args, + **kwargs, # fix https://github.com/pydantic/pydantic/issues/6506 ) -> _pydantic_adapter.CoreSchema: # type: ignore[name-defined,valid-type] def _validate( __input_value: Any, _: _pydantic_adapter.core_schema.ValidationInfo # type: ignore[name-defined] diff --git a/protobuf_to_pydantic/gen_code.py b/protobuf_to_pydantic/gen_code.py index a953cd5..b9e2943 100644 --- a/protobuf_to_pydantic/gen_code.py +++ b/protobuf_to_pydantic/gen_code.py @@ -669,6 +669,8 @@ def _validator_handle(self, validator_dict: Dict[str, classmethod], indent: int) k: getattr(validator_class.decorator_info, k) # type: ignore[attr-defined] for k in validator_class.decorator_info.__dataclass_fields__.keys() # type: ignore[attr-defined] if k not in ("decorator_repr",) + and getattr(validator_class.decorator_info, k) # type: ignore[attr-defined] + is not _pydantic_adapter.PydanticUndefined } if "fields" in decorator_info_dict: diff --git a/protobuf_to_pydantic/gen_model.py b/protobuf_to_pydantic/gen_model.py index 17585ee..5040b59 100644 --- a/protobuf_to_pydantic/gen_model.py +++ b/protobuf_to_pydantic/gen_model.py @@ -31,7 +31,7 @@ ) from protobuf_to_pydantic.grpc_types import AnyMessage, Descriptor, FieldDescriptor, FieldMask, Message from protobuf_to_pydantic.template import Template -from protobuf_to_pydantic.util import create_pydantic_model +from protobuf_to_pydantic.util import create_pydantic_model, pydantic_allow_validation_field_handler if TYPE_CHECKING: from protobuf_to_pydantic.field_info_rule.types import FieldInfoTypedDict, MessageOptionTypedDict, UseOneOfTypedDict @@ -168,7 +168,7 @@ def __init__( self._creat_cache: CREATE_MODEL_CACHE_T = create_model_cache or _create_model_cache self._pydantic_base: Type["BaseModel"] = pydantic_base or BaseModel self._pydantic_module: str = pydantic_module or __name__ - self._comment_template: Template = (template or Template)(local_dict or {}, self._comment_prefix) + self._comment_template: Template = (template or Template)(local_dict or {}, comment_prefix) self._message_type_dict_by_type_name: Dict[str, Any] = ( message_type_dict_by_type_name or constant.message_name_type_dict ) @@ -577,10 +577,14 @@ def _parse_msg_to_pydantic_model( if field_info.default is _pydantic_adapter.PydanticUndefined and field_info.default_factory is None: field_info.default = None annotation_dict[field_dataclass.field_name] = (field_dataclass.field_type, field_info) - if field_info.alias: + if one_of_dict: + model_config_dict = _pydantic_adapter.get_model_config_dict( + self._get_pydantic_base(pydantic_model_config_dict) + ) for one_of_name, sub_one_of_dict in one_of_dict.items(): - sub_one_of_dict["fields"].remove(field_dataclass.field_name) - sub_one_of_dict["fields"].add(field_info.alias) + pydantic_allow_validation_field_handler( + field_dataclass.field_name, field_info.alias, sub_one_of_dict["fields"], model_config_dict + ) if field_dataclass.field_type in ALLOW_ARBITRARY_TYPE and not _pydantic_adapter.get_model_config_value( self._pydantic_base, "arbitrary_types_allowed" diff --git a/protobuf_to_pydantic/plugin/code_gen.py b/protobuf_to_pydantic/plugin/code_gen.py index 66f7edf..843bcd8 100644 --- a/protobuf_to_pydantic/plugin/code_gen.py +++ b/protobuf_to_pydantic/plugin/code_gen.py @@ -3,6 +3,7 @@ import logging import pathlib import sys +import traceback import types from typing import Callable, Dict, Generic, Optional, Type @@ -94,7 +95,7 @@ def _get_config_by_path(self, key: str) -> None: self.config = get_config_by_module(importlib.import_module(module_path), self.config_class) break except ModuleNotFoundError as e: - error_path_dict[module_path] = e + error_path_dict[module_path] = {"error": e, "traceback": traceback.format_exc()} if self.config == default_config: raise SystemError(f"Load config error. try use path and error:{error_path_dict}") diff --git a/protobuf_to_pydantic/plugin/field_desc_proto_to_code.py b/protobuf_to_pydantic/plugin/field_desc_proto_to_code.py index 0cae57b..c8e4d20 100644 --- a/protobuf_to_pydantic/plugin/field_desc_proto_to_code.py +++ b/protobuf_to_pydantic/plugin/field_desc_proto_to_code.py @@ -36,7 +36,7 @@ FileDescriptorProto, ) from protobuf_to_pydantic.plugin.my_types import ProtobufTypeModel -from protobuf_to_pydantic.util import camel_to_snake, get_dict_from_comment +from protobuf_to_pydantic.util import camel_to_snake, get_dict_from_comment, pydantic_allow_validation_field_handler if TYPE_CHECKING: from protobuf_to_pydantic.plugin.config import ConfigModel @@ -477,11 +477,12 @@ def _message_field_handle( if not field_info_dict.get("json_schema_extra", None): field_info_dict.pop("json_schema_extra") - alias = field_info_dict.get("alias", None) - if alias and one_of_dict: + if one_of_dict: + alias = field_info_dict.get("alias", None) + model_config_dict = _pydantic_adapter.get_model_config_dict(self.config.base_model_class) + for one_of_name, sub_one_of_dict in one_of_dict.items(): - sub_one_of_dict["fields"].remove(field.name) - sub_one_of_dict["fields"].add(alias) + pydantic_allow_validation_field_handler(field.name, alias, sub_one_of_dict["fields"], model_config_dict) field_info_str: str = ( ", ".join( diff --git a/protobuf_to_pydantic/util.py b/protobuf_to_pydantic/util.py index bed3835..50159fd 100644 --- a/protobuf_to_pydantic/util.py +++ b/protobuf_to_pydantic/util.py @@ -7,10 +7,12 @@ from contextlib import contextmanager from dataclasses import MISSING from datetime import timedelta -from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Tuple, Type, Union +from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Set, Tuple, Type, Union from pydantic import BaseConfig, BaseModel, create_model +from protobuf_to_pydantic import _pydantic_adapter + if TYPE_CHECKING: from pydantic.main import Model from pydantic.typing import AnyClassMethod @@ -229,3 +231,35 @@ def use_worker_dir_in_ctx(worker_dir: Optional[str] = None) -> Generator: yield else: yield + + +def pydantic_allow_validation_field_handler( + field_name: str, field_alias_name: Optional[str], allow_field_set: Set[str], model_config_dict: dict +) -> None: + """ + fix issue: #74 https://github.com/so1n/protobuf_to_pydantic/issues/74 + + :param field_name: pydantic field name + :param field_alias_name: pydantic field alias name + :param allow_field_set: pydantic allow validation set + :param model_config_dict: pydantic model config dict + """ + if field_alias_name: + allow_field_set.add(field_alias_name) + if model_config_dict.get("populate_by_name") is not True: + allow_field_set.remove(field_name) + if _pydantic_adapter.VERSION < "2.6.0": + alias_generator: Optional[Callable[[str], str]] = model_config_dict.get("alias_generator") + alias_generator_func: Optional[Callable] = alias_generator + if alias_generator: + allow_field_set.add(alias_generator(field_name)) + else: + from pydantic import AliasGenerator + + alias_generator_gte_26: Any = model_config_dict.get("alias_generator") + if isinstance(alias_generator_gte_26, AliasGenerator): # type: ignore + alias_generator_func = alias_generator_gte_26.validation_alias + else: + alias_generator_func = alias_generator_gte_26 + if alias_generator_func: + allow_field_set.add(alias_generator_func(field_name)) diff --git a/tests/base/base_demo_validate.py b/tests/base/base_demo_validate.py new file mode 100644 index 0000000..e84ef97 --- /dev/null +++ b/tests/base/base_demo_validate.py @@ -0,0 +1,109 @@ +from typing import Callable, Type + +import pytest +from pydantic import ValidationError + +from protobuf_to_pydantic import _pydantic_adapter + + +class BaseTestAliasDemoValidator: + replace_message_fn: Callable = staticmethod(lambda x:x) # type: ignore[assignment] + + def _test_alias_demo(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + if not _pydantic_adapter.is_v1: + model_class( + **{ + "sourceId": "123", + "data": { + "locationValue": { + "latitude": 10.01, + "longitude": -10.01, + "altitudeMeters":10.01 + } + } + }) + model_class( + **{ + "source_id": "123", + "data": { + "location_value": { + "latitude": 10.01, + "longitude": -10.01, + "altitudeMeters": 10.01 + } + } + }) + model_class( + **{ + "source_id": "123", + "data": {"time_value": "2000-01-01 10:00:00"} + }) + +class BaseTestAllFieldSetOptionalDemoValidator: + replace_message_fn: Callable = staticmethod(lambda x:x) # type: ignore[assignment] + + def _test_user_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_other_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_map_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_repeated_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_after_refer_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_nested_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_invoice_item(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_empty_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_optional_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class(x="1") + model_class(y=1) + + def _test_invoice_item2(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + def _test_root_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class() + + +class BaseTestDemoValidator: + pass + +class BaseTestSingleConfigValidator: + replace_message_fn: Callable = staticmethod(lambda x:x) # type: ignore[assignment] + + def _test_user_message(self, model_class: Type) -> None: + model_class = self.replace_message_fn(model_class) + model_class(**{"uid": "10086", "age": 1, "height": 1, "user_name": "aaa"}) + + with pytest.raises(ValidationError): + model_class(**{"uid": "10086", "age": -1, "height": 1, "user_name": "aaa"}) + + with pytest.raises(ValidationError): + model_class(**{"uid": "10086", "age": 1, "height": 3, "user_name": "aaa"}) + + with pytest.raises(ValidationError): + model_class(**{"uid": "10086", "age": 1, "height": 1, "user_name": ""}) diff --git a/tests/test_gen_code_output_by_cli/__init__.py b/tests/test_gen_code/__init__.py similarity index 100% rename from tests/test_gen_code_output_by_cli/__init__.py rename to tests/test_gen_code/__init__.py diff --git a/tests/test_gen_code_output_by_cli/test_demo_proto/__init__.py b/tests/test_gen_code/test_demo_proto/__init__.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_demo_proto/__init__.py rename to tests/test_gen_code/test_demo_proto/__init__.py diff --git a/tests/test_gen_code_output_by_cli/test_demo_proto/test_plugin.py b/tests/test_gen_code/test_demo_proto/test_plugin.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_demo_proto/test_plugin.py rename to tests/test_gen_code/test_demo_proto/test_plugin.py diff --git a/tests/test_gen_code_output_by_cli/test_demo_proto/test_simple.py b/tests/test_gen_code/test_demo_proto/test_simple.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_demo_proto/test_simple.py rename to tests/test_gen_code/test_demo_proto/test_simple.py diff --git a/tests/test_gen_code_output_by_cli/test_demo_proto/test_text_comment.py b/tests/test_gen_code/test_demo_proto/test_text_comment.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_demo_proto/test_text_comment.py rename to tests/test_gen_code/test_demo_proto/test_text_comment.py diff --git a/tests/test_gen_code_output_by_cli/test_p2p_validate_proto/__init__.py b/tests/test_gen_code/test_p2p_validate_proto/__init__.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_p2p_validate_proto/__init__.py rename to tests/test_gen_code/test_p2p_validate_proto/__init__.py diff --git a/tests/test_gen_code_output_by_cli/test_p2p_validate_proto/test_p2p_validate.py b/tests/test_gen_code/test_p2p_validate_proto/test_p2p_validate.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_p2p_validate_proto/test_p2p_validate.py rename to tests/test_gen_code/test_p2p_validate_proto/test_p2p_validate.py diff --git a/tests/test_gen_code_output_by_cli/test_validate_proto/__init__.py b/tests/test_gen_code/test_validate_proto/__init__.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_validate_proto/__init__.py rename to tests/test_gen_code/test_validate_proto/__init__.py diff --git a/tests/test_gen_code_output_by_cli/test_validate_proto/test_validate.py b/tests/test_gen_code/test_validate_proto/test_validate.py similarity index 100% rename from tests/test_gen_code_output_by_cli/test_validate_proto/test_validate.py rename to tests/test_gen_code/test_validate_proto/test_validate.py diff --git a/tests/test_gen_code_validate_in_runtime/__init__.py b/tests/test_validate_in_runtime/__init__.py similarity index 100% rename from tests/test_gen_code_validate_in_runtime/__init__.py rename to tests/test_validate_in_runtime/__init__.py diff --git a/tests/test_gen_model_validate_in_runtime/__init__.py b/tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/__init__.py similarity index 100% rename from tests/test_gen_model_validate_in_runtime/__init__.py rename to tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/__init__.py diff --git a/tests/test_gen_code_validate_in_runtime/test_p2p_validate.py b/tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate.py similarity index 100% rename from tests/test_gen_code_validate_in_runtime/test_p2p_validate.py rename to tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate.py diff --git a/tests/test_gen_code_validate_in_runtime/test_p2p_validate_by_protobuf_field_with_comment.py b/tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate_by_protobuf_field_with_comment.py similarity index 100% rename from tests/test_gen_code_validate_in_runtime/test_p2p_validate_by_protobuf_field_with_comment.py rename to tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate_by_protobuf_field_with_comment.py diff --git a/tests/test_gen_code_validate_in_runtime/test_p2p_validate_by_pyi_with_comment.py b/tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate_by_pyi_with_comment.py similarity index 100% rename from tests/test_gen_code_validate_in_runtime/test_p2p_validate_by_pyi_with_comment.py rename to tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_p2p_validate_by_pyi_with_comment.py diff --git a/tests/test_gen_code_validate_in_runtime/test_pgv_validate.py b/tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_pgv_validate.py similarity index 100% rename from tests/test_gen_code_validate_in_runtime/test_pgv_validate.py rename to tests/test_validate_in_runtime/test_gen_code_validate_in_runtime/test_pgv_validate.py diff --git a/tests/test_plugin_gen_code_validate_in_runtime/__init__.py b/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/__init__.py similarity index 100% rename from tests/test_plugin_gen_code_validate_in_runtime/__init__.py rename to tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/__init__.py diff --git a/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_demo.py b/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_demo.py new file mode 100644 index 0000000..ee85dbc --- /dev/null +++ b/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_demo.py @@ -0,0 +1,116 @@ +from functools import partial +from typing import Callable + +import pytest +from google.protobuf import __version__ +from pydantic import ValidationError + +from example.populate_by_name_plugin_config import MyBaseSchema +from protobuf_to_pydantic import msg_to_pydantic_model +from protobuf_to_pydantic._pydantic_adapter import is_v1 +from tests.base.base_demo_validate import ( + BaseTestAliasDemoValidator, + BaseTestAllFieldSetOptionalDemoValidator, + BaseTestDemoValidator, + BaseTestSingleConfigValidator, +) +from tests.base.base_p2p_validate import local_dict + +if __version__ > "4.0.0": + if is_v1: + from example.proto_pydanticv1.example.example_proto.demo import ( + alias_demo_pb2, + all_feidl_set_optional_demo_pb2, + demo_pb2, + single_config_pb2, + ) + else: + from example.proto_pydanticv2.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_pb2, + all_feidl_set_optional_demo_pb2, + demo_pb2, + single_config_pb2, + ) +else: + if is_v1: + from example.proto_3_20_pydanticv1.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_pb2, + all_feidl_set_optional_demo_pb2, + demo_pb2, + single_config_pb2, + ) + else: + from example.proto_3_20_pydanticv2.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_pb2, + all_feidl_set_optional_demo_pb2, + demo_pb2, + single_config_pb2, + ) + +class TestAliasDemoValidator(BaseTestAliasDemoValidator): + replace_message_fn: Callable = staticmethod( # type: ignore + partial( + msg_to_pydantic_model, + local_dict=local_dict, + parse_msg_desc_method=alias_demo_pb2, + pydantic_base=MyBaseSchema + )) + + def test_alias_demo(self) -> None: + super()._test_alias_demo(alias_demo_pb2.Report) + +class TestAllFieldSetOptionalDemoValidator(BaseTestAllFieldSetOptionalDemoValidator): + replace_message_fn: Callable = staticmethod( # type: ignore + partial( + msg_to_pydantic_model, + local_dict=local_dict, + all_field_set_optional=True + )) + + def test_user_message(self) -> None: + super()._test_user_message(all_feidl_set_optional_demo_pb2.UserMessage) + + def test_other_message(self) -> None: + super()._test_other_message(all_feidl_set_optional_demo_pb2.OtherMessage) + + def test_map_message(self) -> None: + super()._test_map_message(all_feidl_set_optional_demo_pb2.MapMessage) + + def test_repeated_message(self) -> None: + super()._test_repeated_message(all_feidl_set_optional_demo_pb2.RepeatedMessage) + + def test_after_refer_message(self) -> None: + super()._test_after_refer_message(all_feidl_set_optional_demo_pb2.AfterReferMessage) + + def test_nested_message(self) -> None: + super()._test_nested_message(all_feidl_set_optional_demo_pb2.NestedMessage) + + def test_invoice_item(self) -> None: + super()._test_invoice_item(all_feidl_set_optional_demo_pb2.InvoiceItem) + + def test_empty_message(self) -> None: + super()._test_empty_message(all_feidl_set_optional_demo_pb2.EmptyMessage) + + def test_optional_message(self) -> None: + super()._test_optional_message(all_feidl_set_optional_demo_pb2.OptionalMessage) + + def test_invoice_item2(self) -> None: + super(all_feidl_set_optional_demo_pb2.InvoiceItem2) + + def test_root_message(self) -> None: + super(all_feidl_set_optional_demo_pb2.RootMessage) + + +class TestDemoValidator: + pass + +class TestSingleConfigValidator(BaseTestSingleConfigValidator): + replace_message_fn: Callable = staticmethod( # type: ignore + partial( + msg_to_pydantic_model, + comment_prefix="aha", + parse_msg_desc_method=single_config_pb2 + )) + + def test_user_message(self) -> None: + super()._test_user_message(single_config_pb2.UserMessage) diff --git a/tests/test_gen_model_validate_in_runtime/test_p2p_validate.py b/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_p2p_validate.py similarity index 100% rename from tests/test_gen_model_validate_in_runtime/test_p2p_validate.py rename to tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_p2p_validate.py diff --git a/tests/test_gen_model_validate_in_runtime/test_pgv_validate.py b/tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_pgv_validate.py similarity index 100% rename from tests/test_gen_model_validate_in_runtime/test_pgv_validate.py rename to tests/test_validate_in_runtime/test_gen_model_validate_in_runtime/test_pgv_validate.py diff --git a/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/__init__.py b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_demo.py b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_demo.py new file mode 100644 index 0000000..05a2fe1 --- /dev/null +++ b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_demo.py @@ -0,0 +1,89 @@ +import pytest +from google.protobuf import __version__ +from pydantic import ValidationError + +from protobuf_to_pydantic._pydantic_adapter import is_v1 +from tests.base.base_demo_validate import ( + BaseTestAliasDemoValidator, + BaseTestAllFieldSetOptionalDemoValidator, + BaseTestDemoValidator, + BaseTestSingleConfigValidator, +) + +if __version__ > "4.0.0": + if is_v1: + from example.proto_pydanticv1.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_p2p, + all_feidl_set_optional_demo_p2p, + demo_p2p, + single_config_p2p, + ) + else: + from example.proto_pydanticv2.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_p2p, + all_feidl_set_optional_demo_p2p, + demo_p2p, + single_config_p2p, + ) +else: + if is_v1: + from example.proto_3_20_pydanticv1.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_p2p, + all_feidl_set_optional_demo_p2p, + demo_p2p, + single_config_p2p, + ) + else: + from example.proto_3_20_pydanticv2.example.example_proto.demo import ( # type: ignore[no-redef] + alias_demo_p2p, + all_feidl_set_optional_demo_p2p, + demo_p2p, + single_config_p2p, + ) + +class TestAliasDemoValidator(BaseTestAliasDemoValidator): + def test_alias_demo(self) -> None: + super()._test_alias_demo(alias_demo_p2p.Report) + +class TestAllFieldSetOptionalDemoValidator(BaseTestAllFieldSetOptionalDemoValidator): + def test_user_message(self) -> None: + super()._test_user_message(all_feidl_set_optional_demo_p2p.UserMessage) + + def test_other_message(self) -> None: + super()._test_other_message(all_feidl_set_optional_demo_p2p.OtherMessage) + + def test_map_message(self) -> None: + super()._test_map_message(all_feidl_set_optional_demo_p2p.MapMessage) + + def test_repeated_message(self) -> None: + super()._test_repeated_message(all_feidl_set_optional_demo_p2p.RepeatedMessage) + + def test_after_refer_message(self) -> None: + super()._test_after_refer_message(all_feidl_set_optional_demo_p2p.AfterReferMessage) + + def test_nested_message(self) -> None: + super()._test_nested_message(all_feidl_set_optional_demo_p2p.NestedMessage) + + def test_invoice_item(self) -> None: + super()._test_invoice_item(all_feidl_set_optional_demo_p2p.InvoiceItem) + + def test_empty_message(self) -> None: + super()._test_empty_message(all_feidl_set_optional_demo_p2p.EmptyMessage) + + def test_optional_message(self) -> None: + super()._test_optional_message(all_feidl_set_optional_demo_p2p.OptionalMessage) + + def test_invoice_item2(self) -> None: + super(all_feidl_set_optional_demo_p2p.InvoiceItem2) + + def test_root_message(self) -> None: + super(all_feidl_set_optional_demo_p2p.RootMessage) + + +class TestDemoValidator: + pass + +class TestSingleConfigValidator(BaseTestSingleConfigValidator): + + def test_user_message(self) -> None: + super()._test_user_message(single_config_p2p.UserMessage) diff --git a/tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py similarity index 93% rename from tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py rename to tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py index 665294b..e33af1e 100644 --- a/tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py +++ b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate.py @@ -1,6 +1,7 @@ from typing import Any, Callable, Type from google.protobuf import __version__ +from pydantic import VERSION from protobuf_to_pydantic._pydantic_adapter import is_v1 @@ -15,7 +16,10 @@ else: from example.proto_3_20_pydanticv2.example.example_proto.p2p_validate import demo_p2p -from tests.test_gen_model_validate_in_runtime.test_p2p_validate import BaseTestP2pModelValidator, local_dict +from tests.test_validate_in_runtime.test_gen_model_validate_in_runtime.test_p2p_validate import ( + BaseTestP2pModelValidator, + local_dict, +) def stub_func(model_class: Type, **kwargs: Any) -> Type: diff --git a/tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py similarity index 94% rename from tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py rename to tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py index bb52a44..dbdcb68 100644 --- a/tests/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py +++ b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_p2p_validate_by_comment.py @@ -15,7 +15,10 @@ else: from example.proto_3_20_pydanticv2.example.example_proto.p2p_validate_by_comment import demo_p2p # type: ignore -from tests.test_gen_model_validate_in_runtime.test_p2p_validate import BaseTestP2pModelValidator, local_dict +from tests.test_validate_in_runtime.test_gen_model_validate_in_runtime.test_p2p_validate import ( + BaseTestP2pModelValidator, + local_dict, +) def stub_func(model_class: Type, **kwargs: Any) -> Type: diff --git a/tests/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py similarity index 94% rename from tests/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py rename to tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py index 33bcef1..867e730 100644 --- a/tests/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py +++ b/tests/test_validate_in_runtime/test_plugin_gen_code_validate_in_runtime/test_pgv_validate.py @@ -16,7 +16,9 @@ else: from example.proto_3_20_pydanticv2.example.example_proto.validate import demo_p2p -from tests.test_gen_model_validate_in_runtime.test_pgv_validate import BaseTestPgvModelValidator +from tests.test_validate_in_runtime.test_gen_model_validate_in_runtime.test_pgv_validate import ( + BaseTestPgvModelValidator, +) def stub_func(model_class: Type[BaseModel], **kwargs: Any) -> Type[BaseModel]: