This commit is contained in:
Brett Cannon 2025-12-08 06:10:50 +02:00 committed by GitHub
commit 1de5543593
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 95 additions and 242 deletions

View file

@ -129,8 +129,7 @@ Importing Modules
of :class:`~importlib.machinery.SourceFileLoader` otherwise. of :class:`~importlib.machinery.SourceFileLoader` otherwise.
The module's :attr:`~module.__file__` attribute will be set to the code The module's :attr:`~module.__file__` attribute will be set to the code
object's :attr:`~codeobject.co_filename`. If applicable, object's :attr:`~codeobject.co_filename`.
:attr:`~module.__cached__` will also be set.
This function will reload the module if it was already imported. See This function will reload the module if it was already imported. See
:c:func:`PyImport_ReloadModule` for the intended way to reload a module. :c:func:`PyImport_ReloadModule` for the intended way to reload a module.
@ -142,10 +141,13 @@ Importing Modules
:c:func:`PyImport_ExecCodeModuleWithPathnames`. :c:func:`PyImport_ExecCodeModuleWithPathnames`.
.. versionchanged:: 3.12 .. versionchanged:: 3.12
The setting of :attr:`~module.__cached__` and :attr:`~module.__loader__` The setting of ``__cached__`` and :attr:`~module.__loader__`
is deprecated. See :class:`~importlib.machinery.ModuleSpec` for is deprecated. See :class:`~importlib.machinery.ModuleSpec` for
alternatives. alternatives.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname) .. c:function:: PyObject* PyImport_ExecCodeModuleEx(const char *name, PyObject *co, const char *pathname)
@ -157,16 +159,19 @@ Importing Modules
.. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname) .. c:function:: PyObject* PyImport_ExecCodeModuleObject(PyObject *name, PyObject *co, PyObject *pathname, PyObject *cpathname)
Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__` Like :c:func:`PyImport_ExecCodeModuleEx`, but the path to any compiled file
attribute of the module object is set to *cpathname* if it is via *cpathname* is used appropriately when non-``NULL``. Of the three
non-``NULL``. Of the three functions, this is the preferred one to use. functions, this is the preferred one to use.
.. versionadded:: 3.3 .. versionadded:: 3.3
.. versionchanged:: 3.12 .. versionchanged:: 3.12
Setting :attr:`~module.__cached__` is deprecated. See Setting ``__cached__`` is deprecated. See
:class:`~importlib.machinery.ModuleSpec` for alternatives. :class:`~importlib.machinery.ModuleSpec` for alternatives.
.. versionchanged:: 3.15
``__cached__`` no longer set.
.. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname) .. c:function:: PyObject* PyImport_ExecCodeModuleWithPathnames(const char *name, PyObject *co, const char *pathname, const char *cpathname)

View file

@ -3,9 +3,9 @@ Pending removal in Python 3.15
* The import system: * The import system:
* Setting :attr:`~module.__cached__` on a module while * Setting ``__cached__`` on a module while
failing to set :attr:`__spec__.cached <importlib.machinery.ModuleSpec.cached>` failing to set :attr:`__spec__.cached <importlib.machinery.ModuleSpec.cached>`
is deprecated. In Python 3.15, :attr:`!__cached__` will cease to be set or is deprecated. In Python 3.15, ``__cached__`` will cease to be set or
take into consideration by the import system or standard library. (:gh:`97879`) take into consideration by the import system or standard library. (:gh:`97879`)
* Setting :attr:`~module.__package__` on a module while * Setting :attr:`~module.__package__` on a module while

View file

@ -136,7 +136,7 @@ enabled::
at Objects/unicodeobject.c:551 at Objects/unicodeobject.c:551
#7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569 #7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569
#8 0x0000000000584abd in PyDict_GetItemString (v= #8 0x0000000000584abd in PyDict_GetItemString (v=
{'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key= {'Yuck': <type at remote 0xad4730>, '__builtins__': <module at remote 0x7ffff7fd5ee8>, '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': <Yuck(i=0) at remote 0xaacd80>, 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__name__': '__main__', 'z': <Yuck(i=0) at remote 0xaace60>, '__doc__': None}, key=
0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171 0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171
Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed

View file

@ -526,7 +526,7 @@ are always available. They are listed here in alphabetical order.
>>> dir() # show the names in the module namespace # doctest: +SKIP >>> dir() # show the names in the module namespace # doctest: +SKIP
['__builtins__', '__name__', 'struct'] ['__builtins__', '__name__', 'struct']
>>> dir(struct) # show the names in the struct module # doctest: +SKIP >>> dir(struct) # show the names in the struct module # doctest: +SKIP
['Struct', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', ['Struct', '__all__', '__builtins__', '__doc__', '__file__',
'__initializing__', '__loader__', '__name__', '__package__', '__initializing__', '__loader__', '__name__', '__package__',
'_clearcache', 'calcsize', 'error', 'pack', 'pack_into', '_clearcache', 'calcsize', 'error', 'pack', 'pack_into',
'unpack', 'unpack_from'] 'unpack', 'unpack_from']

View file

@ -365,7 +365,6 @@ ABC hierarchy::
- :attr:`module.__name__` - :attr:`module.__name__`
- :attr:`module.__file__` - :attr:`module.__file__`
- :attr:`module.__cached__` *(deprecated)*
- :attr:`module.__path__` - :attr:`module.__path__`
- :attr:`module.__package__` *(deprecated)* - :attr:`module.__package__` *(deprecated)*
- :attr:`module.__loader__` *(deprecated)* - :attr:`module.__loader__` *(deprecated)*
@ -1262,8 +1261,7 @@ find and load modules.
.. attribute:: cached .. attribute:: cached
The filename of a compiled version of the module's code The filename of a compiled version of the module's code.
(see :attr:`module.__cached__`).
The :term:`finder` should always set this attribute but it may be ``None`` The :term:`finder` should always set this attribute but it may be ``None``
for modules that do not need compiled code stored. for modules that do not need compiled code stored.

View file

@ -50,10 +50,10 @@ The :mod:`runpy` module provides two functions:
overridden by :func:`run_module`. overridden by :func:`run_module`.
The special global variables ``__name__``, ``__spec__``, ``__file__``, The special global variables ``__name__``, ``__spec__``, ``__file__``,
``__cached__``, ``__loader__`` and ``__package__`` are set in the globals ``__loader__`` and ``__package__`` are set in the globals dictionary before
dictionary before the module code is executed. (Note that this is a the module code is executed. (Note that this is a minimal set of variables -
minimal set of variables - other variables may be set implicitly as an other variables may be set implicitly as an interpreter implementation
interpreter implementation detail.) detail.)
``__name__`` is set to *run_name* if this optional argument is not ``__name__`` is set to *run_name* if this optional argument is not
:const:`None`, to ``mod_name + '.__main__'`` if the named module is a :const:`None`, to ``mod_name + '.__main__'`` if the named module is a
@ -63,7 +63,7 @@ The :mod:`runpy` module provides two functions:
module (that is, ``__spec__.name`` will always be *mod_name* or module (that is, ``__spec__.name`` will always be *mod_name* or
``mod_name + '.__main__'``, never *run_name*). ``mod_name + '.__main__'``, never *run_name*).
``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` are ``__file__``, ``__loader__`` and ``__package__`` are
:ref:`set as normal <import-mod-attrs>` based on the module spec. :ref:`set as normal <import-mod-attrs>` based on the module spec.
If the argument *alter_sys* is supplied and evaluates to :const:`True`, If the argument *alter_sys* is supplied and evaluates to :const:`True`,
@ -98,6 +98,9 @@ The :mod:`runpy` module provides two functions:
``__package__`` are deprecated. See ``__package__`` are deprecated. See
:class:`~importlib.machinery.ModuleSpec` for alternatives. :class:`~importlib.machinery.ModuleSpec` for alternatives.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. function:: run_path(path_name, init_globals=None, run_name=None) .. function:: run_path(path_name, init_globals=None, run_name=None)
.. index:: .. index::
@ -125,23 +128,23 @@ The :mod:`runpy` module provides two functions:
overridden by :func:`run_path`. overridden by :func:`run_path`.
The special global variables ``__name__``, ``__spec__``, ``__file__``, The special global variables ``__name__``, ``__spec__``, ``__file__``,
``__cached__``, ``__loader__`` and ``__package__`` are set in the globals ``__loader__`` and ``__package__`` are set in the globals dictionary before
dictionary before the module code is executed. (Note that this is a the module code is executed. (Note that this is a minimal set of variables -
minimal set of variables - other variables may be set implicitly as an other variables may be set implicitly as an interpreter implementation
interpreter implementation detail.) detail.)
``__name__`` is set to *run_name* if this optional argument is not ``__name__`` is set to *run_name* if this optional argument is not
:const:`None` and to ``'<run_path>'`` otherwise. :const:`None` and to ``'<run_path>'`` otherwise.
If *file_path* directly references a script file (whether as source If *file_path* directly references a script file (whether as source
or as precompiled byte code), then ``__file__`` will be set to or as precompiled byte code), then ``__file__`` will be set to
*file_path*, and ``__spec__``, ``__cached__``, ``__loader__`` and *file_path*, and ``__spec__``, ``__loader__`` and
``__package__`` will all be set to :const:`None`. ``__package__`` will all be set to :const:`None`.
If *file_path* is a reference to a valid :data:`sys.path` entry, then If *file_path* is a reference to a valid :data:`sys.path` entry, then
``__spec__`` will be set appropriately for the imported :mod:`__main__` ``__spec__`` will be set appropriately for the imported :mod:`__main__`
module (that is, ``__spec__.name`` will always be ``__main__``). module (that is, ``__spec__.name`` will always be ``__main__``).
``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` will be ``__file__``, ``__loader__`` and ``__package__`` will be
:ref:`set as normal <import-mod-attrs>` based on the module spec. :ref:`set as normal <import-mod-attrs>` based on the module spec.
A number of alterations are also made to the :mod:`sys` module. Firstly, A number of alterations are also made to the :mod:`sys` module. Firstly,
@ -173,6 +176,9 @@ The :mod:`runpy` module provides two functions:
The setting of ``__cached__``, ``__loader__``, and The setting of ``__cached__``, ``__loader__``, and
``__package__`` are deprecated. ``__package__`` are deprecated.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
.. seealso:: .. seealso::
:pep:`338` -- Executing modules as scripts :pep:`338` -- Executing modules as scripts

View file

@ -895,7 +895,6 @@ Attribute assignment updates the module's namespace dictionary, e.g.,
single: __loader__ (module attribute) single: __loader__ (module attribute)
single: __path__ (module attribute) single: __path__ (module attribute)
single: __file__ (module attribute) single: __file__ (module attribute)
single: __cached__ (module attribute)
single: __doc__ (module attribute) single: __doc__ (module attribute)
single: __annotations__ (module attribute) single: __annotations__ (module attribute)
single: __annotate__ (module attribute) single: __annotate__ (module attribute)
@ -1044,43 +1043,28 @@ this approach.
instead of :attr:`!module.__path__`. instead of :attr:`!module.__path__`.
.. attribute:: module.__file__ .. attribute:: module.__file__
.. attribute:: module.__cached__
:attr:`!__file__` and :attr:`!__cached__` are both optional attributes that :attr:`!__file__` is an optional attribute that
may or may not be set. Both attributes should be a :class:`str` when they may or may not be set. Both attributes should be a :class:`str` when they
are available. are available.
:attr:`!__file__` indicates the pathname of the file from which the module An optional attribute, :attr:`!__file__` indicates the pathname of the file
was loaded (if loaded from a file), or the pathname of the shared library from which the module was loaded (if loaded from a file), or the pathname of
file for extension modules loaded dynamically from a shared library. the shared library file for extension modules loaded dynamically from a
It might be missing for certain types of modules, such as C modules that are shared library. It might be missing for certain types of modules, such as C
statically linked into the interpreter, and the modules that are statically linked into the interpreter, and the
:ref:`import system <importsystem>` may opt to leave it unset if it :ref:`import system <importsystem>` may opt to leave it unset if it
has no semantic meaning (for example, a module loaded from a database). has no semantic meaning (for example, a module loaded from a database).
If :attr:`!__file__` is set then the :attr:`!__cached__` attribute might
also be set, which is the path to any compiled version of
the code (for example, a byte-compiled file). The file does not need to exist
to set this attribute; the path can simply point to where the
compiled file *would* exist (see :pep:`3147`).
Note that :attr:`!__cached__` may be set even if :attr:`!__file__` is not
set. However, that scenario is quite atypical. Ultimately, the
:term:`loader` is what makes use of the module spec provided by the
:term:`finder` (from which :attr:`!__file__` and :attr:`!__cached__` are
derived). So if a loader can load from a cached module but otherwise does
not load from a file, that atypical scenario may be appropriate.
It is **strongly** recommended that you use
:attr:`module.__spec__.cached <importlib.machinery.ModuleSpec.cached>`
instead of :attr:`!module.__cached__`.
.. deprecated-removed:: 3.13 3.15 .. deprecated-removed:: 3.13 3.15
Setting :attr:`!__cached__` on a module while failing to set Setting ``__cached__`` on a module while failing to set
:attr:`!__spec__.cached` is deprecated. In Python 3.15, :attr:`!__spec__.cached` is deprecated. In Python 3.15,
:attr:`!__cached__` will cease to be set or taken into consideration by ``__cached__`` will cease to be set or taken into consideration by
the import system or standard library. the import system or standard library.
.. versionchanged:: 3.15
``__cached__`` is no longer set.
Other writable attributes on module objects Other writable attributes on module objects
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -1337,7 +1337,7 @@ Deprecated
it was :exc:`ImportWarning`). it was :exc:`ImportWarning`).
(Contributed by Brett Cannon in :gh:`65961`.) (Contributed by Brett Cannon in :gh:`65961`.)
* Setting :attr:`~module.__package__` or :attr:`~module.__cached__` on a * Setting :attr:`~module.__package__` or ``__cached__`` on a
module is deprecated, and will cease to be set or taken into consideration by module is deprecated, and will cease to be set or taken into consideration by
the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.) the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.)

View file

@ -312,7 +312,7 @@ cluttering source directories, the *pyc* files are now collected in a
Aside from the filenames and target directories, the new scheme has a few Aside from the filenames and target directories, the new scheme has a few
aspects that are visible to the programmer: aspects that are visible to the programmer:
* Imported modules now have a :attr:`~module.__cached__` attribute which stores * Imported modules now have a ``__cached__`` attribute which stores
the name of the actual file that was imported: the name of the actual file that was imported:
>>> import collections >>> import collections

View file

@ -583,8 +583,7 @@ class ModuleSpec:
`has_location` indicates that a spec's "origin" reflects a location. `has_location` indicates that a spec's "origin" reflects a location.
When this is True, `__file__` attribute of the module is set. When this is True, `__file__` attribute of the module is set.
`cached` is the location of the cached bytecode file, if any. It `cached` is the location of the cached bytecode file, if any.
corresponds to the `__cached__` attribute.
`submodule_search_locations` is the sequence of path entries to `submodule_search_locations` is the sequence of path entries to
search when importing submodules. If set, is_package should be search when importing submodules. If set, is_package should be
@ -717,10 +716,6 @@ def _spec_from_module(module, loader=None, origin=None):
origin = getattr(loader, '_ORIGIN', None) origin = getattr(loader, '_ORIGIN', None)
if not origin and location is not None: if not origin and location is not None:
origin = location origin = location
try:
cached = module.__cached__
except AttributeError:
cached = None
try: try:
submodule_search_locations = list(module.__path__) submodule_search_locations = list(module.__path__)
except AttributeError: except AttributeError:
@ -728,7 +723,7 @@ def _spec_from_module(module, loader=None, origin=None):
spec = ModuleSpec(name, loader, origin=origin) spec = ModuleSpec(name, loader, origin=origin)
spec._set_fileattr = False if location is None else (origin == location) spec._set_fileattr = False if location is None else (origin == location)
spec.cached = cached spec.cached = None
spec.submodule_search_locations = submodule_search_locations spec.submodule_search_locations = submodule_search_locations
return spec return spec
@ -789,7 +784,7 @@ def _init_module_attrs(spec, module, *, override=False):
module.__path__ = spec.submodule_search_locations module.__path__ = spec.submodule_search_locations
except AttributeError: except AttributeError:
pass pass
# __file__/__cached__ # __file__
if spec.has_location: if spec.has_location:
if override or getattr(module, '__file__', None) is None: if override or getattr(module, '__file__', None) is None:
try: try:
@ -797,12 +792,6 @@ def _init_module_attrs(spec, module, *, override=False):
except AttributeError: except AttributeError:
pass pass
if override or getattr(module, '__cached__', None) is None:
if spec.cached is not None:
try:
module.__cached__ = spec.cached
except AttributeError:
pass
return module return module

View file

@ -1543,7 +1543,6 @@ def _fix_up_module(ns, name, pathname, cpathname=None):
ns['__spec__'] = spec ns['__spec__'] = spec
ns['__loader__'] = loader ns['__loader__'] = loader
ns['__file__'] = pathname ns['__file__'] = pathname
ns['__cached__'] = cpathname
except Exception: except Exception:
# Not important enough to report. # Not important enough to report.
pass pass

View file

@ -3408,20 +3408,20 @@ def _main():
sys.exit(1) sys.exit(1)
if args.details: if args.details:
print('Target: {}'.format(target)) print(f'Target: {target}')
print('Origin: {}'.format(getsourcefile(module))) print(f'Origin: {getsourcefile(module)}')
print('Cached: {}'.format(module.__cached__)) print(f'Cached: {module.__spec__.cached}')
if obj is module: if obj is module:
print('Loader: {}'.format(repr(module.__loader__))) print(f'Loader: {module.__loader__!r}')
if hasattr(module, '__path__'): if hasattr(module, '__path__'):
print('Submodule search path: {}'.format(module.__path__)) print(f'Submodule search path: {module.__path__}')
else: else:
try: try:
__, lineno = findsource(obj) __, lineno = findsource(obj)
except Exception: except Exception:
pass pass
else: else:
print('Line: {}'.format(lineno)) print(f'Line: {lineno}')
print() print()
else: else:

View file

@ -607,7 +607,6 @@ def main():
'__file__': spec.origin, '__file__': spec.origin,
'__name__': spec.name, '__name__': spec.name,
'__package__': None, '__package__': None,
'__cached__': None,
} }
try: try:
runctx(code, globs, None, options.outfile, options.sort) runctx(code, globs, None, options.outfile, options.sort)

View file

@ -201,7 +201,6 @@ def main():
'__file__': spec.origin, '__file__': spec.origin,
'__name__': spec.name, '__name__': spec.name,
'__package__': None, '__package__': None,
'__cached__': None,
}) })
try: try:

View file

@ -241,12 +241,12 @@ def visiblename(name, all=None, obj=None):
"""Decide whether to show documentation on a variable.""" """Decide whether to show documentation on a variable."""
# Certain special names are redundant or internal. # Certain special names are redundant or internal.
# XXX Remove __initializing__? # XXX Remove __initializing__?
if name in {'__author__', '__builtins__', '__cached__', '__credits__', if name in {'__author__', '__builtins__', '__credits__', '__date__',
'__date__', '__doc__', '__file__', '__spec__', '__doc__', '__file__', '__spec__', '__loader__', '__module__',
'__loader__', '__module__', '__name__', '__package__', '__name__', '__package__', '__path__', '__qualname__',
'__path__', '__qualname__', '__slots__', '__version__', '__slots__', '__version__', '__static_attributes__',
'__static_attributes__', '__firstlineno__', '__firstlineno__', '__annotate_func__',
'__annotate_func__', '__annotations_cache__'}: '__annotations_cache__'}:
return 0 return 0
# Private names are hidden, but special names are displayed. # Private names are hidden, but special names are displayed.
if name.startswith('__') and name.endswith('__'): return 1 if name.startswith('__') and name.endswith('__'): return 1

View file

@ -80,7 +80,6 @@ def _run_code(code, run_globals, init_globals=None,
pkg_name = mod_spec.parent pkg_name = mod_spec.parent
run_globals.update(__name__ = mod_name, run_globals.update(__name__ = mod_name,
__file__ = fname, __file__ = fname,
__cached__ = cached,
__doc__ = None, __doc__ = None,
__loader__ = loader, __loader__ = loader,
__package__ = pkg_name, __package__ = pkg_name,
@ -180,7 +179,6 @@ def _run_module_as_main(mod_name, alter_argv=True):
At the very least, these variables in __main__ will be overwritten: At the very least, these variables in __main__ will be overwritten:
__name__ __name__
__file__ __file__
__cached__
__loader__ __loader__
__package__ __package__
""" """

View file

@ -111,7 +111,7 @@ def makepath(*paths):
def abs_paths(): def abs_paths():
"""Set all module __file__ and __cached__ attributes to an absolute path""" """Set __file__ to an absolute path."""
for m in set(sys.modules.values()): for m in set(sys.modules.values()):
loader_module = None loader_module = None
try: try:
@ -127,10 +127,6 @@ def abs_paths():
m.__file__ = os.path.abspath(m.__file__) m.__file__ = os.path.abspath(m.__file__)
except (AttributeError, OSError, TypeError): except (AttributeError, OSError, TypeError):
pass pass
try:
m.__cached__ = os.path.abspath(m.__cached__)
except (AttributeError, OSError, TypeError):
pass
def removeduppaths(): def removeduppaths():
@ -699,7 +695,7 @@ def main():
known_paths = removeduppaths() known_paths = removeduppaths()
if orig_path != sys.path: if orig_path != sys.path:
# removeduppaths() might make sys.path absolute. # removeduppaths() might make sys.path absolute.
# fix __file__ and __cached__ of already imported modules too. # Fix __file__ of already imported modules too.
abs_paths() abs_paths()
known_paths = venv(known_paths) known_paths = venv(known_paths)

View file

@ -44,7 +44,6 @@ def f():
_loader = __loader__ if __loader__ is BuiltinImporter else type(__loader__) _loader = __loader__ if __loader__ is BuiltinImporter else type(__loader__)
print('__loader__==%a' % _loader) print('__loader__==%a' % _loader)
print('__file__==%a' % __file__) print('__file__==%a' % __file__)
print('__cached__==%a' % __cached__)
print('__package__==%r' % __package__) print('__package__==%r' % __package__)
# Check PEP 451 details # Check PEP 451 details
import os.path import os.path
@ -58,8 +57,6 @@ def f():
assertEqual(__spec__.parent, __package__) assertEqual(__spec__.parent, __package__)
assertIdentical(__spec__.submodule_search_locations, None) assertIdentical(__spec__.submodule_search_locations, None)
assertEqual(__spec__.origin, __file__) assertEqual(__spec__.origin, __file__)
if __spec__.cached is not None:
assertEqual(__spec__.cached, __cached__)
# Check the sys module # Check the sys module
import sys import sys
assertIdentical(globals(), sys.modules[__name__].__dict__) assertIdentical(globals(), sys.modules[__name__].__dict__)

View file

@ -1699,78 +1699,6 @@ def test_missing_source_legacy(self):
finally: finally:
os.remove(pyc_file) os.remove(pyc_file)
def test___cached__(self):
# Modules now also have an __cached__ that points to the pyc file.
m = __import__(TESTFN)
pyc_file = importlib.util.cache_from_source(TESTFN + '.py')
self.assertEqual(m.__cached__, os.path.join(os.getcwd(), pyc_file))
@skip_if_dont_write_bytecode
def test___cached___legacy_pyc(self):
# Like test___cached__() except that for backward compatibility,
# when the pyc file lives where the py file would have been (and named
# without the tag), it is importable. The __cached__ of the imported
# module is the pyc location.
__import__(TESTFN)
# pyc_file gets removed in _clean() via tearDown().
pyc_file = make_legacy_pyc(self.source)
os.remove(self.source)
unload(TESTFN)
importlib.invalidate_caches()
m = __import__(TESTFN)
self.assertEqual(m.__cached__,
os.path.join(os.getcwd(), os.path.relpath(pyc_file)))
@skip_if_dont_write_bytecode
def test_package___cached__(self):
# Like test___cached__ but for packages.
def cleanup():
rmtree('pep3147')
unload('pep3147.foo')
unload('pep3147')
os.mkdir('pep3147')
self.addCleanup(cleanup)
# Touch the __init__.py
with open(os.path.join('pep3147', '__init__.py'), 'wb'):
pass
with open(os.path.join('pep3147', 'foo.py'), 'wb'):
pass
importlib.invalidate_caches()
m = __import__('pep3147.foo')
init_pyc = importlib.util.cache_from_source(
os.path.join('pep3147', '__init__.py'))
self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc))
foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
self.assertEqual(sys.modules['pep3147.foo'].__cached__,
os.path.join(os.getcwd(), foo_pyc))
def test_package___cached___from_pyc(self):
# Like test___cached__ but ensuring __cached__ when imported from a
# PEP 3147 pyc file.
def cleanup():
rmtree('pep3147')
unload('pep3147.foo')
unload('pep3147')
os.mkdir('pep3147')
self.addCleanup(cleanup)
# Touch the __init__.py
with open(os.path.join('pep3147', '__init__.py'), 'wb'):
pass
with open(os.path.join('pep3147', 'foo.py'), 'wb'):
pass
importlib.invalidate_caches()
m = __import__('pep3147.foo')
unload('pep3147.foo')
unload('pep3147')
importlib.invalidate_caches()
m = __import__('pep3147.foo')
init_pyc = importlib.util.cache_from_source(
os.path.join('pep3147', '__init__.py'))
self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc))
foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
self.assertEqual(sys.modules['pep3147.foo'].__cached__,
os.path.join(os.getcwd(), foo_pyc))
def test_recompute_pyc_same_second(self): def test_recompute_pyc_same_second(self):
# Even when the source file doesn't change timestamp, a change in # Even when the source file doesn't change timestamp, a change in
# source size is enough to trigger recomputation of the pyc file. # source size is enough to trigger recomputation of the pyc file.

View file

@ -1,9 +1,9 @@
import sys import sys
class MyMod(object): class MyMod(object):
__slots__ = ['__builtins__', '__cached__', '__doc__', __slots__ = ['__builtins__', '__doc__', '__file__',
'__file__', '__loader__', '__name__', '__loader__', '__name__', '__package__',
'__package__', '__path__', '__spec__'] '__path__', '__spec__']
def __init__(self): def __init__(self):
for attr in self.__slots__: for attr in self.__slots__:
setattr(self, attr, globals()[attr]) setattr(self, attr, globals()[attr])

View file

@ -19,8 +19,7 @@ def test_no_loader_but_spec(self):
ns = {"__spec__": spec} ns = {"__spec__": spec}
_bootstrap_external._fix_up_module(ns, name, path) _bootstrap_external._fix_up_module(ns, name, path)
expected = {"__spec__": spec, "__loader__": loader, "__file__": path, expected = {"__spec__": spec, "__loader__": loader, "__file__": path}
"__cached__": None}
self.assertEqual(ns, expected) self.assertEqual(ns, expected)
def test_no_loader_no_spec_but_sourceless(self): def test_no_loader_no_spec_but_sourceless(self):
@ -29,7 +28,7 @@ def test_no_loader_no_spec_but_sourceless(self):
ns = {} ns = {}
_bootstrap_external._fix_up_module(ns, name, path, path) _bootstrap_external._fix_up_module(ns, name, path, path)
expected = {"__file__": path, "__cached__": path} expected = {"__file__": path}
for key, val in expected.items(): for key, val in expected.items():
with self.subTest(f"{key}: {val}"): with self.subTest(f"{key}: {val}"):
@ -51,7 +50,7 @@ def test_no_loader_no_spec_but_source(self):
ns = {} ns = {}
_bootstrap_external._fix_up_module(ns, name, path) _bootstrap_external._fix_up_module(ns, name, path)
expected = {"__file__": path, "__cached__": None} expected = {"__file__": path}
for key, val in expected.items(): for key, val in expected.items():
with self.subTest(f"{key}: {val}"): with self.subTest(f"{key}: {val}"):

View file

@ -182,8 +182,6 @@ def test_file_from_empty_string_dir(self):
warnings.simplefilter('ignore', DeprecationWarning) warnings.simplefilter('ignore', DeprecationWarning)
mod = loader.load_module('_temp') mod = loader.load_module('_temp')
self.assertEqual(file_path, mod.__file__) self.assertEqual(file_path, mod.__file__)
self.assertEqual(self.util.cache_from_source(file_path),
mod.__cached__)
finally: finally:
os.unlink(file_path) os.unlink(file_path)
pycache = os.path.dirname(self.util.cache_from_source(file_path)) pycache = os.path.dirname(self.util.cache_from_source(file_path))
@ -219,8 +217,7 @@ def test_timestamp_overflow(self):
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning) warnings.simplefilter('ignore', DeprecationWarning)
mod = loader.load_module('_temp') mod = loader.load_module('_temp')
# Sanity checks. # Safety checks.
self.assertEqual(mod.__cached__, compiled)
self.assertEqual(mod.x, 5) self.assertEqual(mod.x, 5)
# The pyc file was created. # The pyc file was created.
self.assertTrue(os.path.exists(compiled)) self.assertTrue(os.path.exists(compiled))

View file

@ -599,8 +599,7 @@ def test_get_code_no_path(self):
class SourceOnlyLoader: class SourceOnlyLoader:
# Globals that should be defined for all modules. # Globals that should be defined for all modules.
source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " source = (b"_ = '::'.join([__name__, __file__, __package__, repr(__loader__)])")
b"repr(__loader__)])")
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
@ -675,20 +674,17 @@ def setUp(self, *, is_package=True, **kwargs):
def verify_module(self, module): def verify_module(self, module):
self.assertEqual(module.__name__, self.name) self.assertEqual(module.__name__, self.name)
self.assertEqual(module.__file__, self.path) self.assertEqual(module.__file__, self.path)
self.assertEqual(module.__cached__, self.cached)
self.assertEqual(module.__package__, self.package) self.assertEqual(module.__package__, self.package)
self.assertEqual(module.__loader__, self.loader) self.assertEqual(module.__loader__, self.loader)
values = module._.split('::') values = module._.split('::')
self.assertEqual(values[0], self.name) self.assertEqual(values[0], self.name)
self.assertEqual(values[1], self.path) self.assertEqual(values[1], self.path)
self.assertEqual(values[2], self.cached) self.assertEqual(values[2], self.package)
self.assertEqual(values[3], self.package) self.assertEqual(values[3], repr(self.loader))
self.assertEqual(values[4], repr(self.loader))
def verify_code(self, code_object): def verify_code(self, code_object):
module = types.ModuleType(self.name) module = types.ModuleType(self.name)
module.__file__ = self.path module.__file__ = self.path
module.__cached__ = self.cached
module.__package__ = self.package module.__package__ = self.package
module.__loader__ = self.loader module.__loader__ = self.loader
module.__path__ = [] module.__path__ = []
@ -731,7 +727,7 @@ def test_source_to_code(self):
def test_load_module(self): def test_load_module(self):
# Loading a module should set __name__, __loader__, __package__, # Loading a module should set __name__, __loader__, __package__,
# __path__ (for packages), __file__, and __cached__. # __path__ (for packages), and __file__.
# The module should also be put into sys.modules. # The module should also be put into sys.modules.
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("ignore", ImportWarning) warnings.simplefilter("ignore", ImportWarning)

View file

@ -235,7 +235,6 @@ def test_reload_location_changed(self):
expected = {'__name__': name, expected = {'__name__': name,
'__package__': '', '__package__': '',
'__file__': path, '__file__': path,
'__cached__': cached,
'__doc__': None, '__doc__': None,
} }
os_helper.create_empty_file(path) os_helper.create_empty_file(path)
@ -256,7 +255,6 @@ def test_reload_location_changed(self):
expected = {'__name__': name, expected = {'__name__': name,
'__package__': name, '__package__': name,
'__file__': init_path, '__file__': init_path,
'__cached__': cached,
'__path__': [os.path.dirname(init_path)], '__path__': [os.path.dirname(init_path)],
'__doc__': None, '__doc__': None,
} }
@ -316,7 +314,6 @@ def test_reload_namespace_changed(self):
expected = {'__name__': name, expected = {'__name__': name,
'__package__': name, '__package__': name,
'__file__': init_path, '__file__': init_path,
'__cached__': cached,
'__path__': [os.path.dirname(init_path)], '__path__': [os.path.dirname(init_path)],
'__doc__': None, '__doc__': None,
'eggs': None, 'eggs': None,

View file

@ -350,7 +350,6 @@ def test_reload_init_module_attrs(self):
self.assertIs(loaded.__spec__, self.spec) self.assertIs(loaded.__spec__, self.spec)
self.assertNotHasAttr(loaded, '__path__') self.assertNotHasAttr(loaded, '__path__')
self.assertNotHasAttr(loaded, '__file__') self.assertNotHasAttr(loaded, '__file__')
self.assertNotHasAttr(loaded, '__cached__')
(Frozen_ModuleSpecMethodsTests, (Frozen_ModuleSpecMethodsTests,

View file

@ -124,12 +124,6 @@ def test___file__(self):
module = self.util.module_from_spec(spec) module = self.util.module_from_spec(spec)
self.assertEqual(module.__file__, spec.origin) self.assertEqual(module.__file__, spec.origin)
def test___cached__(self):
spec = self.machinery.ModuleSpec('test', object())
spec.cached = 'some/path'
spec.has_location = True
module = self.util.module_from_spec(spec)
self.assertEqual(module.__cached__, spec.cached)
(Frozen_ModuleFromSpecTests, (Frozen_ModuleFromSpecTests,
Source_ModuleFromSpecTests Source_ModuleFromSpecTests

View file

@ -6494,13 +6494,12 @@ def test_details(self):
rc, out, err = assert_python_ok(*args, '-m', 'inspect', rc, out, err = assert_python_ok(*args, '-m', 'inspect',
'unittest', '--details') 'unittest', '--details')
output = out.decode() output = out.decode()
# Just a quick sanity check on the output # Just a quick safety check on the output
self.assertIn(module.__spec__.name, output) self.assertIn(module.__spec__.name, output)
self.assertIn(module.__name__, output) self.assertIn(module.__name__, output)
self.assertIn(module.__spec__.origin, output) self.assertIn(module.__spec__.origin, output)
self.assertIn(module.__file__, output) self.assertIn(module.__file__, output)
self.assertIn(module.__spec__.cached, output) self.assertIn(module.__spec__.cached, output)
self.assertIn(module.__cached__, output)
self.assertEqual(err, b'') self.assertEqual(err, b'')

View file

@ -198,15 +198,15 @@ def test_5(self):
import t5 import t5
self.assertEqual(fixdir(dir(t5)), self.assertEqual(fixdir(dir(t5)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__path__', '__spec__', '__package__', '__path__', '__spec__', 'foo',
'foo', 'string', 't5']) 'string', 't5'])
self.assertEqual(fixdir(dir(t5.foo)), self.assertEqual(fixdir(dir(t5.foo)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__spec__', 'string']) '__package__', '__spec__', 'string'])
self.assertEqual(fixdir(dir(t5.string)), self.assertEqual(fixdir(dir(t5.string)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__spec__', 'spam']) '__package__', '__spec__', 'spam'])
def test_6(self): def test_6(self):
hier = [ hier = [
@ -221,14 +221,13 @@ def test_6(self):
import t6 import t6
self.assertEqual(fixdir(dir(t6)), self.assertEqual(fixdir(dir(t6)),
['__all__', '__cached__', '__doc__', '__file__', ['__all__', '__doc__', '__file__', '__loader__',
'__loader__', '__name__', '__package__', '__path__', '__name__', '__package__', '__path__', '__spec__'])
'__spec__'])
s = """ s = """
import t6 import t6
from t6 import * from t6 import *
self.assertEqual(fixdir(dir(t6)), self.assertEqual(fixdir(dir(t6)),
['__all__', '__cached__', '__doc__', '__file__', ['__all__', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__loader__', '__name__', '__package__',
'__path__', '__spec__', 'eggs', 'ham', 'spam']) '__path__', '__spec__', 'eggs', 'ham', 'spam'])
self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6'])
@ -256,20 +255,19 @@ def test_7(self):
t7, sub, subsub = None, None, None t7, sub, subsub = None, None, None
import t7 as tas import t7 as tas
self.assertEqual(fixdir(dir(tas)), self.assertEqual(fixdir(dir(tas)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__path__', '__spec__']) '__package__', '__path__', '__spec__'])
self.assertFalse(t7) self.assertFalse(t7)
from t7 import sub as subpar from t7 import sub as subpar
self.assertEqual(fixdir(dir(subpar)), self.assertEqual(fixdir(dir(subpar)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__path__', '__spec__']) '__package__', '__path__', '__spec__'])
self.assertFalse(t7) self.assertFalse(t7)
self.assertFalse(sub) self.assertFalse(sub)
from t7.sub import subsub as subsubsub from t7.sub import subsub as subsubsub
self.assertEqual(fixdir(dir(subsubsub)), self.assertEqual(fixdir(dir(subsubsub)),
['__cached__', '__doc__', '__file__', '__loader__', ['__doc__', '__file__', '__loader__', '__name__',
'__name__', '__package__', '__path__', '__spec__', '__package__', '__path__', '__spec__', 'spam'])
'spam'])
self.assertFalse(t7) self.assertFalse(t7)
self.assertFalse(sub) self.assertFalse(sub)
self.assertFalse(subsub) self.assertFalse(subsub)

View file

@ -1443,10 +1443,10 @@ def test_exposed_globals_in_repl(self):
case2 = f"{pre}, '__doc__', '__file__', {post}" in output case2 = f"{pre}, '__doc__', '__file__', {post}" in output
# if `__main__` is a cached .pyc file and the .py source exists # if `__main__` is a cached .pyc file and the .py source exists
case3 = f"{pre}, '__cached__', '__doc__', '__file__', {post}" in output case3 = f"{pre}, '__doc__', '__file__', {post}" in output
# if `__main__` is a cached .pyc file but there's no .py source file # if `__main__` is a cached .pyc file but there's no .py source file
case4 = f"{pre}, '__cached__', '__doc__', {post}" in output case4 = f"{pre}, '__doc__', {post}" in output
self.assertTrue(case1 or case2 or case3 or case4, output) self.assertTrue(case1 or case2 or case3 or case4, output)

View file

@ -57,7 +57,6 @@ def f():
implicit_namespace = { implicit_namespace = {
"__name__": None, "__name__": None,
"__file__": None, "__file__": None,
"__cached__": None,
"__package__": None, "__package__": None,
"__doc__": None, "__doc__": None,
"__spec__": None "__spec__": None
@ -286,7 +285,6 @@ def _del_pkg(self, top):
def _fix_ns_for_legacy_pyc(self, ns, alter_sys): def _fix_ns_for_legacy_pyc(self, ns, alter_sys):
char_to_add = "c" char_to_add = "c"
ns["__file__"] += char_to_add ns["__file__"] += char_to_add
ns["__cached__"] = ns["__file__"]
spec = ns["__spec__"] spec = ns["__spec__"]
new_spec = importlib.util.spec_from_file_location(spec.name, new_spec = importlib.util.spec_from_file_location(spec.name,
ns["__file__"]) ns["__file__"])
@ -306,7 +304,6 @@ def _check_module(self, depth, alter_sys=False,
expected_ns.update({ expected_ns.update({
"__name__": mod_name, "__name__": mod_name,
"__file__": mod_fname, "__file__": mod_fname,
"__cached__": mod_spec.cached,
"__package__": mod_name.rpartition(".")[0], "__package__": mod_name.rpartition(".")[0],
"__spec__": mod_spec, "__spec__": mod_spec,
}) })
@ -347,7 +344,6 @@ def _check_package(self, depth, alter_sys=False,
expected_ns.update({ expected_ns.update({
"__name__": mod_name, "__name__": mod_name,
"__file__": mod_fname, "__file__": mod_fname,
"__cached__": importlib.util.cache_from_source(mod_fname),
"__package__": pkg_name, "__package__": pkg_name,
"__spec__": mod_spec, "__spec__": mod_spec,
}) })
@ -552,7 +548,6 @@ def test_run_name(self):
expected_ns.update({ expected_ns.update({
"__name__": run_name, "__name__": run_name,
"__file__": mod_fname, "__file__": mod_fname,
"__cached__": importlib.util.cache_from_source(mod_fname),
"__package__": mod_name.rpartition(".")[0], "__package__": mod_name.rpartition(".")[0],
"__spec__": mod_spec, "__spec__": mod_spec,
}) })
@ -632,7 +627,6 @@ def create_ns(init_globals):
expected_ns.update({ expected_ns.update({
"__name__": expected_name, "__name__": expected_name,
"__file__": expected_file, "__file__": expected_file,
"__cached__": mod_cached,
"__package__": "", "__package__": "",
"__spec__": mod_spec, "__spec__": mod_spec,
"run_argv0": expected_argv0, "run_argv0": expected_argv0,

View file

@ -466,17 +466,6 @@ def tearDown(self):
"""Restore sys.path""" """Restore sys.path"""
sys.path[:] = self.sys_path sys.path[:] = self.sys_path
def test_abs_paths_cached_None(self):
"""Test for __cached__ is None.
Regarding to PEP 3147, __cached__ can be None.
See also: https://bugs.python.org/issue30167
"""
sys.modules['test'].__cached__ = None
site.abs_paths()
self.assertIsNone(sys.modules['test'].__cached__)
def test_no_duplicate_paths(self): def test_no_duplicate_paths(self):
# No duplicate paths should exist in sys.path # No duplicate paths should exist in sys.path
# Handled by removeduppaths() # Handled by removeduppaths()

View file

@ -721,7 +721,6 @@ def parse_ignore_dir(s):
'__package__': mod_spec.parent, '__package__': mod_spec.parent,
'__loader__': mod_spec.loader, '__loader__': mod_spec.loader,
'__spec__': mod_spec, '__spec__': mod_spec,
'__cached__': None,
} }
else: else:
sys.argv = [opts.progname, *opts.arguments] sys.argv = [opts.progname, *opts.arguments]
@ -734,7 +733,6 @@ def parse_ignore_dir(s):
'__file__': opts.progname, '__file__': opts.progname,
'__name__': '__main__', '__name__': '__main__',
'__package__': None, '__package__': None,
'__cached__': None,
} }
t.runctx(code, globs, globs) t.runctx(code, globs, globs)
except OSError as err: except OSError as err:

View file

@ -0,0 +1 @@
Stop setting ``__cached__`` on modules.

View file

@ -478,9 +478,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit,
if (PyDict_SetItemString(dict, "__file__", filename) < 0) { if (PyDict_SetItemString(dict, "__file__", filename) < 0) {
goto done; goto done;
} }
if (PyDict_SetItemString(dict, "__cached__", Py_None) < 0) {
goto done;
}
set_file_name = 1; set_file_name = 1;
} }
@ -535,9 +532,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit,
if (PyDict_PopString(dict, "__file__", NULL) < 0) { if (PyDict_PopString(dict, "__file__", NULL) < 0) {
PyErr_Print(); PyErr_Print();
} }
if (PyDict_PopString(dict, "__cached__", NULL) < 0) {
PyErr_Print();
}
} }
Py_XDECREF(main_module); Py_XDECREF(main_module);
return ret; return ret;