diff --git a/Doc/c-api/import.rst b/Doc/c-api/import.rst index 1786ac6b503895..a28c0713dd3b2f 100644 --- a/Doc/c-api/import.rst +++ b/Doc/c-api/import.rst @@ -129,8 +129,7 @@ Importing Modules of :class:`~importlib.machinery.SourceFileLoader` otherwise. The module's :attr:`~module.__file__` attribute will be set to the code - object's :attr:`~codeobject.co_filename`. If applicable, - :attr:`~module.__cached__` will also be set. + object's :attr:`~codeobject.co_filename`. This function will reload the module if it was already imported. See :c:func:`PyImport_ReloadModule` for the intended way to reload a module. @@ -142,10 +141,13 @@ Importing Modules :c:func:`PyImport_ExecCodeModuleWithPathnames`. .. 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 alternatives. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + .. 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) - Like :c:func:`PyImport_ExecCodeModuleEx`, but the :attr:`~module.__cached__` - attribute of the module object is set to *cpathname* if it is - non-``NULL``. Of the three functions, this is the preferred one to use. + Like :c:func:`PyImport_ExecCodeModuleEx`, but the path to any compiled file + via *cpathname* is used appropriately when non-``NULL``. Of the three + functions, this is the preferred one to use. .. versionadded:: 3.3 .. versionchanged:: 3.12 - Setting :attr:`~module.__cached__` is deprecated. See + Setting ``__cached__`` is deprecated. See :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) diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index 09cbd6f01a0580..3b9cf892fe913d 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -3,9 +3,9 @@ Pending removal in Python 3.15 * The import system: - * Setting :attr:`~module.__cached__` on a module while + * Setting ``__cached__`` on a module while failing to set :attr:`__spec__.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`) * Setting :attr:`~module.__package__` on a module while diff --git a/Doc/howto/gdb_helpers.rst b/Doc/howto/gdb_helpers.rst index 98ce813ca4ab02..33d1fbf8cd9e9e 100644 --- a/Doc/howto/gdb_helpers.rst +++ b/Doc/howto/gdb_helpers.rst @@ -136,7 +136,7 @@ enabled:: at Objects/unicodeobject.c:551 #7 0x0000000000440d94 in PyUnicodeUCS2_FromString (u=0x5c2b8d "__lltrace__") at Objects/unicodeobject.c:569 #8 0x0000000000584abd in PyDict_GetItemString (v= - {'Yuck': , '__builtins__': , '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': , 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': , '__doc__': None}, key= + {'Yuck': , '__builtins__': , '__file__': 'Lib/test/crashers/nasty_eq_vs_dict.py', '__package__': None, 'y': , 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__name__': '__main__', 'z': , '__doc__': None}, key= 0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171 Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 8314fed80fa512..601745a75780fc 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -526,7 +526,7 @@ are always available. They are listed here in alphabetical order. >>> dir() # show the names in the module namespace # doctest: +SKIP ['__builtins__', '__name__', 'struct'] >>> 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__', '_clearcache', 'calcsize', 'error', 'pack', 'pack_into', 'unpack', 'unpack_from'] diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 3f0a54ac535cd6..7cc43c22e06cab 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -365,7 +365,6 @@ ABC hierarchy:: - :attr:`module.__name__` - :attr:`module.__file__` - - :attr:`module.__cached__` *(deprecated)* - :attr:`module.__path__` - :attr:`module.__package__` *(deprecated)* - :attr:`module.__loader__` *(deprecated)* @@ -1262,8 +1261,7 @@ find and load modules. .. attribute:: cached - The filename of a compiled version of the module's code - (see :attr:`module.__cached__`). + The filename of a compiled version of the module's code. The :term:`finder` should always set this attribute but it may be ``None`` for modules that do not need compiled code stored. diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index b07ec6e93f80ab..64735b5a109e66 100644 --- a/Doc/library/runpy.rst +++ b/Doc/library/runpy.rst @@ -50,10 +50,10 @@ The :mod:`runpy` module provides two functions: overridden by :func:`run_module`. The special global variables ``__name__``, ``__spec__``, ``__file__``, - ``__cached__``, ``__loader__`` and ``__package__`` are set in the globals - dictionary before the module code is executed. (Note that this is a - minimal set of variables - other variables may be set implicitly as an - interpreter implementation detail.) + ``__loader__`` and ``__package__`` are set in the globals dictionary before + the module code is executed. (Note that this is a minimal set of variables - + other variables may be set implicitly as an interpreter implementation + detail.) ``__name__`` is set to *run_name* if this optional argument is not :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 ``mod_name + '.__main__'``, never *run_name*). - ``__file__``, ``__cached__``, ``__loader__`` and ``__package__`` are + ``__file__``, ``__loader__`` and ``__package__`` are :ref:`set as normal ` based on the module spec. 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 :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) .. index:: @@ -125,23 +128,23 @@ The :mod:`runpy` module provides two functions: overridden by :func:`run_path`. The special global variables ``__name__``, ``__spec__``, ``__file__``, - ``__cached__``, ``__loader__`` and ``__package__`` are set in the globals - dictionary before the module code is executed. (Note that this is a - minimal set of variables - other variables may be set implicitly as an - interpreter implementation detail.) + ``__loader__`` and ``__package__`` are set in the globals dictionary before + the module code is executed. (Note that this is a minimal set of variables - + other variables may be set implicitly as an interpreter implementation + detail.) ``__name__`` is set to *run_name* if this optional argument is not :const:`None` and to ``''`` otherwise. If *file_path* directly references a script file (whether as source 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`. If *file_path* is a reference to a valid :data:`sys.path` entry, then ``__spec__`` will be set appropriately for the imported :mod:`__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 ` based on the module spec. 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 ``__package__`` are deprecated. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + .. seealso:: :pep:`338` -- Executing modules as scripts diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index ebadbc215a0eed..b6032a39980ce8 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -895,7 +895,6 @@ Attribute assignment updates the module's namespace dictionary, e.g., single: __loader__ (module attribute) single: __path__ (module attribute) single: __file__ (module attribute) - single: __cached__ (module attribute) single: __doc__ (module attribute) single: __annotations__ (module attribute) single: __annotate__ (module attribute) @@ -1044,43 +1043,28 @@ this approach. instead of :attr:`!module.__path__`. .. 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 are available. - :attr:`!__file__` indicates the pathname of the file from which the module - was loaded (if loaded from a file), or the pathname of the shared library - file for extension modules loaded dynamically from a shared library. - It might be missing for certain types of modules, such as C modules that are - statically linked into the interpreter, and the + An optional attribute, :attr:`!__file__` indicates the pathname of the file + from which the module was loaded (if loaded from a file), or the pathname of + the shared library file for extension modules loaded dynamically from a + shared library. It might be missing for certain types of modules, such as C + modules that are statically linked into the interpreter, and the :ref:`import system ` may opt to leave it unset if it 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 ` - instead of :attr:`!module.__cached__`. - .. 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:`!__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. + .. versionchanged:: 3.15 + ``__cached__`` is no longer set. + Other writable attributes on module objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 8badfe9a6b49b9..221956f3dd3819 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -1337,7 +1337,7 @@ Deprecated it was :exc:`ImportWarning`). (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 the import system in Python 3.14. (Contributed by Brett Cannon in :gh:`65961`.) diff --git a/Doc/whatsnew/3.2.rst b/Doc/whatsnew/3.2.rst index 47c4d9acbc870e..3b13d90f7692cd 100644 --- a/Doc/whatsnew/3.2.rst +++ b/Doc/whatsnew/3.2.rst @@ -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 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: >>> import collections diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 43c66765dd9779..962e69b7ceee1e 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -583,8 +583,7 @@ class ModuleSpec: `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. + `cached` is the location of the cached bytecode file, if any. `submodule_search_locations` is the sequence of path entries to 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) if not origin and location is not None: origin = location - try: - cached = module.__cached__ - except AttributeError: - cached = None try: submodule_search_locations = list(module.__path__) except AttributeError: @@ -728,7 +723,7 @@ def _spec_from_module(module, loader=None, origin=None): spec = ModuleSpec(name, loader, origin=origin) spec._set_fileattr = False if location is None else (origin == location) - spec.cached = cached + spec.cached = None spec.submodule_search_locations = submodule_search_locations return spec @@ -789,7 +784,7 @@ def _init_module_attrs(spec, module, *, override=False): module.__path__ = spec.submodule_search_locations except AttributeError: pass - # __file__/__cached__ + # __file__ if spec.has_location: if override or getattr(module, '__file__', None) is None: try: @@ -797,12 +792,6 @@ def _init_module_attrs(spec, module, *, override=False): except AttributeError: 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 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 2f9307cba4f086..37769447781fbc 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -1543,7 +1543,6 @@ def _fix_up_module(ns, name, pathname, cpathname=None): ns['__spec__'] = spec ns['__loader__'] = loader ns['__file__'] = pathname - ns['__cached__'] = cpathname except Exception: # Not important enough to report. pass diff --git a/Lib/inspect.py b/Lib/inspect.py index 8e7511b3af015f..7449acc9f96af6 100644 --- a/Lib/inspect.py +++ b/Lib/inspect.py @@ -3408,20 +3408,20 @@ def _main(): sys.exit(1) if args.details: - print('Target: {}'.format(target)) - print('Origin: {}'.format(getsourcefile(module))) - print('Cached: {}'.format(module.__cached__)) + print(f'Target: {target}') + print(f'Origin: {getsourcefile(module)}') + print(f'Cached: {module.__spec__.cached}') if obj is module: - print('Loader: {}'.format(repr(module.__loader__))) + print(f'Loader: {module.__loader__!r}') if hasattr(module, '__path__'): - print('Submodule search path: {}'.format(module.__path__)) + print(f'Submodule search path: {module.__path__}') else: try: __, lineno = findsource(obj) except Exception: pass else: - print('Line: {}'.format(lineno)) + print(f'Line: {lineno}') print() else: diff --git a/Lib/profile.py b/Lib/profile.py index 20c500d28bc5b9..304284da421163 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -607,7 +607,6 @@ def main(): '__file__': spec.origin, '__name__': spec.name, '__package__': None, - '__cached__': None, } try: runctx(code, globs, None, options.outfile, options.sort) diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index a6b8edf721611f..bd3cbf299aab3b 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -201,7 +201,6 @@ def main(): '__file__': spec.origin, '__name__': spec.name, '__package__': None, - '__cached__': None, }) try: diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 45ff5fca308c14..ee4457d9d3a932 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -241,12 +241,12 @@ def visiblename(name, all=None, obj=None): """Decide whether to show documentation on a variable.""" # Certain special names are redundant or internal. # XXX Remove __initializing__? - if name in {'__author__', '__builtins__', '__cached__', '__credits__', - '__date__', '__doc__', '__file__', '__spec__', - '__loader__', '__module__', '__name__', '__package__', - '__path__', '__qualname__', '__slots__', '__version__', - '__static_attributes__', '__firstlineno__', - '__annotate_func__', '__annotations_cache__'}: + if name in {'__author__', '__builtins__', '__credits__', '__date__', + '__doc__', '__file__', '__spec__', '__loader__', '__module__', + '__name__', '__package__', '__path__', '__qualname__', + '__slots__', '__version__', '__static_attributes__', + '__firstlineno__', '__annotate_func__', + '__annotations_cache__'}: return 0 # Private names are hidden, but special names are displayed. if name.startswith('__') and name.endswith('__'): return 1 diff --git a/Lib/runpy.py b/Lib/runpy.py index f072498f6cb405..9f62d20e9a2322 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -80,7 +80,6 @@ def _run_code(code, run_globals, init_globals=None, pkg_name = mod_spec.parent run_globals.update(__name__ = mod_name, __file__ = fname, - __cached__ = cached, __doc__ = None, __loader__ = loader, __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: __name__ __file__ - __cached__ __loader__ __package__ """ diff --git a/Lib/site.py b/Lib/site.py index 7c6810792cfa7e..1b7a656551b853 100644 --- a/Lib/site.py +++ b/Lib/site.py @@ -111,7 +111,7 @@ def makepath(*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()): loader_module = None try: @@ -127,10 +127,6 @@ def abs_paths(): m.__file__ = os.path.abspath(m.__file__) except (AttributeError, OSError, TypeError): pass - try: - m.__cached__ = os.path.abspath(m.__cached__) - except (AttributeError, OSError, TypeError): - pass def removeduppaths(): @@ -699,7 +695,7 @@ def main(): known_paths = removeduppaths() if orig_path != sys.path: # removeduppaths() might make sys.path absolute. - # fix __file__ and __cached__ of already imported modules too. + # Fix __file__ of already imported modules too. abs_paths() known_paths = venv(known_paths) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index cc1a625a5097d8..8695df9eb0c294 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -44,7 +44,6 @@ def f(): _loader = __loader__ if __loader__ is BuiltinImporter else type(__loader__) print('__loader__==%a' % _loader) print('__file__==%a' % __file__) -print('__cached__==%a' % __cached__) print('__package__==%r' % __package__) # Check PEP 451 details import os.path @@ -58,8 +57,6 @@ def f(): assertEqual(__spec__.parent, __package__) assertIdentical(__spec__.submodule_search_locations, None) assertEqual(__spec__.origin, __file__) - if __spec__.cached is not None: - assertEqual(__spec__.cached, __cached__) # Check the sys module import sys assertIdentical(globals(), sys.modules[__name__].__dict__) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 271361ae816449..62a5d8514698f0 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1699,78 +1699,6 @@ def test_missing_source_legacy(self): finally: 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): # Even when the source file doesn't change timestamp, a change in # source size is enough to trigger recomputation of the pyc file. diff --git a/Lib/test/test_import/data/unwritable/__init__.py b/Lib/test/test_import/data/unwritable/__init__.py index da4ddb3d027c34..1d61ff348d8d15 100644 --- a/Lib/test/test_import/data/unwritable/__init__.py +++ b/Lib/test/test_import/data/unwritable/__init__.py @@ -1,9 +1,9 @@ import sys class MyMod(object): - __slots__ = ['__builtins__', '__cached__', '__doc__', - '__file__', '__loader__', '__name__', - '__package__', '__path__', '__spec__'] + __slots__ = ['__builtins__', '__doc__', '__file__', + '__loader__', '__name__', '__package__', + '__path__', '__spec__'] def __init__(self): for attr in self.__slots__: setattr(self, attr, globals()[attr]) diff --git a/Lib/test/test_importlib/import_/test_helpers.py b/Lib/test/test_importlib/import_/test_helpers.py index 550f88d1d7a651..7587276a41e953 100644 --- a/Lib/test/test_importlib/import_/test_helpers.py +++ b/Lib/test/test_importlib/import_/test_helpers.py @@ -19,8 +19,7 @@ def test_no_loader_but_spec(self): ns = {"__spec__": spec} _bootstrap_external._fix_up_module(ns, name, path) - expected = {"__spec__": spec, "__loader__": loader, "__file__": path, - "__cached__": None} + expected = {"__spec__": spec, "__loader__": loader, "__file__": path} self.assertEqual(ns, expected) def test_no_loader_no_spec_but_sourceless(self): @@ -29,7 +28,7 @@ def test_no_loader_no_spec_but_sourceless(self): ns = {} _bootstrap_external._fix_up_module(ns, name, path, path) - expected = {"__file__": path, "__cached__": path} + expected = {"__file__": path} for key, val in expected.items(): with self.subTest(f"{key}: {val}"): @@ -51,7 +50,7 @@ def test_no_loader_no_spec_but_source(self): ns = {} _bootstrap_external._fix_up_module(ns, name, path) - expected = {"__file__": path, "__cached__": None} + expected = {"__file__": path} for key, val in expected.items(): with self.subTest(f"{key}: {val}"): diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py index f35adec1a8e800..23c73e674748f7 100644 --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -182,8 +182,6 @@ def test_file_from_empty_string_dir(self): warnings.simplefilter('ignore', DeprecationWarning) mod = loader.load_module('_temp') self.assertEqual(file_path, mod.__file__) - self.assertEqual(self.util.cache_from_source(file_path), - mod.__cached__) finally: os.unlink(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(): warnings.simplefilter('ignore', DeprecationWarning) mod = loader.load_module('_temp') - # Sanity checks. - self.assertEqual(mod.__cached__, compiled) + # Safety checks. self.assertEqual(mod.x, 5) # The pyc file was created. self.assertTrue(os.path.exists(compiled)) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index bd1540ce403ce2..46cf8d40888bba 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -599,8 +599,7 @@ def test_get_code_no_path(self): class SourceOnlyLoader: # Globals that should be defined for all modules. - source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " - b"repr(__loader__)])") + source = (b"_ = '::'.join([__name__, __file__, __package__, repr(__loader__)])") def __init__(self, path): self.path = path @@ -675,20 +674,17 @@ def setUp(self, *, is_package=True, **kwargs): def verify_module(self, module): self.assertEqual(module.__name__, self.name) self.assertEqual(module.__file__, self.path) - self.assertEqual(module.__cached__, self.cached) self.assertEqual(module.__package__, self.package) self.assertEqual(module.__loader__, self.loader) values = module._.split('::') self.assertEqual(values[0], self.name) self.assertEqual(values[1], self.path) - self.assertEqual(values[2], self.cached) - self.assertEqual(values[3], self.package) - self.assertEqual(values[4], repr(self.loader)) + self.assertEqual(values[2], self.package) + self.assertEqual(values[3], repr(self.loader)) def verify_code(self, code_object): module = types.ModuleType(self.name) module.__file__ = self.path - module.__cached__ = self.cached module.__package__ = self.package module.__loader__ = self.loader module.__path__ = [] @@ -731,7 +727,7 @@ def test_source_to_code(self): def test_load_module(self): # 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. with warnings.catch_warnings(): warnings.simplefilter("ignore", ImportWarning) diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 1bc531a2fe34e7..4de0cf029a81e0 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -235,7 +235,6 @@ def test_reload_location_changed(self): expected = {'__name__': name, '__package__': '', '__file__': path, - '__cached__': cached, '__doc__': None, } os_helper.create_empty_file(path) @@ -256,7 +255,6 @@ def test_reload_location_changed(self): expected = {'__name__': name, '__package__': name, '__file__': init_path, - '__cached__': cached, '__path__': [os.path.dirname(init_path)], '__doc__': None, } @@ -316,7 +314,6 @@ def test_reload_namespace_changed(self): expected = {'__name__': name, '__package__': name, '__file__': init_path, - '__cached__': cached, '__path__': [os.path.dirname(init_path)], '__doc__': None, 'eggs': None, diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index aebeabaf83f75d..9e5d3ce5d2ea4d 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -350,7 +350,6 @@ def test_reload_init_module_attrs(self): self.assertIs(loaded.__spec__, self.spec) self.assertNotHasAttr(loaded, '__path__') self.assertNotHasAttr(loaded, '__file__') - self.assertNotHasAttr(loaded, '__cached__') (Frozen_ModuleSpecMethodsTests, diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index 0adab8d14e0452..f19a49973664c7 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -124,12 +124,6 @@ def test___file__(self): module = self.util.module_from_spec(spec) 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, Source_ModuleFromSpecTests diff --git a/Lib/test/test_inspect/test_inspect.py b/Lib/test/test_inspect/test_inspect.py index dd3b7d9c5b4b5b..075e1802bebc3e 100644 --- a/Lib/test/test_inspect/test_inspect.py +++ b/Lib/test/test_inspect/test_inspect.py @@ -6494,13 +6494,12 @@ def test_details(self): rc, out, err = assert_python_ok(*args, '-m', 'inspect', 'unittest', '--details') 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.__name__, output) self.assertIn(module.__spec__.origin, output) self.assertIn(module.__file__, output) self.assertIn(module.__spec__.cached, output) - self.assertIn(module.__cached__, output) self.assertEqual(err, b'') diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index d2b724db40d3e9..0a366e2a5bb2d1 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -198,15 +198,15 @@ def test_5(self): import t5 self.assertEqual(fixdir(dir(t5)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__', - 'foo', 'string', 't5']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__', 'foo', + 'string', 't5']) self.assertEqual(fixdir(dir(t5.foo)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'string']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__spec__', 'string']) self.assertEqual(fixdir(dir(t5.string)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'spam']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__spec__', 'spam']) def test_6(self): hier = [ @@ -221,14 +221,13 @@ def test_6(self): import t6 self.assertEqual(fixdir(dir(t6)), - ['__all__', '__cached__', '__doc__', '__file__', - '__loader__', '__name__', '__package__', '__path__', - '__spec__']) + ['__all__', '__doc__', '__file__', '__loader__', + '__name__', '__package__', '__path__', '__spec__']) s = """ import t6 from t6 import * self.assertEqual(fixdir(dir(t6)), - ['__all__', '__cached__', '__doc__', '__file__', + ['__all__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'eggs', 'ham', 'spam']) self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) @@ -256,20 +255,19 @@ def test_7(self): t7, sub, subsub = None, None, None import t7 as tas self.assertEqual(fixdir(dir(tas)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__']) self.assertFalse(t7) from t7 import sub as subpar self.assertEqual(fixdir(dir(subpar)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__']) self.assertFalse(t7) self.assertFalse(sub) from t7.sub import subsub as subsubsub self.assertEqual(fixdir(dir(subsubsub)), - ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__', - 'spam']) + ['__doc__', '__file__', '__loader__', '__name__', + '__package__', '__path__', '__spec__', 'spam']) self.assertFalse(t7) self.assertFalse(sub) self.assertFalse(subsub) diff --git a/Lib/test/test_pyrepl/test_pyrepl.py b/Lib/test/test_pyrepl/test_pyrepl.py index e298b2add52c3e..ddcaafc9b7dbe8 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -1443,10 +1443,10 @@ def test_exposed_globals_in_repl(self): case2 = f"{pre}, '__doc__', '__file__', {post}" in output # 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 - 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) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index cc76b72b9639eb..254a009a69718b 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -57,7 +57,6 @@ def f(): implicit_namespace = { "__name__": None, "__file__": None, - "__cached__": None, "__package__": None, "__doc__": None, "__spec__": None @@ -286,7 +285,6 @@ def _del_pkg(self, top): def _fix_ns_for_legacy_pyc(self, ns, alter_sys): char_to_add = "c" ns["__file__"] += char_to_add - ns["__cached__"] = ns["__file__"] spec = ns["__spec__"] new_spec = importlib.util.spec_from_file_location(spec.name, ns["__file__"]) @@ -306,7 +304,6 @@ def _check_module(self, depth, alter_sys=False, expected_ns.update({ "__name__": mod_name, "__file__": mod_fname, - "__cached__": mod_spec.cached, "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) @@ -347,7 +344,6 @@ def _check_package(self, depth, alter_sys=False, expected_ns.update({ "__name__": mod_name, "__file__": mod_fname, - "__cached__": importlib.util.cache_from_source(mod_fname), "__package__": pkg_name, "__spec__": mod_spec, }) @@ -552,7 +548,6 @@ def test_run_name(self): expected_ns.update({ "__name__": run_name, "__file__": mod_fname, - "__cached__": importlib.util.cache_from_source(mod_fname), "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) @@ -632,7 +627,6 @@ def create_ns(init_globals): expected_ns.update({ "__name__": expected_name, "__file__": expected_file, - "__cached__": mod_cached, "__package__": "", "__spec__": mod_spec, "run_argv0": expected_argv0, diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index 27ae3539b554ef..e7dc5e2611c2de 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -466,17 +466,6 @@ def tearDown(self): """Restore 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): # No duplicate paths should exist in sys.path # Handled by removeduppaths() diff --git a/Lib/trace.py b/Lib/trace.py index cf8817f4383fc1..cd3a6d30661da3 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -721,7 +721,6 @@ def parse_ignore_dir(s): '__package__': mod_spec.parent, '__loader__': mod_spec.loader, '__spec__': mod_spec, - '__cached__': None, } else: sys.argv = [opts.progname, *opts.arguments] @@ -734,7 +733,6 @@ def parse_ignore_dir(s): '__file__': opts.progname, '__name__': '__main__', '__package__': None, - '__cached__': None, } t.runctx(code, globs, globs) except OSError as err: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-15-22-54.gh-issue-65961.hCJvRB.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-15-22-54.gh-issue-65961.hCJvRB.rst new file mode 100644 index 00000000000000..59ab00ac8321f6 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-01-15-22-54.gh-issue-65961.hCJvRB.rst @@ -0,0 +1 @@ +Stop setting ``__cached__`` on modules. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 272be504a68fa1..f2c402eb1a03b5 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -478,9 +478,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, if (PyDict_SetItemString(dict, "__file__", filename) < 0) { goto done; } - if (PyDict_SetItemString(dict, "__cached__", Py_None) < 0) { - goto done; - } set_file_name = 1; } @@ -535,9 +532,6 @@ _PyRun_SimpleFileObject(FILE *fp, PyObject *filename, int closeit, if (PyDict_PopString(dict, "__file__", NULL) < 0) { PyErr_Print(); } - if (PyDict_PopString(dict, "__cached__", NULL) < 0) { - PyErr_Print(); - } } Py_XDECREF(main_module); return ret;