Comments (5)
@forestbelton - mind taking a look at #112 to see if it handles the case you've brought up here (There are tests which should help illustrate).
from mypy-protobuf.
Interesting. Thanks for the report.
Do you know what line of your source file you see this error at? What is going on in your source leading to this? Is it at the time of import?
The .py
code you pasted seems to indicate that Foo
is a Message
here. It would also be helpful to have the equivalent .pyi
code pasted to debug.
These errors:
generated/python/foo_pb2.pyi:123: error: Function "Foo" is not valid as a type
generated/python/foo_pb2.pyi:123: note: Perhaps you need "Callable[...]" or a callback protocol?
seem to indicate that something in your code is using Foo as a function rather than as a message?
If you have a repro of the situation that you are willing to share, that'll help (ideally minimal).
Hopefully this is enough information to help your debugging!
from mypy-protobuf.
I believe I've tracked down the issue. It appears there are two different errors that arise as a result of the same underlying problem โ when an instance member/method has the same name as an existing type.
Here is one way to trigger an error by using an enum
:
enum AThing {
Unknown = 0;
A = 1;
B = 2;
}
message Foo {
AThing AThing = 1;
}
This results in the following generated .pyi
file:
# definition of AThing
# ...
class Foo(google___protobuf___message___Message):
DESCRIPTOR: google___protobuf___descriptor___Descriptor = ...
AThing = ... # type: AThing
def __init__(self,
*,
AThing : typing___Optional[AThing] = None,
) -> None: ...
if sys.version_info >= (3,):
@classmethod
def FromString(cls, s: builtin___bytes) -> Foo: ...
else:
@classmethod
def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Foo: ...
def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
if sys.version_info >= (3,):
def ClearField(self, field_name: typing_extensions___Literal[u"AThing"]) -> None: ...
else:
def ClearField(self, field_name: typing_extensions___Literal[u"AThing",b"AThing"]) -> None: ...
And attempts to use Foo
result in the following error:
from foo_pb2 import AThing, Foo
x: Foo = Foo(AThing=AThing.A)
test/foo_pb2.pyi:60: error: Variable "foo_pb2.Foo.AThing" is not valid as a type
Found 1 error in 1 file (checked 1 source file)
Per python/mypy#1775, this can be fixed by adding an alias for AThing
and referring to it in Foo
like so:
# definition of AThing
# ...
_AThing = AThing
class Foo(google___protobuf___message___Message):
DESCRIPTOR: google___protobuf___descriptor___Descriptor = ...
AThing = ... # type: _AThing
def __init__(self,
*,
AThing : typing___Optional[_AThing] = None,
) -> None: ...
if sys.version_info >= (3,):
@classmethod
def FromString(cls, s: builtin___bytes) -> Foo: ...
else:
@classmethod
def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Foo: ...
def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
if sys.version_info >= (3,):
def ClearField(self, field_name: typing_extensions___Literal[u"AThing"]) -> None: ...
else:
def ClearField(self, field_name: typing_extensions___Literal[u"AThing",b"AThing"]) -> None: ...
The second way is similar, using a nested Message
instead of an enum:
message Bar {
int64 X = 1;
}
message Foo {
Bar Bar = 1;
}
which results in the following .pyi
:
# definition of Bar
# ...
class Foo(google___protobuf___message___Message):
DESCRIPTOR: google___protobuf___descriptor___Descriptor = ...
@property
def Bar(self) -> Bar: ...
def __init__(self,
*,
Bar : typing___Optional[Bar] = None,
) -> None: ...
if sys.version_info >= (3,):
@classmethod
def FromString(cls, s: builtin___bytes) -> Foo: ...
else:
@classmethod
def FromString(cls, s: typing___Union[builtin___bytes, builtin___buffer, builtin___unicode]) -> Foo: ...
def MergeFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
def CopyFrom(self, other_msg: google___protobuf___message___Message) -> None: ...
if sys.version_info >= (3,):
def HasField(self, field_name: typing_extensions___Literal[u"Bar"]) -> builtin___bool: ...
def ClearField(self, field_name: typing_extensions___Literal[u"Bar"]) -> None: ...
else:
def HasField(self, field_name: typing_extensions___Literal[u"Bar",b"Bar"]) -> builtin___bool: ...
def ClearField(self, field_name: typing_extensions___Literal[u"Bar",b"Bar"]) -> None: ...
and the following test case reproduces the error message from my original comment:
from foo_pb2 import Bar, Foo
x: Foo = Foo(Bar=Bar(X=123))
This can also be fixed by defining an alias like _Bar = Bar
and referring to _Bar
in the definition of Foo
.
While using a field that has the same name as a type is admittedly not a great pattern, unfortunately we are stuck with it since we are already using these types in production.
Is there any workaround we could do here?
from mypy-protobuf.
yeah - this seems like a totally reasonable concern - that may be avoidable by autogenerating an alias. We already generate some aliases like typing_extensions__Literal
for mangling - so this seems like a reasonable strategy. Poking around with it to see what we can get working.
Great bugreport and analysis
from mypy-protobuf.
@nipunn1313, #112 looks like it will cover these above cases. Thanks for the quick turnaround!
from mypy-protobuf.
Related Issues (20)
- my-protobuf-3.4.0 breaks backward compatibility by silently upgrading to protobuf-4 HOT 10
- Add version to header comment. HOT 3
- No module named mypy_protobuf HOT 8
- Not generating .py files from protouf file using this plugin HOT 1
- Question: why not use Pythonโs Enum HOT 11
- Get generated code to be black-compatible for readability
- Compatibility with flake8-pyi>=23.5.0 HOT 1
- timeout should be float HOT 2
- Release version on pypi is to low! HOT 2
- A better way to annotation the AsyncStub HOT 9
- Document the experience on configuring properly with Visual Studio Code HOT 1
- Fix github actions warnings
- Add error code to bare type ignore
- Ignoring field names equal to reserved keywords like "from" HOT 1
- Manage optional field in Message body HOT 1
- OneOf fields not typed as optional in constructor HOT 3
- Add metaclass=GeneratedProtocolMessageType to protobuf message class HOT 3
- `google.protobuf.any_pb2.global__Any` is not marked as `TypeAlias` HOT 5
- Where is the tag for version 3.6.0? HOT 1
- Somewhat random `Module "project.foo.bar" has no attribute "baz_pb2" [attr-defined]` errors HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from mypy-protobuf.