"""The machinery of importlib: finders, loaders, hooks, etc."""

import importlib.abc
import sys
import types
from _typeshed import ReadableBuffer
from collections.abc import Callable, Iterable, MutableSequence, Sequence
from importlib.metadata import DistributionFinder, PathDistribution
from typing import Any, Literal
from typing_extensions import deprecated

class ModuleSpec:
    """
    The specification for a module, used for loading.

    A module's spec is the source for information about the module.  For
    data associated with the module, including source, use the spec's
    loader.

    `name` is the absolute name of the module.  `loader` is the loader
    to use when loading the module.  `parent` is the name of the
    package the module is in.  The parent is derived from the name.

    `is_package` determines if the module is considered a package or
    not.  On modules this is reflected by the `__path__` attribute.

    `origin` is the specific location used by the loader from which to
    load the module, if that information is available.  When filename is
    set, origin will match.

    `has_location` indicates that a spec's "origin" reflects a location.
    When this is True, `__file__` attribute of the module is set.

    `cached` is the location of the cached bytecode file, if any.  It
    corresponds to the `__cached__` attribute.

    `submodule_search_locations` is the sequence of path entries to
    search when importing submodules.  If set, is_package should be
    True--and False otherwise.

    Packages are simply modules that (may) have submodules.  If a spec
    has a non-None value in `submodule_search_locations`, the import
    system will consider modules loaded from the spec as packages.

    Only finders (see importlib.abc.MetaPathFinder and
    importlib.abc.PathEntryFinder) should modify ModuleSpec instances.
    """
    def __init__(
        self,
        name: str,
        loader: importlib.abc.Loader | None,
        *,
        origin: str | None = None,
        loader_state: Any = None,
        is_package: bool | None = None,
    ) -> None: ...
    name: str
    loader: importlib.abc.Loader | None
    origin: str | None
    submodule_search_locations: list[str] | None
    loader_state: Any
    cached: str | None
    @property
    def parent(self) -> str | None:
        """The name of the module's parent."""
        ...
    has_location: bool
    def __eq__(self, other: object) -> bool: ...

class BuiltinImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader):
    """
    Meta path import for built-in modules.

    All methods are either class or static methods to avoid the need to
    instantiate the class.
    """
    # MetaPathFinder
    if sys.version_info < (3, 12):
        @classmethod
        def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ...

    @classmethod
    def find_spec(
        cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None
    ) -> ModuleSpec | None: ...
    # InspectLoader
    @classmethod
    def is_package(cls, fullname: str) -> bool:
        """Return False as built-in modules are never packages."""
        ...
    @classmethod
    def load_module(cls, fullname: str) -> types.ModuleType:
        """
        Load the specified module into sys.modules and return it.

        This method is deprecated.  Use loader.exec_module() instead.
        """
        ...
    @classmethod
    def get_code(cls, fullname: str) -> None:
        """Return None as built-in modules do not have code objects."""
        ...
    @classmethod
    def get_source(cls, fullname: str) -> None:
        """Return None as built-in modules do not have source code."""
        ...
    # Loader
    if sys.version_info < (3, 12):
        @staticmethod
        def module_repr(module: types.ModuleType) -> str: ...
    if sys.version_info >= (3, 10):
        @staticmethod
        def create_module(spec: ModuleSpec) -> types.ModuleType | None:
            """Create a built-in module"""
            ...
        @staticmethod
        def exec_module(module: types.ModuleType) -> None:
            """Exec a built-in module"""
            ...
    else:
        @classmethod
        def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ...
        @classmethod
        def exec_module(cls, module: types.ModuleType) -> None: ...

class FrozenImporter(importlib.abc.MetaPathFinder, importlib.abc.InspectLoader):
    """
    Meta path import for frozen modules.

    All methods are either class or static methods to avoid the need to
    instantiate the class.
    """
    # MetaPathFinder
    if sys.version_info < (3, 12):
        @classmethod
        def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ...

    @classmethod
    def find_spec(
        cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None
    ) -> ModuleSpec | None: ...
    # InspectLoader
    @classmethod
    def is_package(cls, fullname: str) -> bool:
        """Return True if the frozen module is a package."""
        ...
    @classmethod
    def load_module(cls, fullname: str) -> types.ModuleType:
        """
        Load a frozen module.

        This method is deprecated.  Use exec_module() instead.
        """
        ...
    @classmethod
    def get_code(cls, fullname: str) -> None:
        """Return the code object for the frozen module."""
        ...
    @classmethod
    def get_source(cls, fullname: str) -> None:
        """Return None as frozen modules do not have source code."""
        ...
    # Loader
    if sys.version_info < (3, 12):
        @staticmethod
        def module_repr(m: types.ModuleType) -> str: ...
    if sys.version_info >= (3, 10):
        @staticmethod
        def create_module(spec: ModuleSpec) -> types.ModuleType | None:
            """Set __file__, if able."""
            ...
    else:
        @classmethod
        def create_module(cls, spec: ModuleSpec) -> types.ModuleType | None: ...

    @staticmethod
    def exec_module(module: types.ModuleType) -> None: ...

class WindowsRegistryFinder(importlib.abc.MetaPathFinder):
    """Meta path finder for modules declared in the Windows registry."""
    if sys.version_info < (3, 12):
        @classmethod
        def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ...

    @classmethod
    def find_spec(
        cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None
    ) -> ModuleSpec | None: ...

class PathFinder:
    """Meta path finder for sys.path and package __path__ attributes."""
    if sys.version_info >= (3, 10):
        @staticmethod
        def invalidate_caches() -> None:
            """
            Call the invalidate_caches() method on all path entry finders
            stored in sys.path_importer_cache (where implemented).
            """
            ...
    else:
        @classmethod
        def invalidate_caches(cls) -> None: ...
    if sys.version_info >= (3, 10):
        @staticmethod
        def find_distributions(context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]:
            """
            Find distributions.

            Return an iterable of all Distribution instances capable of
            loading the metadata for packages matching ``context.name``
            (or all names if ``None`` indicated) along the paths in the list
            of directories ``context.path``.
            """
            ...
    else:
        @classmethod
        def find_distributions(cls, context: DistributionFinder.Context = ...) -> Iterable[PathDistribution]: ...

    @classmethod
    def find_spec(
        cls, fullname: str, path: Sequence[str] | None = None, target: types.ModuleType | None = None
    ) -> ModuleSpec | None:
        """
        Try to find a spec for 'fullname' on sys.path or 'path'.

        The search is based on sys.path_hooks and sys.path_importer_cache.
        """
        ...
    if sys.version_info < (3, 12):
        @classmethod
        def find_module(cls, fullname: str, path: Sequence[str] | None = None) -> importlib.abc.Loader | None: ...

SOURCE_SUFFIXES: list[str]
DEBUG_BYTECODE_SUFFIXES: list[str]
OPTIMIZED_BYTECODE_SUFFIXES: list[str]
BYTECODE_SUFFIXES: list[str]
EXTENSION_SUFFIXES: list[str]

def all_suffixes() -> list[str]:
    """Returns a list of all recognized module suffixes for this process"""
    ...

class FileFinder(importlib.abc.PathEntryFinder):
    """
    File-based finder.

    Interactions with the file system are cached for performance, being
    refreshed when the directory the finder is handling has been modified.
    """
    path: str
    def __init__(self, path: str, *loader_details: tuple[type[importlib.abc.Loader], list[str]]) -> None:
        """
        Initialize with the path to search on and a variable number of
        2-tuples containing the loader and the file suffixes the loader
        recognizes.
        """
        ...
    @classmethod
    def path_hook(
        cls, *loader_details: tuple[type[importlib.abc.Loader], list[str]]
    ) -> Callable[[str], importlib.abc.PathEntryFinder]:
        """
        A class method which returns a closure to use on sys.path_hook
        which will return an instance using the specified loaders and the path
        called on the closure.

        If the path called on the closure is not a directory, ImportError is
        raised.
        """
        ...

class SourceFileLoader(importlib.abc.FileLoader, importlib.abc.SourceLoader):
    """Concrete implementation of SourceLoader using the file system."""
    def set_data(self, path: str, data: ReadableBuffer, *, _mode: int = 0o666) -> None:
        """Write bytes data to a file."""
        ...

class SourcelessFileLoader(importlib.abc.FileLoader, importlib.abc.SourceLoader):
    """Loader which handles sourceless file imports."""
    ...

class ExtensionFileLoader(importlib.abc.ExecutionLoader):
    """
    Loader for extension modules.

    The constructor is designed to work with FileFinder.
    """
    def __init__(self, name: str, path: str) -> None: ...
    def get_filename(self, name: str | None = None) -> str:
        """Return the path to the source file as found by the finder."""
        ...
    def get_source(self, fullname: str) -> None:
        """Return None as extension modules have no source code."""
        ...
    def create_module(self, spec: ModuleSpec) -> types.ModuleType:
        """Create an uninitialized extension module"""
        ...
    def exec_module(self, module: types.ModuleType) -> None:
        """Initialize an extension module"""
        ...
    def get_code(self, fullname: str) -> None:
        """Return None as an extension module cannot create a code object."""
        ...
    def __eq__(self, other: object) -> bool: ...
    def __hash__(self) -> int: ...

if sys.version_info >= (3, 11):
    import importlib.readers

    class NamespaceLoader(importlib.abc.InspectLoader):
        def __init__(
            self, name: str, path: MutableSequence[str], path_finder: Callable[[str, tuple[str, ...]], ModuleSpec]
        ) -> None: ...
        def is_package(self, fullname: str) -> Literal[True]: ...
        def get_source(self, fullname: str) -> Literal[""]: ...
        def get_code(self, fullname: str) -> types.CodeType: ...
        def create_module(self, spec: ModuleSpec) -> None:
            """Use default semantics for module creation."""
            ...
        def exec_module(self, module: types.ModuleType) -> None: ...
        @deprecated("load_module() is deprecated; use exec_module() instead")
        def load_module(self, fullname: str) -> types.ModuleType:
            """
            Load a namespace module.

            This method is deprecated.  Use exec_module() instead.
            """
            ...
        def get_resource_reader(self, module: types.ModuleType) -> importlib.readers.NamespaceReader: ...
        if sys.version_info < (3, 12):
            @staticmethod
            @deprecated("module_repr() is deprecated, and has been removed in Python 3.12")
            def module_repr(module: types.ModuleType) -> str: ...
