The Wayback Machine - https://web.archive.org/web/20221223135756/https://github.com/python/cpython/pull/29049/files
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-35673: Add a public alias for namespace package __loader__ attribute #29049

Merged
merged 3 commits into from Oct 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1353,6 +1353,24 @@ find and load modules.
.. versionadded:: 3.4


.. class:: NamespaceLoader(name, path, path_finder):

A concrete implementation of :class:`importlib.abc.InspectLoader` for
namespace packages. This is an alias for a private class and is only made
public for introspecting the ``__loader__`` attribute on namespace
packages::

>>> from importlib.machinery import NamespaceLoader
>>> import my_namespace
>>> isinstance(my_namespace.__loader__, NamespaceLoader)
True
>>> import importlib.abc
>>> isinstance(my_namespace.__loader__, importlib.abc.Loader)
True

.. versionadded:: 3.11


.. class:: ModuleSpec(name, loader, *, origin=None, loader_state=None, is_package=None)

A specification for a module's import-system-related state. This is
@@ -507,9 +507,9 @@ def _init_module_attrs(spec, module, *, override=False):
if spec.submodule_search_locations is not None:
if _bootstrap_external is None:
raise NotImplementedError
_NamespaceLoader = _bootstrap_external._NamespaceLoader
NamespaceLoader = _bootstrap_external.NamespaceLoader

loader = _NamespaceLoader.__new__(_NamespaceLoader)
loader = NamespaceLoader.__new__(NamespaceLoader)
loader._path = spec.submodule_search_locations
spec.loader = loader
# While the docs say that module.__file__ is not set for
@@ -1279,8 +1279,10 @@ def append(self, item):
self._path.append(item)


# We use this exclusively in module_from_spec() for backward-compatibility.
class _NamespaceLoader:
# This class is actually exposed publicly in a namespace package's __loader__
# attribute, so it should be available through a non-private name.
# https://bugs.python.org/issue35673
class NamespaceLoader:
def __init__(self, name, path, path_finder):
self._path = _NamespacePath(name, path, path_finder)

@@ -1291,7 +1293,7 @@ def module_repr(module):
The method is deprecated. The import machinery does the job itself.

"""
_warnings.warn("_NamespaceLoader.module_repr() is deprecated and "
_warnings.warn("NamespaceLoader.module_repr() is deprecated and "
"slated for removal in Python 3.12", DeprecationWarning)
return '<module {!r} (namespace)>'.format(module.__name__)

@@ -1327,6 +1329,10 @@ def get_resource_reader(self, module):
return NamespaceReader(self._path)


# We use this exclusively in module_from_spec() for backward-compatibility.
_NamespaceLoader = NamespaceLoader


# Finders #####################################################################

class PathFinder:
@@ -213,7 +213,7 @@ def source_to_code(data, path='<string>'):
exec_module = _bootstrap_external._LoaderBasics.exec_module
load_module = _bootstrap_external._LoaderBasics.load_module

_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter)
_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader)


class ExecutionLoader(InspectLoader):
@@ -12,6 +12,7 @@
from ._bootstrap_external import SourceFileLoader
from ._bootstrap_external import SourcelessFileLoader
from ._bootstrap_external import ExtensionFileLoader
from ._bootstrap_external import NamespaceLoader


def all_suffixes():
@@ -1,5 +1,7 @@
import contextlib
import importlib
import importlib.abc
import importlib.machinery
import os
import sys
import unittest
@@ -342,6 +344,11 @@ def test_path_indexable(self):
expected_path = os.path.join(self.root, 'portion1', 'foo')
self.assertEqual(foo.__path__[0], expected_path)

def test_loader_abc(self):
import foo
self.assertTrue(isinstance(foo.__loader__, importlib.abc.Loader))
self.assertTrue(isinstance(foo.__loader__, importlib.machinery.NamespaceLoader))


if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,4 @@
Improve the introspectability of the ``__loader__`` attribute for namespace
packages. :class:`importlib.machinery.NamespaceLoader` is now public, and
implements the :class:`importlib.abc.InspectLoader` interface. ``_NamespaceLoader``
is kept for backward compatibility.