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

Add metaclass=GeneratedProtocolMessageType to protobuf message class #581

Open
summylight opened this issue Apr 1, 2024 · 3 comments
Open

Comments

@summylight
Copy link

summylight commented Apr 1, 2024

I'm working on our codebase to apply mypy-protobuf to generate pyi code. However, we have codes like:

from google.protobuf import json_format
from google.protobuf.reflection import GeneratedProtocolMessageType

def convert_model_to_pb(
        config: Config,
        pb_class: GeneratedProtocolMessageType,
        ignore_unknown_fields: bool = False) -> Message:
    return json_format.ParseDict(
        config.to_json(use_str_for_datetime=True),
        pb_class()
    )

This func accepts protobuf message class as parameters, and parse proto into json. We add GeneratedProtocolMessageType as its type. and mypy would report this error since GeneratedProtocolMessageType does not exist in generated pyi files:

error: Argument 2 to "convert_model_to_pb" has incompatible type "Type[Config]"; expected "GeneratedProtocolMessageType"  [arg-type]

I add metaclass=metaclass=GeneratedProtocolMessageType to pyi files and pass mypy check:

Class Config(_message.Message, metaclass=GeneratedProtocolMessageType)

Can mypy-protobuf support this?

@summylight
Copy link
Author

Well, I realize it's hard to determine the type of return value in this func. I decide to write typing like this:

from typing import TypeVar, Type

T = TypeVar('T')
def convert_model_to_pb(
        config: Config,
        pb_class: Type['T'],
        ignore_unknown_fields: bool = False) -> T:


@summylight summylight reopened this Apr 1, 2024
@nipunn1313
Copy link
Owner

Well, I realize it's hard to determine the type of return value in this func. I decide to write typing like this:

from typing import TypeVar, Type

T = TypeVar('T')
def convert_model_to_pb(
        config: Config,
        pb_class: Type['T'],
        ignore_unknown_fields: bool = False) -> T:

This seems like the way to go. You may be able to restrict the TypeVar to a Message to really make sure it's a pb message being passed in. Otherwise, seems like you've figured it out.

@summylight
Copy link
Author

summylight commented Apr 2, 2024

Well, I realize it's hard to determine the type of return value in this func. I decide to write typing like this:

from typing import TypeVar, Type

T = TypeVar('T')
def convert_model_to_pb(
        config: Config,
        pb_class: Type['T'],
        ignore_unknown_fields: bool = False) -> T:

This seems like the way to go. You may be able to restrict the TypeVar to a Message to really make sure it's a pb message being passed in. Otherwise, seems like you've figured it out.

you are right. I added bound=Message to it:

T = TypeVar('T', bound=Message)

But I still think it's okay to add metaclass typing to proto message classes. Sorry if my idea is stupid.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants