Skip to content

types.ModuleType.__getattr__ is never respected #1346

@AlexWaygood

Description

@AlexWaygood

Summary

Typeshed includes a __getattr__ method on its stub for types.ModuleType. This makes code like this easier to write: although it is true that not all modules have an __all__ attribute, I do happen to know in this case that all the submodules of typeshed_stats do have __all__ attributes, and it would be somewhat annoying to have to type: ignore these lines. There's no other way of annotating this code to make the type checker happy, and it's pretty often the case that when you're handling a list of ModuleType instances in this way in Python, you know where they came from. A little bit of dynamic typing here goes a long way to improve ergonomics.

Ty ignores ModuleType.__getattr__ when resolving attribute accesses on module literal types, which is good, because otherwise it would consider every module to have every attribute. But it also ignores ModuleType.__getattr__ when resolving attribute accesses on non-literal instances of ModuleType, which doesn't seem right. Ty therefore emits an unresolved-attribute diagnostic on this snippet even though mypy, pyright and pyrefly all have no complaints about it:

import types

def f(x: types.ModuleType):
    print(x.__all__)

I spotted this by studying the ecosystem report in astral-sh/ruff#20723 (comment)

Version

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    attribute accessInstance attributes, class attributes, etc.bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions