bpo-42133: update parts of the stdlib to fall back to `__spec__.loader` when `__loader__` is missing (#22929)

This commit is contained in:
Brett Cannon 2020-11-06 18:45:56 -08:00 committed by GitHub
parent 7c01f1540f
commit 825ac38332
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 14 deletions

View File

@ -186,6 +186,12 @@ by :func:`curses.color_content`, :func:`curses.init_color`,
support is provided by the underlying ncurses library. support is provided by the underlying ncurses library.
(Contributed by Jeffrey Kintscher and Hans Petter Jansson in :issue:`36982`.) (Contributed by Jeffrey Kintscher and Hans Petter Jansson in :issue:`36982`.)
doctest
-------
When a module does not define ``__loader__``, fall back to ``__spec__.loader``.
(Contributed by Brett Cannon in :issue:`42133`.)
encodings encodings
--------- ---------
:func:`encodings.normalize_encoding` now ignores non-ASCII characters. :func:`encodings.normalize_encoding` now ignores non-ASCII characters.
@ -198,6 +204,18 @@ Added the *root_dir* and *dir_fd* parameters in :func:`~glob.glob` and
:func:`~glob.iglob` which allow to specify the root directory for searching. :func:`~glob.iglob` which allow to specify the root directory for searching.
(Contributed by Serhiy Storchaka in :issue:`38144`.) (Contributed by Serhiy Storchaka in :issue:`38144`.)
inspect
-------
When a module does not define ``__loader__``, fall back to ``__spec__.loader``.
(Contributed by Brett Cannon in :issue:`42133`.)
linecache
---------
When a module does not define ``__loader__``, fall back to ``__spec__.loader``.
(Contributed by Brett Cannon in :issue:`42133`.)
os os
-- --
@ -217,6 +235,12 @@ The :mod:`shelve` module now uses :data:`pickle.DEFAULT_PROTOCOL` by default
instead of :mod:`pickle` protocol ``3`` when creating shelves. instead of :mod:`pickle` protocol ``3`` when creating shelves.
(Contributed by Zackery Spytz in :issue:`34204`.) (Contributed by Zackery Spytz in :issue:`34204`.)
site
----
When a module does not define ``__loader__``, fall back to ``__spec__.loader``.
(Contributed by Brett Cannon in :issue:`42133`.)
sys sys
--- ---

View File

@ -222,9 +222,13 @@ def _load_testfile(filename, package, module_relative, encoding):
if module_relative: if module_relative:
package = _normalize_module(package, 3) package = _normalize_module(package, 3)
filename = _module_relative_path(package, filename) filename = _module_relative_path(package, filename)
if getattr(package, '__loader__', None) is not None: if (loader := getattr(package, '__loader__', None)) is None:
if hasattr(package.__loader__, 'get_data'): try:
file_contents = package.__loader__.get_data(filename) loader = package.__spec__.loader
except AttributeError:
pass
if hasattr(loader, 'get_data'):
file_contents = loader.get_data(filename)
file_contents = file_contents.decode(encoding) file_contents = file_contents.decode(encoding)
# get_data() opens files as 'rb', so one must do the equivalent # get_data() opens files as 'rb', so one must do the equivalent
# conversion as universal newlines would do. # conversion as universal newlines would do.

View File

@ -707,10 +707,13 @@ def getsourcefile(object):
if os.path.exists(filename): if os.path.exists(filename):
return filename return filename
# only return a non-existent filename if the module has a PEP 302 loader # only return a non-existent filename if the module has a PEP 302 loader
if getattr(getmodule(object, filename), '__loader__', None) is not None: module = getmodule(object, filename)
if getattr(module, '__loader__', None) is not None:
return filename
elif getattr(getattr(module, "__spec__", None), "loader", None) is not None:
return filename return filename
# or it is in the linecache # or it is in the linecache
if filename in linecache.cache: elif filename in linecache.cache:
return filename return filename
def getabsfile(object, _filename=None): def getabsfile(object, _filename=None):

View File

@ -165,9 +165,14 @@ def lazycache(filename, module_globals):
if not filename or (filename.startswith('<') and filename.endswith('>')): if not filename or (filename.startswith('<') and filename.endswith('>')):
return False return False
# Try for a __loader__, if available # Try for a __loader__, if available
if module_globals and '__loader__' in module_globals: if module_globals and '__name__' in module_globals:
name = module_globals.get('__name__') name = module_globals['__name__']
loader = module_globals['__loader__'] if (loader := module_globals.get('__loader__')) is None:
if spec := module_globals.get('__spec__'):
try:
loader = spec.loader
except AttributeError:
pass
get_source = getattr(loader, 'get_source', None) get_source = getattr(loader, 'get_source', None)
if name and get_source: if name and get_source:

View File

@ -105,8 +105,15 @@ def makepath(*paths):
def abs_paths(): def abs_paths():
"""Set all module __file__ and __cached__ attributes to an absolute path""" """Set all module __file__ and __cached__ attributes to an absolute path"""
for m in set(sys.modules.values()): for m in set(sys.modules.values()):
if (getattr(getattr(m, '__loader__', None), '__module__', None) not in loader_module = None
('_frozen_importlib', '_frozen_importlib_external')): try:
loader_module = m.__loader__.__module__
except AttributeError:
try:
loader_module = m.__spec__.loader.__module__
except AttributeError:
pass
if loader_module not in {'_frozen_importlib', '_frozen_importlib_external'}:
continue # don't mess with a PEP 302-supplied __file__ continue # don't mess with a PEP 302-supplied __file__
try: try:
m.__file__ = os.path.abspath(m.__file__) m.__file__ = os.path.abspath(m.__file__)

View File

@ -0,0 +1,2 @@
Update various modules in the stdlib to fall back on `__spec__.loader` when
`__loader__` isn't defined on a module.