From 2ce902b888bd03de29185c4141699629eb26e74f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 22 Nov 2021 16:17:41 +0000 Subject: [PATCH] Remove ModuleType.__getattr__ This caused false negatives for mypy -- mypy would consider that any module would have any attribute. The method also does not exist at runtime. I've also updated `builtins.__import__`, `importlib.__import__`, and `importlib.import_module` to return `Any`. I don't have a strong opinion on this change, but this arguably minimizes the impact of the removal, and maintains the return types of these functions consistent. Also, it could be argued that since arbitrary objects can be stuffed into `sys.modules` (and I've heard people actually suggest taking advantage of this), the `Any` type best reflects this. There may be other reasonable ways to deal with module objects, but I think that adding `ModuleType.__getattr__` regresses things too much. --- stdlib/builtins.pyi | 2 +- stdlib/importlib/__init__.pyi | 6 +++--- stdlib/types.pyi | 4 ---- tests/stubtest_allowlists/py3_common.txt | 1 - 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index dfafe6f738e5..240f95eb7ab2 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1487,7 +1487,7 @@ def __import__( locals: Mapping[str, object] | None = ..., fromlist: Sequence[str] = ..., level: int = ..., -) -> types.ModuleType: ... +) -> Any: ... # Actually the type of Ellipsis is , but since it's # not exposed anywhere under that name, we make it private here. diff --git a/stdlib/importlib/__init__.pyi b/stdlib/importlib/__init__.pyi index 1b91cc55f2df..d394c90fa9a7 100644 --- a/stdlib/importlib/__init__.pyi +++ b/stdlib/importlib/__init__.pyi @@ -1,6 +1,6 @@ from importlib.abc import Loader from types import ModuleType -from typing import Mapping, Sequence +from typing import Any, Mapping, Sequence # Signature of `builtins.__import__` should be kept identical to `importlib.__import__` def __import__( @@ -9,10 +9,10 @@ def __import__( locals: Mapping[str, object] | None = ..., fromlist: Sequence[str] = ..., level: int = ..., -) -> ModuleType: ... +) -> Any: ... # `importlib.import_module` return type should be kept the same as `builtins.__import__` -def import_module(name: str, package: str | None = ...) -> ModuleType: ... +def import_module(name: str, package: str | None = ...) -> Any: ... def find_loader(name: str, path: str | None = ...) -> Loader | None: ... def invalidate_caches() -> None: ... def reload(module: ModuleType) -> ModuleType: ... diff --git a/stdlib/types.pyi b/stdlib/types.pyi index 899024f2dd4d..2788cf22b343 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -180,10 +180,6 @@ class ModuleType: __path__: MutableSequence[str] __spec__: ModuleSpec | None def __init__(self, name: str, doc: str | None = ...) -> None: ... - # __getattr__ doesn't exist at runtime, - # but having it here in typeshed makes dynamic imports - # using `builtins.__import__` or `importlib.import_module` less painful - def __getattr__(self, name: str) -> Any: ... @final class GeneratorType(Generator[_T_co, _T_contra, _V_co]): diff --git a/tests/stubtest_allowlists/py3_common.txt b/tests/stubtest_allowlists/py3_common.txt index ad4981cc4449..d22907d4bd14 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -199,7 +199,6 @@ tkinter.font.Font.__getitem__ # Argument name differs (doesn't matter for __dun traceback.TracebackException.from_exception # explicitly expanding arguments going into TracebackException __init__ types.GetSetDescriptorType.__get__ # this function can accept no value for the type parameter. types.MemberDescriptorType.__get__ # this function can accept no value for the type parameter. -types.ModuleType.__getattr__ # this doesn't exist at runtime types.SimpleNamespace.__init__ # class doesn't accept positional arguments but has default C signature typing.IO.__iter__ # Added because IO streams are iterable. See https://github.com/python/typeshed/commit/97bc450acd60c1bcdafef3ce8fbe3b95a9c0cac3 typing.IO.__next__ # Added because IO streams are iterable. See https://github.com/python/typeshed/commit/97bc450acd60c1bcdafef3ce8fbe3b95a9c0cac3