The Fool
The Fool

Reputation: 20587

Creating a typed decorator as classmethod and importing/using it in another file

I am trying to add typing to my project. I have pretty much replicated the pattern for decorator factories.

This is the example provided in the linked docs:

from typing import Any, Callable, TypeVar

F = TypeVar("F", bound=Callable[..., Any])

def route(url: str) -> Callable[[F], F]:
    ...

@route(url='/')
def index(request: Any) -> str:
    return 'Hello world'

This is my actual code:

from json import loads
from typing import TypeVar, Callable, Any, Optional, Dict, Union 


Handler = TypeVar("Handler", bound=Callable[[Any], None])

class Subscriber:
    """Decorate topic handlers. Must register the subscriber with register_subscriber."""

    def __init__(self) -> None:
        self.handlers: Dict[str, tuple] = dict()

    def topic(
        self, topic: str, 
        parse_func: Optional[Callable[[Union[str, bytes]], Any]] = loads
    ) -> Callable[[Handler], Handler]:
        """Subscribe to mqtt topic. by default the response is parsed with json.loads and passed into the handler.
        Override this with a custom parser or set it to None to receive the raw response."""

        def add_handler(handler: Handler) -> Handler:
            self.handlers[topic] = (handler, parse_func)
            return handler

        return add_handler

I am importing and using this class in another file.

from typing import Union
from from organization.namespace.package.mqtt.client import Subscriber

paho: Subscriber = Subscriber()

@paho.topic("test")
def test(payload: Union[dict, list]) -> None:
    print(payload)

But I am not able to get rid of this error.

Untyped decorator makes function "handler" untypedmypy(error)

As we found out through the help of @AlexWaygood, it doesn't throw this error when used from within the same file. But for some reason, it does when imported in another file like shown above.

My project has the following directory structure:

organization
└── namespace
    └── package
        └── mqtt
            ├── client.py
            └── handler.py

I do not currently have __init__.py files in my directories or sub-directories.

Upvotes: 1

Views: 304

Answers (1)

The Fool
The Fool

Reputation: 20587

This issue has to do with the module system. There are 2 different solutions to this problem:

  1. Create an __init__.py in each folder.
  2. Using the options --namespace-packages and --explicit-package-bases when running mypy.

For more details, see the mypy issues I created here and here.

Upvotes: 1

Related Questions