Skip to content

Mypy shoould not suggest Foo[...] if annotation contains Foo(arg=...) etc. #16506

Open
@gordiig

Description

@gordiig

Hi!
I've been developing something kinda like dependency injection mechanism and for it I've decided to create functions that return typing.Annotated with needed data and annotate di function arguments with this function. Something like that:

Provider-providable data code:

class _EnvironmentVariables(IProvidableData, Mapping):
    """
    Class storing environment variables from dump file.
    Should be used as Mapping
    """

    def __init__(self, variables: dict[str, bytes]) -> None:
        self.__variables = variables

    def as_json_obj(self) -> JSON:
        return {k: v.decode('ascii') for k, v in self.__variables.items()}

    def __getitem__(self, __key: str) -> bytes:
        return self.__variables.__getitem__(__key)

    def __len__(self) -> int:
        return self.__variables.__len__()

    def __iter__(self) -> Iterator[str]:
        return self.__variables.__iter__()

    def __str__(self):
        return str(self.__variables)


class EnvironmentVariablesProvider(ILinuxProvider[_EnvironmentVariables]):
    """
    Provides environment variables from Linux dump file
    """
    def __init__(self, coredump: Coredump, sort: bool) -> None:
        super().__init__(coredump=coredump)
        self.sort = sort

    def provide(self) -> _EnvironmentVariables:
        env_names = self.coredump.env.keys()
        if self.sort:
            env_names = sorted(env_names)

        envs = {env_name: self.coredump.getenv(env_name) for env_name in env_names}
        return _EnvironmentVariables(variables=envs)


def EnvironmentVariables(sort: bool):  # noqa (This func is imitating a type name, so upper-camel-case is ok)
    """
    Gets all environment variables from the core dump.

    These environment variables were captured by the process that generated core dump.

    Args:
        sort: Whether to sort variables by name or not

    Returns:
        Mapping with env name as a key and env value as a mapping value.

    Notes:
        This docstring is for user, so it is not covering or describing real implementation details!
    """
    return Annotated[_EnvironmentVariables, ArgsKwargs(sort=sort)]

End user code

@scenario(name='Unsorted env variables')  # Decorator for DI
@linux  # DI filter, doesn't matter in this example
def unsorted_env_variables(variables: EnvironmentVariables(sort=False)) -> JSON:
    return variables.as_json_obj()

The issue

The issue I have is that mypy is giving me error like:

error: Invalid type comment or annotation  [valid-type]
note: Suggestion: use EnvironmentVariables[...] instead of EnvironmentVariables(...)

I understand that static in "static code analysis" means that code won't run during this process and there is no (or almost no) way for mypy to see that EnvironmentVariables() returns typing.Annotated. But I think that mypy should be capable of differentiating function name from type name in type annotation.

This style of annotations might be kinda unintuitive, but I think that typing.Annotated is a mechanism that might be used dynamically by some users. And in this cases it is can be very handy to annotate argumens like that.

Environment:

  • Python version used: 3.10.1
  • Mypy version used: 1.7.0
  • Mypy configuration options from pyproject.toml:
### Mypy section
[tool.mypy]
python_version = "3.10"

files = "src/,test/"

# Stop errors for pytest_lazy_fixtures about untyped import
[[tool.mypy.overrides]]
module = "pytest_lazy_fixtures"
ignore_missing_imports = true

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions