c0mr4t
c0mr4t

Reputation: 361

How can I type hint the return type of .values() in a custom dict subclass?

When I type check the following class with mypy it throws an error

error: Returning Any from function declared to return "Optional[SomeDictValueType]"

in get_by_id as the type of .values() isn't defined/restricted properly.

class SomeDict(dict):
    def __init__(self) -> None:
        self._some_attribute: SomeRandomType = None

    def get_by_id(self, id: str) -> Optional[SomeDictValueType]:
        for p in self.values():
            if p._id == id:
                return p
        return None

I found similar questions online and tried the following things:
  1. adding type hints to __setitem__ as explained here

     def __setitem__(self, key: str, value: SomeDictValueType) -> None:
         super(SomeDict, self).__setitem__(key, value)
    
  2. using Mapping in the class header as explained here

     class SomeDict(dict, Mapping[str, SomeDictValueType]): ...
    

How can I get rid of this error without using # type: ignore? Instances of this class will never hold values of a type other than SomeDictValueType.


EDIT:
Here is a minimalistic example to reproduce the error. Save the following code snippet to a python file and execute mypy --strict <filename>.py on it.

from typing import Optional

class SomeDict(dict):  # type: ignore
    def __init__(self) -> None:
        self._some_attribute: Optional[str] = None

    def get_by_id(self, id: str) -> Optional[int]:
        for p in self.values():
            if p._id == id:
                return p
        return None

The following error should be thrown:

test.py:10: error: Returning Any from function declared to return "Optional[int]"

Upvotes: 0

Views: 2240

Answers (2)

c0mr4t
c0mr4t

Reputation: 361

I think, I just figured it out. I thought you cannot subclass from a typing definition (I tried it once at the beginning but got another error and didn't look close enough).
In my opinion, the following snippet would be a solution for the minimalistic error reproducing example.

from typing import Optional, Dict

class SomeDict(Dict[str, int]):
    def __init__(self) -> None:
        self._some_attribute: Optional[str] = None

    def get_by_id(self, id: str) -> Optional[int]:
        for p in self.values():
            if p == 5:
                return p
        return None

Upvotes: 1

balderman
balderman

Reputation: 23825

mypy is correct. Since you iterate over values(), it can not tell what is the type of the dict value, it consider it as Any.

Upvotes: 1

Related Questions