Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support repeated extensions #248

Merged
merged 1 commit into from
Jul 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ test_message_option: google.protobuf.descriptor.FieldDescriptor = ...
# Now generates
test_message_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, typing.Text] = ...
```
- Now requires [types-protobuf](https://pypi.org/project/types-protobuf/) 3.17.1
Fix repeated extensions as well - to generate RepeatedScalarFieldContainer and RepeatedCompositeFieldContainer
- Now requires [types-protobuf](https://pypi.org/project/types-protobuf/) 3.17.3
- Fix [#238](https://github.com/dropbox/mypy-protobuf/issues/238) - handling enum variants that name conflict with EnumTypeWrapper methods


Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ See [Changelog](CHANGELOG.md) for recent changes.
## Requirements to run mypy on stubs generated by mypy-protobuf
[mypy >= v0.910](https://pypi.org/project/mypy)
[python-protobuf >= 3.17.3](https://pypi.org/project/protobuf/) - matching protoc release
[types-protobuf==3.17.1](https://pypi.org/project/types-protobuf/) - for stubs from the google.protobuf library
[types-protobuf==3.17.3](https://pypi.org/project/types-protobuf/) - for stubs from the google.protobuf library

### To run mypy on code generated with grpc plugin - you'll additionally need
[grpcio>=1.38.1](https://pypi.org/project/grpcio/)
Expand Down
2 changes: 1 addition & 1 deletion proto/testproto/test3.proto
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ enum OuterEnum {
}

message OuterMessage3 {
bool a_bool = 1;
string a_string = 1;
}

message SimpleProto3 {
Expand Down
23 changes: 20 additions & 3 deletions proto/testproto/test_extensions3.proto
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
syntax = "proto3";

import "google/protobuf/descriptor.proto";
import "testproto/test3.proto";

package test;
package test3;

extend google.protobuf.FieldOptions {
string test_field_extension = 50000;
}

extend google.protobuf.MessageOptions {
string test_message_option = 51234;
string scalar_option = 51234;
repeated string repeated_scalar_option = 51235;
OuterEnum enum_option = 51236;
repeated OuterEnum repeated_enum_option = 51237;
OuterMessage3 msg_option = 51238;
repeated OuterMessage3 repeated_msg_option = 51239;
}

message MessageOptionsTestMsg {
option (test_message_option) = "Hello world!";
option (scalar_option) = "Hello world!";
option (repeated_scalar_option) = "A";
option (repeated_scalar_option) = "B";
option (repeated_scalar_option) = "C";

option (enum_option) = FOO3;
option (repeated_enum_option) = FOO3;
option (repeated_enum_option) = BAR3;

option (msg_option).a_string = "Hello OuterMessage3";
option (repeated_msg_option) = {a_string: "Hello OuterMessage3 A"};
option (repeated_msg_option) = {a_string: "Hello OuterMessage3 B"};
}
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ grpcio-tools==1.38.1 ; python_version>="3.0"
grpc-stubs>=1.24.6 ; python_version>="3.0"

types-six==0.1.7
types-protobuf==3.17.1
types-protobuf==3.17.3
8 changes: 4 additions & 4 deletions test/generated/testproto/test3_pb2.pyi.expected
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ class _OuterEnum(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[Out

class OuterMessage3(google.protobuf.message.Message):
DESCRIPTOR: google.protobuf.descriptor.Descriptor = ...
A_BOOL_FIELD_NUMBER: builtins.int
a_bool: builtins.bool = ...
A_STRING_FIELD_NUMBER: builtins.int
a_string: typing.Text = ...

def __init__(self,
*,
a_bool : builtins.bool = ...,
a_string : typing.Text = ...,
) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal[u"a_bool",b"a_bool"]) -> None: ...
def ClearField(self, field_name: typing_extensions.Literal[u"a_string",b"a_string"]) -> None: ...
global___OuterMessage3 = OuterMessage3

class SimpleProto3(google.protobuf.message.Message):
Expand Down
14 changes: 13 additions & 1 deletion test/generated/testproto/test_extensions3_pb2.pyi.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ isort:skip_file
"""
import google.protobuf.descriptor
import google.protobuf.descriptor_pb2
import google.protobuf.internal.containers
import google.protobuf.internal.extension_dict
import google.protobuf.message
import testproto.test3_pb2
import typing

DESCRIPTOR: google.protobuf.descriptor.FileDescriptor = ...
Expand All @@ -19,4 +21,14 @@ global___MessageOptionsTestMsg = MessageOptionsTestMsg

test_field_extension: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.FieldOptions, typing.Text] = ...

test_message_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, typing.Text] = ...
scalar_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, typing.Text] = ...

repeated_scalar_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]] = ...

enum_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, testproto.test3_pb2.OuterEnum.V] = ...

repeated_enum_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, google.protobuf.internal.containers.RepeatedScalarFieldContainer[testproto.test3_pb2.OuterEnum.V]] = ...

msg_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, testproto.test3_pb2.OuterMessage3] = ...

repeated_msg_option: google.protobuf.internal.extension_dict._ExtensionFieldDescriptor[google.protobuf.descriptor_pb2.MessageOptions, google.protobuf.internal.containers.RepeatedCompositeFieldContainer[testproto.test3_pb2.OuterMessage3]] = ...
35 changes: 30 additions & 5 deletions test/test_generated_mypy.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,20 @@
Simple2,
)
from testproto.test3_pb2 import (
BAR3,
FOO3,
OuterMessage3,
SimpleProto3,
)
from testproto.test_extensions3_pb2 import MessageOptionsTestMsg, test_message_option
from testproto.test_extensions3_pb2 import (
MessageOptionsTestMsg,
scalar_option,
repeated_scalar_option,
enum_option,
repeated_enum_option,
msg_option,
repeated_msg_option,
)
from testproto.Capitalized.Capitalized_pb2 import lower, lower2, Upper

from typing import (
Expand Down Expand Up @@ -451,9 +460,25 @@ def test_extensions_proto2():
def test_extensions_proto3():
# type: () -> None
assert (
MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[test_message_option]
MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[scalar_option]
== "Hello world!"
)
assert MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[
repeated_scalar_option
] == ["A", "B", "C"]
assert MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[enum_option] == FOO3
assert MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[
repeated_enum_option
] == [FOO3, BAR3]
assert MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[
msg_option
] == OuterMessage3(a_string="Hello OuterMessage3")
assert list(
MessageOptionsTestMsg.DESCRIPTOR.GetOptions().Extensions[repeated_msg_option]
) == [
OuterMessage3(a_string="Hello OuterMessage3 A"),
OuterMessage3(a_string="Hello OuterMessage3 B"),
]


def test_constructor_proto2():
Expand Down Expand Up @@ -499,15 +524,15 @@ def test_mapping_type():
s.map_scalar[5] = "abcd"
assert s.map_scalar[5] == "abcd"

s.map_message[5].a_bool = True
assert s.map_message[5] == OuterMessage3(a_bool=True)
s.map_message[5].a_string = "hi"
assert s.map_message[5] == OuterMessage3(a_string="hi")

assert s.map_message.get_or_create(6) == OuterMessage3()
assert s.map_message[6] == OuterMessage3()
assert s.map_message.get_or_create(6) == OuterMessage3()

s2 = SimpleProto3(
map_scalar={5: "abcd"}, map_message={5: OuterMessage3(a_bool=True)}
map_scalar={5: "abcd"}, map_message={5: OuterMessage3(a_string="hi")}
)


Expand Down
2 changes: 1 addition & 1 deletion test_negative/negative.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@

# In proto2 - you can pass in None for primitive, but not in proto3
Simple2(a_string=None)
OuterMessage3(a_bool=None) # E:2.7 E:3.8
OuterMessage3(a_string=None) # E:2.7 E:3.8

# Repeated scalar fields are not assignable only extendable
s9 = Simple1()
Expand Down
2 changes: 1 addition & 1 deletion test_negative/output.expected.2.7
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ test_negative/negative.py:159: error: Argument "user_id" to "Simple1" has incomp
test_negative/negative.py:159: error: Argument "email" to "Simple1" has incompatible type "str"; expected "Optional[Email]"
test_negative/negative.py:159: error: Dict entry 0 has incompatible type "int": "str"; expected "UserId": "Email"
test_negative/negative.py:162: error: Module "testproto.reexport_pb2" has no attribute "Inner"
test_negative/negative.py:166: error: Argument "a_bool" to "OuterMessage3" has incompatible type "None"; expected "bool"
test_negative/negative.py:166: error: Argument "a_string" to "OuterMessage3" has incompatible type "None"; expected "unicode"
test_negative/negative.py:171: error: Property "a_repeated_string" defined in "Simple1" is read-only
test_negative/negative.py:172: error: Property "rep_inner_enum" defined in "Simple1" is read-only
Found 62 errors in 1 file (checked 17 source files)
2 changes: 1 addition & 1 deletion test_negative/output.expected.3.8
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ test_negative/negative.py:159: error: Argument "user_id" to "Simple1" has incomp
test_negative/negative.py:159: error: Argument "email" to "Simple1" has incompatible type "str"; expected "Optional[Email]"
test_negative/negative.py:159: error: Dict entry 0 has incompatible type "int": "str"; expected "UserId": "Email"
test_negative/negative.py:162: error: Module "testproto.reexport_pb2" has no attribute "Inner"
test_negative/negative.py:166: error: Argument "a_bool" to "OuterMessage3" has incompatible type "None"; expected "bool"
test_negative/negative.py:166: error: Argument "a_string" to "OuterMessage3" has incompatible type "None"; expected "str"
test_negative/negative.py:171: error: Property "a_repeated_string" defined in "Simple1" is read-only
test_negative/negative.py:172: error: Property "rep_inner_enum" defined in "Simple1" is read-only
Found 78 errors in 2 files (checked 32 source files)