Skip to content

Feature request: accessing fields of TypeVars #8833

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

Closed
mikolajz opened this issue May 15, 2020 · 1 comment
Closed

Feature request: accessing fields of TypeVars #8833

mikolajz opened this issue May 15, 2020 · 1 comment

Comments

@mikolajz
Copy link

In ROS (www.ros.org) a service (=an RPC method) is defined by a class that has request_type and response_type fields with the types of the argument and return value an calling the service. One passes the service class to ServiceProxy constructor to create a service proxy object:

# Trigger.request_type == TriggerRequest, Trigger.response_type == TriggerResponse
update_service = rospy.ServiceProxy("/some/service/name", Trigger)  # Create proxy.
response: TriggerResponse = update_service(TriggerRequest(...))  # Perform the RPC.

To annotate it, I would like to be able to do:

class ServiceProxy(Generic[T]):
    def __init__(name: str, service_type: Type[T]): ...
    def __call__(request: T.request_type) -> T.response_type: ...

However, it seems I can't access subfields of a TypeVar ("name T.RequestType is not defined").

Of course, any other solution that will solve this problem (or is better than having a proxy function that takes the request and response types as parameters as well, which we will likely do in our project) is good as well.

PS: I've noticed that I can't use the type defined in the service class directly since as explained in #7866, it will be considered a variable, but I control the type stub generation so I can add there a 1-element Union which seems to work, so it's not a problem.

@mikolajz
Copy link
Author

Nevermind, this can be done with a Protocol instead of TypeVar:

ReqT = TypeVar('ReqT', bound=Message)
RespT = TypeVar('RespT', bound=Message)

class ServiceProtocol(Protocol[ReqT, RespT]):
    _request_class = None  # type: ClassVar[Type[ReqT]]
    _response_class = None  # type: ClassVar[Type[RespT]]

class ServiceProxy(_Service, Generic[ReqT, RespT]):
    def __init__(self, name: str, service_class: Type[ServiceProtocol[ReqT, RespT]]) -> None: ...
    def __call__(self, msg: ReqT) -> RespT: ...

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

1 participant