-
Notifications
You must be signed in to change notification settings - Fork 80
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
Question: why not use Python’s Enum #484
Comments
Hi - thanks for the interest! The mypy types are trying to correctly represent what protobuf actually presents. Protobuf's python generator does not actually produce an If we typed it as If you prefer IntEnum, you can write up your own IntEnum and take the int from protobuf and decode it into your custom IntEnum class. |
Thanks @nipunn1313, that makes sense. I’ve been using Python Enums but the extra layer of mapping from protobuf Any thoughts on the second question about typing the function arg? |
Hi. I think enums values in protobuf are represented as ints. The enum class itself is a subclass of There is good documentation on this here https://developers.google.com/protocol-buffers/docs/reference/python-generated#enum. I find the choice of behavior confusing, but this is how protobuf works. Play around with it a bit and see if you might be able to come up with something. For your specific question, you might want your function to take in |
Sorry, I misread the
Oh nice, I’ve not seen that bit of docs yet 👍🏼
Actually, the function is supposed to take the enum type itself, not a specific enum value. For example: enum MyEnum1 { ... }
enum MyEnum2 { ... }
enum MyEnum3 { ... } then the function should look like this: # Here I’d like to narrow Any to “protobuf enums”. That’s why I tried using the
# metaclass type from which all the enums are built, but that didn’t work 🤔
def f(pb2_enum_type: Any):
print(pb2_enum_type.items())
f(MyEnum1) # Prints all enum values for MyEnum1 (or any other). |
Here's an example
in your example, I think you want this:
|
Another possibility would include a generic
|
Heh… that’s where it all started 😉 If I run this from protos import foo_pb2 # Supplies MyEnum.
from google.protobuf.internal.enum_type_wrapper import EnumTypeWrapper
def f(pb2_enum_type: EnumTypeWrapper) -> None:
print(pb2_enum_type.items())
f(foo_pb2.MyEnum) then I get the expected result:
However,
I tried
So, here I am 🤓 |
Aha thanks for walking me through the entire process up to where you are now. Let me try to explain what protobuf autogenerates (it's a bit weird). Protobuf autogenerates an object Mypy protobuf wants to allow you to ensure that
In typeshed, Hence I think in your code, in order for it to work, you would need to use from protos import foo_pb2 # Supplies MyEnum.
from typing import TypeVar, TYPE_CHECKING
if TYPE_CHECKING:
from google.protobuf.internal.enum_type_wrapper import _EnumTypeWrapper
_V = TypeVar("_V", bound=int)
def f(pb2_enum_type: _EnumTypeWrapper[_V]) -> None:
print(pb2_enum_type.items())
f(foo_pb2.MyEnum) We may actually be able to achieve the goal of having I haven't tested the above - just typing it off the top of my head. Could take a closer look when I get some time in one of these upcoming weekends. |
@nipunn1313 I think your suggestion actually worked 🥳 One minor tweak though: if TYPE_CHECKING:
from google.protobuf.internal.enum_type_wrapper import _EnumTypeWrapper
else:
_EnumTypeWrapper = Generic to ensure that
Do you think that’s a change that could roll out soon? I’m going to use the above suggestion for now, though. |
In python3.10 and up, type annotations aren't executed at runtime. I will give it a shot when I get the chance. I am not 100% sure if it will work (hard to wrap my head around conceptually without trying it out), but will try and see. |
I’m on Python 3.10 and according to the docs, The first type annotation must be enclosed in quotes, making it a “forward reference”, […]. Now it works 👍🏼 Alternatively, the
No problem. If you like I can give you more actual context, to help with the practical relevance… |
I keep playing with protobuf’s enumerations which are encoded as 32b integers.
When compiled to Python and using this plugin, protobuf enums are represented using an
int
subtypeEnumTypeWrapper
to implement a stronger typedint
of sorts.What was the reasoning behind this decision vs. using e.g. IntEnum?
Also, suppose I have two or more enums and compile them to Python. I now would like to have a function
which takes any one of the enums, how would I type that function’s arg? I understood that metaclasses are handled ok by
mypy
but the above case fails withThe text was updated successfully, but these errors were encountered: