Use protocols instead of importlib.abc.Loader/MetaPathFinder/PathEntryFinder (#11890)

This commit is contained in:
Anderson Bravalheri
2024-05-12 10:58:33 +01:00
committed by GitHub
parent 6565e8a0a0
commit b42e3b2e89
8 changed files with 72 additions and 25 deletions

View File

@@ -1,7 +1,14 @@
from __future__ import annotations
import importlib.abc
import importlib.util
import pathlib
import sys
import zipfile
from collections.abc import Sequence
from importlib.machinery import ModuleSpec
from types import ModuleType
from typing_extensions import Self
# Assert that some Path classes are Traversable.
if sys.version_info >= (3, 9):
@@ -11,3 +18,30 @@ if sys.version_info >= (3, 9):
traverse(pathlib.Path())
traverse(zipfile.Path(""))
class MetaFinder:
@classmethod
def find_spec(cls, fullname: str, path: Sequence[str] | None, target: ModuleType | None = None) -> ModuleSpec | None:
return None # simplified mock for demonstration purposes only
class PathFinder:
@classmethod
def path_hook(cls, path_entry: str) -> type[Self]:
return cls # simplified mock for demonstration purposes only
@classmethod
def find_spec(cls, fullname: str, target: ModuleType | None = None) -> ModuleSpec | None:
return None # simplified mock for demonstration purposes only
class Loader:
@classmethod
def load_module(cls, fullname: str) -> ModuleType:
return ModuleType(fullname)
sys.meta_path.append(MetaFinder)
sys.path_hooks.append(PathFinder.path_hook)
importlib.util.spec_from_loader("xxxx42xxxx", Loader)

View File

@@ -0,0 +1,18 @@
# Implicit protocols used in importlib.
# We intentionally omit deprecated and optional methods.
from collections.abc import Sequence
from importlib.machinery import ModuleSpec
from types import ModuleType
from typing import Protocol
__all__ = ["LoaderProtocol", "MetaPathFinderProtocol", "PathEntryFinderProtocol"]
class LoaderProtocol(Protocol):
def load_module(self, fullname: str, /) -> ModuleType: ...
class MetaPathFinderProtocol(Protocol):
def find_spec(self, fullname: str, path: Sequence[str] | None, target: ModuleType | None = ..., /) -> ModuleSpec | None: ...
class PathEntryFinderProtocol(Protocol):
def find_spec(self, fullname: str, target: ModuleType | None = ..., /) -> ModuleSpec | None: ...

View File

@@ -64,7 +64,7 @@ class SourceLoader(ResourceLoader, ExecutionLoader, metaclass=ABCMeta):
# The base classes differ starting in 3.10:
if sys.version_info >= (3, 10):
# Please keep in sync with sys._MetaPathFinder
# Please keep in sync with _typeshed.importlib.MetaPathFinderProtocol
class MetaPathFinder(metaclass=ABCMeta):
if sys.version_info < (3, 12):
def find_module(self, fullname: str, path: Sequence[str] | None) -> Loader | None: ...
@@ -85,7 +85,7 @@ if sys.version_info >= (3, 10):
def find_spec(self, fullname: str, target: types.ModuleType | None = ...) -> ModuleSpec | None: ...
else:
# Please keep in sync with sys._MetaPathFinder
# Please keep in sync with _typeshed.importlib.MetaPathFinderProtocol
class MetaPathFinder(Finder):
def find_module(self, fullname: str, path: Sequence[str] | None) -> Loader | None: ...
def invalidate_caches(self) -> None: ...

View File

@@ -3,6 +3,7 @@ import importlib.machinery
import sys
import types
from _typeshed import ReadableBuffer, StrOrBytesPath
from _typeshed.importlib import LoaderProtocol
from collections.abc import Callable
from typing import Any
from typing_extensions import ParamSpec
@@ -23,13 +24,13 @@ def source_from_cache(path: str) -> str: ...
def decode_source(source_bytes: ReadableBuffer) -> str: ...
def find_spec(name: str, package: str | None = None) -> importlib.machinery.ModuleSpec | None: ...
def spec_from_loader(
name: str, loader: importlib.abc.Loader | None, *, origin: str | None = None, is_package: bool | None = None
name: str, loader: LoaderProtocol | None, *, origin: str | None = None, is_package: bool | None = None
) -> importlib.machinery.ModuleSpec | None: ...
def spec_from_file_location(
name: str,
location: StrOrBytesPath | None = None,
*,
loader: importlib.abc.Loader | None = None,
loader: LoaderProtocol | None = None,
submodule_search_locations: list[str] | None = ...,
) -> importlib.machinery.ModuleSpec | None: ...
def module_from_spec(spec: importlib.machinery.ModuleSpec) -> types.ModuleType: ...

View File

@@ -1,7 +1,7 @@
import sys
from _typeshed import SupportsRead
from _typeshed.importlib import LoaderProtocol, MetaPathFinderProtocol, PathEntryFinderProtocol
from collections.abc import Callable, Iterable, Iterator
from importlib.abc import Loader, MetaPathFinder, PathEntryFinder
from typing import IO, Any, NamedTuple, TypeVar
from typing_extensions import deprecated
@@ -23,7 +23,7 @@ if sys.version_info < (3, 12):
_PathT = TypeVar("_PathT", bound=Iterable[str])
class ModuleInfo(NamedTuple):
module_finder: MetaPathFinder | PathEntryFinder
module_finder: MetaPathFinderProtocol | PathEntryFinderProtocol
name: str
ispkg: bool
@@ -37,11 +37,11 @@ if sys.version_info < (3, 12):
def __init__(self, fullname: str, file: IO[str], filename: str, etc: tuple[str, str, int]) -> None: ...
@deprecated("Use importlib.util.find_spec() instead. Will be removed in Python 3.14.")
def find_loader(fullname: str) -> Loader | None: ...
def get_importer(path_item: str) -> PathEntryFinder | None: ...
def find_loader(fullname: str) -> LoaderProtocol | None: ...
def get_importer(path_item: str) -> PathEntryFinderProtocol | None: ...
@deprecated("Use importlib.util.find_spec() instead. Will be removed in Python 3.14.")
def get_loader(module_or_name: str) -> Loader | None: ...
def iter_importers(fullname: str = "") -> Iterator[MetaPathFinder | PathEntryFinder]: ...
def get_loader(module_or_name: str) -> LoaderProtocol | None: ...
def iter_importers(fullname: str = "") -> Iterator[MetaPathFinderProtocol | PathEntryFinderProtocol]: ...
def iter_modules(path: Iterable[str] | None = None, prefix: str = "") -> Iterator[ModuleInfo]: ...
def read_code(stream: SupportsRead[bytes]) -> Any: ... # undocumented
def walk_packages(

View File

@@ -1,9 +1,8 @@
import sys
from _typeshed import OptExcInfo, ProfileFunction, TraceFunction, structseq
from _typeshed.importlib import MetaPathFinderProtocol, PathEntryFinderProtocol
from builtins import object as _object
from collections.abc import AsyncGenerator, Callable, Sequence
from importlib.abc import PathEntryFinder
from importlib.machinery import ModuleSpec
from io import TextIOWrapper
from types import FrameType, ModuleType, TracebackType
from typing import Any, Final, Literal, NoReturn, Protocol, TextIO, TypeVar, final
@@ -15,10 +14,6 @@ _T = TypeVar("_T")
_ExitCode: TypeAlias = str | int | None
_OptExcInfo: TypeAlias = OptExcInfo # noqa: Y047 # TODO: obsolete, remove fall 2022 or later
# Intentionally omits one deprecated and one optional method of `importlib.abc.MetaPathFinder`
class _MetaPathFinder(Protocol):
def find_spec(self, fullname: str, path: Sequence[str] | None, target: ModuleType | None = ..., /) -> ModuleSpec | None: ...
# ----- sys variables -----
if sys.platform != "win32":
abiflags: str
@@ -44,13 +39,13 @@ if sys.version_info >= (3, 12):
last_exc: BaseException # or undefined.
maxsize: int
maxunicode: int
meta_path: list[_MetaPathFinder]
meta_path: list[MetaPathFinderProtocol]
modules: dict[str, ModuleType]
if sys.version_info >= (3, 10):
orig_argv: list[str]
path: list[str]
path_hooks: list[Callable[[str], PathEntryFinder]]
path_importer_cache: dict[str, PathEntryFinder | None]
path_hooks: list[Callable[[str], PathEntryFinderProtocol]]
path_importer_cache: dict[str, PathEntryFinderProtocol | None]
platform: str
if sys.version_info >= (3, 9):
platlibdir: str

View File

@@ -1,5 +1,6 @@
import sys
from _typeshed import SupportsKeysAndGetItem
from _typeshed.importlib import LoaderProtocol
from collections.abc import (
AsyncGenerator,
Awaitable,
@@ -16,7 +17,7 @@ from collections.abc import (
from importlib.machinery import ModuleSpec
# pytype crashes if types.MappingProxyType inherits from collections.abc.Mapping instead of typing.Mapping
from typing import Any, ClassVar, Literal, Mapping, Protocol, TypeVar, final, overload # noqa: Y022
from typing import Any, ClassVar, Literal, Mapping, TypeVar, final, overload # noqa: Y022
from typing_extensions import ParamSpec, Self, TypeVarTuple, deprecated
__all__ = [
@@ -318,15 +319,12 @@ class SimpleNamespace:
def __setattr__(self, name: str, value: Any, /) -> None: ...
def __delattr__(self, name: str, /) -> None: ...
class _LoaderProtocol(Protocol):
def load_module(self, fullname: str, /) -> ModuleType: ...
class ModuleType:
__name__: str
__file__: str | None
@property
def __dict__(self) -> dict[str, Any]: ... # type: ignore[override]
__loader__: _LoaderProtocol | None
__loader__: LoaderProtocol | None
__package__: str | None
__path__: MutableSequence[str]
__spec__: ModuleSpec | None

View File

@@ -1,6 +1,7 @@
import types
import zipimport
from _typeshed import Incomplete, StrPath, Unused
from _typeshed.importlib import LoaderProtocol
from collections.abc import Callable, Generator, Iterable, Iterator, Sequence
from io import BytesIO
from itertools import chain
@@ -359,7 +360,7 @@ def evaluate_marker(text: str, extra: Incomplete | None = None) -> bool: ...
class NullProvider:
egg_name: str | None
egg_info: str | None
loader: types._LoaderProtocol | None
loader: LoaderProtocol | None
module_path: str | None
def __init__(self, module: _ModuleLike) -> None: ...