Why does mypy complain about Any as return annotation and how should I annotate a return value that can be anything?

Question:

I have a class that is essentially a wrapper around a dictionary:

class Wrapper(dict):

    ...

    def __getitem__(self, item: Hashable) -> Any:
        return self.wrapped[item]

When checking the annotations with mypy, it yields an Explicit "Any" is not allowed when checking this code. My guess is that this stems from the concept that Any is the ancestor and successor of all other types. How should I annotate such function where I want to allow anything to be returned?

Asked By: funky-future

||

Answers:

This happens when the disallow_any_explicit is set to True for that module in the configuration file. Just remove that option for the default False.

Answered By: funky-future

You have provided insufficient information in the question to recreate this error but if your sole question is:

How should I annotate such function where I want to allow anything to be returned?

The simple answer is don’t annotate it at all. It will by default act as Any.

Answered By: Ishan Srivastava

We need to tell mypy that types of self.wrapped container are related to the ones of Wrapper methods, we can do that using typing.TypeVar instances for keys and values in our case.

So we can end up with something like

from collections import abc
from typing import (Dict,
                    Iterator,
                    TypeVar)


class Wrapper(abc.MutableMapping):
    KeyType = TypeVar('KeyType')
    ValueType = TypeVar('ValueType')

    def __init__(self, wrapped: Dict[KeyType, ValueType]) -> None:
        self.wrapped = wrapped

    def __delitem__(self, key: KeyType) -> None:
        del self.wrapped[key]

    def __len__(self) -> int:
        return len(self.wrapped)

    def __iter__(self) -> Iterator[KeyType]:
        return iter(self.wrapped)

    def __setitem__(self, key: KeyType, value: ValueType) -> None:
        self.wrapped[key] = value

    def __getitem__(self, key: KeyType) -> ValueType:
        return self.wrapped[key]

Test

Running mypy with --disallow-any-explicit flag causes no errors/warnings.

Note about inheritance/composition

If one really needs a custom mapping I’ll recommend to not mix inheritance from dict with using self.wrapped dict-field as it can cause a lot of pain in the future (we should re-define all of its methods or sometimes you will be using self.wrapped and sometimes not).

We can simply use MutableMapping ABC from collections.abc module and define basic methods (like __getitem__), the rest (keys(), values, items() are defined already).

Answered By: Azat Ibrakov
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.