From 5d0cbffd7ac3663af64442c9727bae7f525e573f Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 15 Nov 2021 13:49:05 +0000 Subject: [PATCH 1/3] Harmonise return type of `builtins.__import__` and `importlib.import_module` --- stdlib/builtins.pyi | 2 +- stdlib/importlib/__init__.pyi | 1 + stdlib/types.pyi | 1 + tests/stubtest_allowlists/py3_common.txt | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 44e76da31b6d..21e113c18b8c 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1449,7 +1449,7 @@ def __import__( locals: Mapping[str, object] | None = ..., fromlist: Sequence[str] = ..., level: int = ..., -) -> Any: ... +) -> types.ModuleType: ... # 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 b7986de57a45..af7c3f500eab 100644 --- a/stdlib/importlib/__init__.pyi +++ b/stdlib/importlib/__init__.pyi @@ -2,6 +2,7 @@ import types from importlib.abc import Loader from typing import Any, Mapping, Sequence +# `__import__` and `import_module` return type should be kept the same as `builtins.__import__` def __import__( name: str, globals: Mapping[str, Any] | None = ..., diff --git a/stdlib/types.pyi b/stdlib/types.pyi index 7d738bf7eb7a..4c6031441998 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -178,6 +178,7 @@ class ModuleType: __path__: MutableSequence[str] __spec__: ModuleSpec | None def __init__(self, name: str, doc: str | None = ...) -> None: ... + 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 d22907d4bd14..ad4981cc4449 100644 --- a/tests/stubtest_allowlists/py3_common.txt +++ b/tests/stubtest_allowlists/py3_common.txt @@ -199,6 +199,7 @@ 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 From 676614241b5f794a7fe0318b9a98d35dc2a9b90c Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 15 Nov 2021 13:51:16 +0000 Subject: [PATCH 2/3] tweak builtins --- stdlib/builtins.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 21e113c18b8c..4ccaf52d4c8c 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1443,6 +1443,7 @@ class zip(Iterator[_T_co], Generic[_T_co]): def __iter__(self) -> Iterator[_T_co]: ... def __next__(self) -> _T_co: ... +# Return type of `__import__` should be kept the same as return type of `importlib.import_module` def __import__( name: str, globals: Mapping[str, object] | None = ..., From c36e17f983781f0443b66fc7426a4614540c3f1b Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 15 Nov 2021 13:54:34 +0000 Subject: [PATCH 3/3] tweak types.pyi --- stdlib/types.pyi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stdlib/types.pyi b/stdlib/types.pyi index 4c6031441998..ebf95db5795b 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -178,6 +178,9 @@ 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