diff --git a/Doc/c-api/extension-modules.rst b/Doc/c-api/extension-modules.rst index 0ce173b4bfea7c..4259defe05fdad 100644 --- a/Doc/c-api/extension-modules.rst +++ b/Doc/c-api/extension-modules.rst @@ -134,9 +134,8 @@ The process of creating an extension module follows several phases: - By default, Python itself then creates the module object -- that is, it does the equivalent of calling :py:meth:`~object.__new__` when creating an object. This step can be overridden using the :c:data:`Py_mod_create` slot. -- Python sets initial module attributes like :attr:`~module.__package__` and - :attr:`~module.__loader__`, and inserts the module object into - :py:attr:`sys.modules`. +- Python sets initial module attributes like :attr:`~module.__spec__`, and + inserts the module object into :py:attr:`sys.modules`. - Afterwards, the module object is initialized in an extension-specific way -- the equivalent of :py:meth:`~object.__init__` when creating an object, or of executing top-level code in a Python-language module. diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst index a12f6331c85912..75fc91d156e22d 100644 --- a/Doc/c-api/module.rst +++ b/Doc/c-api/module.rst @@ -33,14 +33,13 @@ Module Objects single: __name__ (module attribute) single: __doc__ (module attribute) single: __file__ (module attribute) - single: __package__ (module attribute) single: __loader__ (module attribute) Return a new module object with :attr:`module.__name__` set to *name*. - The module's :attr:`!__name__`, :attr:`~module.__doc__`, - :attr:`~module.__package__` and :attr:`~module.__loader__` attributes are - filled in (all but :attr:`!__name__` are set to ``None``). The caller is - responsible for setting a :attr:`~module.__file__` attribute. + The module's :attr:`!__name__`, :attr:`~module.__doc__`, and + :attr:`~module.__loader__` attributes are filled in (all but + :attr:`!__name__` are set to ``None``). The caller is responsible for + setting a :attr:`~module.__file__` attribute. Return ``NULL`` with an exception set on error. @@ -50,6 +49,9 @@ Module Objects :attr:`~module.__package__` and :attr:`~module.__loader__` are now set to ``None``. + .. versionchanged:: 3.15 + :attr:`~module.__package__` is no longer set. + .. c:function:: PyObject* PyModule_New(const char *name) diff --git a/Doc/deprecations/pending-removal-in-3.15.rst b/Doc/deprecations/pending-removal-in-3.15.rst index 09cbd6f01a0580..99ad5f35402512 100644 --- a/Doc/deprecations/pending-removal-in-3.15.rst +++ b/Doc/deprecations/pending-removal-in-3.15.rst @@ -10,8 +10,8 @@ Pending removal in Python 3.15 * Setting :attr:`~module.__package__` on a module while failing to set :attr:`__spec__.parent ` - is deprecated. In Python 3.15, :attr:`!__package__` will cease to be set or - take into consideration by the import system or standard library. (:gh:`97879`) + is deprecated. In Python 3.15, :attr:`!__package__` will cease to be set by + the import system or standard library. (:gh:`97879`) * :mod:`ctypes`: diff --git a/Doc/howto/gdb_helpers.rst b/Doc/howto/gdb_helpers.rst index 98ce813ca4ab02..968285f8fe038a 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', 'y': , 'dict': {0: 0, 1: 1, 2: 2, 3: 3}, '__cached__': None, '__name__': '__main__', 'z': , '__doc__': None}, key= 0x5c2b8d "__lltrace__") at Objects/dictobject.c:2171 Notice how the dictionary argument to ``PyDict_GetItemString`` is displayed @@ -148,8 +148,7 @@ cast the value to a pointer of the appropriate type. For example:: (gdb) p globals $1 = {'__builtins__': , '__name__': - '__main__', 'ctypes': , '__doc__': None, - '__package__': None} + '__main__', 'ctypes': , '__doc__': None} (gdb) p *(PyDictObject*)globals $2 = {ob_refcnt = 3, ob_type = 0x3dbdf85820, ma_fill = 5, ma_used = 5, @@ -162,8 +161,7 @@ cast the value to a pointer of the appropriate type. For example:: {me_hash = -9177857982131165996, me_key = 'ctypes', me_value = }, {me_hash = -8518757509529533123, me_key = '__doc__', me_value = None}, - {me_hash = 0, me_key = 0x0, me_value = 0x0}, { - me_hash = 6614918939584953775, me_key = '__package__', me_value = None}}} + {me_hash = 0, me_key = 0x0, me_value = 0x0}}} Note that the pretty-printers do not actually call ``repr()``. For basic types, they try to match its result closely. diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 3f0a54ac535cd6..d7f396a4a1c6b8 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -367,7 +367,6 @@ ABC hierarchy:: - :attr:`module.__file__` - :attr:`module.__cached__` *(deprecated)* - :attr:`module.__path__` - - :attr:`module.__package__` *(deprecated)* - :attr:`module.__loader__` *(deprecated)* When :meth:`exec_module` is available then backwards-compatible @@ -1271,7 +1270,8 @@ find and load modules. (Read-only) The fully qualified name of the package the module is in (or the empty string for a top-level module). - See :attr:`module.__package__`. + See :attr:`module.__package__` for an optional way to override using + this attribute by the import system. If the module is a package then this is the same as :attr:`name`. .. attribute:: has_location diff --git a/Doc/library/runpy.rst b/Doc/library/runpy.rst index b07ec6e93f80ab..a9da6e444ef6cd 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.) + ``__cached__``, and ``__loader__`` 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__``, ``__cached__``, and ``__loader__`` 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 + ``__package__`` 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.) + ``__cached__``, and ``__loader__`` 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 - ``__package__`` will all be set to :const:`None`. + *file_path*, and ``__spec__``, ``__cached__``, and ``__loader__`` 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__``, ``__cached__``, and ``__loader__`` 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 + ``__package__`` 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..eeb20cae4ba5ca 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -960,7 +960,7 @@ this approach. .. attribute:: module.__package__ - The :term:`package` a module belongs to. + An optional attribute that states what :term:`package` a module belongs to. If the module is top-level (that is, not a part of any specific package) then the attribute should be set to ``''`` (the empty string). Otherwise, @@ -968,17 +968,13 @@ this approach. :attr:`module.__name__` if the module itself is a package). See :pep:`366` for further details. - This attribute is used instead of :attr:`~module.__name__` to calculate - explicit relative imports for main modules. It defaults to ``None`` for - modules created dynamically using the :class:`types.ModuleType` constructor; - use :func:`importlib.util.module_from_spec` instead to ensure the attribute - is set to a :class:`str`. + When set, this attribute is used instead of :attr:`~module.__spec__` or + :attr:`~module.__name__` to calculate explicit relative imports for main + modules. It is **strongly** recommended that you use :attr:`module.__spec__.parent ` - instead of :attr:`!module.__package__`. :attr:`__package__` is now only used - as a fallback if :attr:`!__spec__.parent` is not set, and this fallback - path is deprecated. + instead of :attr:`!module.__package__`. .. versionchanged:: 3.4 This attribute now defaults to ``None`` for modules created dynamically @@ -1001,8 +997,7 @@ this approach. falling back to :attr:`!__package__` during import resolution. .. deprecated-removed:: 3.13 3.15 - :attr:`!__package__` will cease to be set or taken into consideration - by the import system or standard library. + :attr:`!__package__` is no longer set implicitly. .. attribute:: module.__loader__ diff --git a/Doc/tutorial/inputoutput.rst b/Doc/tutorial/inputoutput.rst index a00f06cf46c41a..a70bffd77fbdfd 100644 --- a/Doc/tutorial/inputoutput.rst +++ b/Doc/tutorial/inputoutput.rst @@ -217,7 +217,7 @@ This is particularly useful in combination with the built-in function >>> table = {k: str(v) for k, v in vars().items()} >>> message = " ".join([f'{k}: ' + '{' + k +'};' for k in table.keys()]) >>> print(message.format(**table)) - __name__: __main__; __doc__: None; __package__: None; __loader__: ... + __name__: __main__; __doc__: None; __loader__: ... As an example, the following lines produce a tidily aligned set of columns giving integers and their squares and cubes:: diff --git a/Doc/tutorial/modules.rst b/Doc/tutorial/modules.rst index f8105cd5441fec..3a617d260fe6de 100644 --- a/Doc/tutorial/modules.rst +++ b/Doc/tutorial/modules.rst @@ -316,7 +316,7 @@ defines. It returns a sorted list of strings:: ['__name__', 'fib', 'fib2'] >>> dir(sys) # doctest: +NORMALIZE_WHITESPACE ['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__', - '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__', + '__interactivehook__', '__loader__', '__name__', '__spec__', '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__', '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework', '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook', @@ -373,7 +373,7 @@ want a list of those, they are defined in the standard module 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__', - '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', + '__debug__', '__doc__', '__import__', '__name__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', diff --git a/Lib/_pyrepl/_module_completer.py b/Lib/_pyrepl/_module_completer.py index cf59e007f4df80..41188fb1a508b5 100644 --- a/Lib/_pyrepl/_module_completer.py +++ b/Lib/_pyrepl/_module_completer.py @@ -29,8 +29,7 @@ def make_default_module_completer() -> ModuleCompleter: - # Inside pyrepl, __package__ is set to None by default - return ModuleCompleter(namespace={'__package__': None}) + return ModuleCompleter() class ModuleCompleter: @@ -102,7 +101,9 @@ def _find_modules(self, path: str, prefix: str) -> list[str]: if path.startswith('.'): # Convert relative path to absolute path - package = self.namespace.get('__package__', '') + if not (package := self.namespace.get('__package__', '')): + if spec := self.namespace.get('__spec__'): + package = spec.parent or '' path = self.resolve_relative_name(path, package) # type: ignore[assignment] if path is None: return [] diff --git a/Lib/asyncio/__main__.py b/Lib/asyncio/__main__.py index d078ebfa4cedbe..e6c20deb1bceb8 100644 --- a/Lib/asyncio/__main__.py +++ b/Lib/asyncio/__main__.py @@ -191,7 +191,7 @@ def interrupt(self) -> None: asyncio.set_event_loop(loop) repl_locals = {'asyncio': asyncio} - for key in {'__name__', '__package__', + for key in {'__name__', '__loader__', '__spec__', '__builtins__', '__file__'}: repl_locals[key] = locals()[key] diff --git a/Lib/asyncio/log.py b/Lib/asyncio/log.py index 23a7074afb0a53..79524a795318d5 100644 --- a/Lib/asyncio/log.py +++ b/Lib/asyncio/log.py @@ -4,4 +4,4 @@ # Name the logger after the package. -logger = logging.getLogger(__package__) +logger = logging.getLogger(__spec__.parent) diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py index 83112d85575e47..8b4641b5086f02 100644 --- a/Lib/idlelib/editor.py +++ b/Lib/idlelib/editor.py @@ -1154,7 +1154,7 @@ def load_extension(self, name): fname = self.extfiles.get(name, name) try: try: - mod = importlib.import_module('.' + fname, package=__package__) + mod = importlib.import_module('.' + fname, package=__spec__.parent) except (ImportError, TypeError): mod = importlib.import_module(fname) except ImportError: diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index a7d57561ead046..45d02204e4675d 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -21,7 +21,6 @@ # importlib._bootstrap is the built-in import, ensure we don't create # a second copy of the module. _bootstrap.__name__ = 'importlib._bootstrap' - _bootstrap.__package__ = 'importlib' try: _bootstrap.__file__ = __file__.replace('__init__.py', '_bootstrap.py') except NameError: @@ -38,7 +37,6 @@ _bootstrap._bootstrap_external = _bootstrap_external else: _bootstrap_external.__name__ = 'importlib._bootstrap_external' - _bootstrap_external.__package__ = 'importlib' try: _bootstrap_external.__file__ = __file__.replace('__init__.py', '_bootstrap_external.py') except NameError: diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 43c66765dd9779..3c976b723555b5 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -770,12 +770,6 @@ def _init_module_attrs(spec, module, *, override=False): module.__loader__ = loader except AttributeError: pass - # __package__ - if override or getattr(module, '__package__', None) is None: - try: - module.__package__ = spec.parent - except AttributeError: - pass # __spec__ try: module.__spec__ = spec @@ -894,16 +888,6 @@ def _load_backward_compatible(spec): module.__loader__ = spec.loader except AttributeError: pass - if getattr(module, '__package__', None) is None: - try: - # Since module.__path__ may not line up with - # spec.submodule_search_paths, we can't necessarily rely - # on spec.parent here. - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = spec.name.rpartition('.')[0] - except AttributeError: - pass if getattr(module, '__spec__', None) is None: try: module.__spec__ = spec @@ -1295,7 +1279,7 @@ def _sanity_check(name, package, level): raise ValueError('level must be >= 0') if level > 0: if not isinstance(package, str): - raise TypeError('__package__ not set to a string') + raise TypeError('__package__ or __spec__.parent not set to a string') elif not package: raise ImportError('attempted relative import with no known parent ' 'package') @@ -1396,8 +1380,7 @@ def _gcd_import(name, package=None, level=0): being made from, and the level adjustment. This function represents the greatest common denominator of functionality - between import_module and __import__. This includes setting __package__ if - the loader did not. + between import_module and __import__. """ _sanity_check(name, package, level) @@ -1443,20 +1426,11 @@ def _handle_fromlist(module, fromlist, import_, *, recursive=False): return module -def _calc___package__(globals): - """Calculate what __package__ should be. - - __package__ is not guaranteed to be defined or could be set to None - to represent that its proper value is unknown. - - """ +def _calc_package(globals): + """Calculate what the containing package is.""" package = globals.get('__package__') spec = globals.get('__spec__') if package is not None: - if spec is not None and package != spec.parent: - _warnings.warn("__package__ != __spec__.parent " - f"({package!r} != {spec.parent!r})", - DeprecationWarning, stacklevel=3) return package elif spec is not None: return spec.parent @@ -1485,7 +1459,7 @@ def __import__(name, globals=None, locals=None, fromlist=(), level=0): module = _gcd_import(name) else: globals_ = globals if globals is not None else {} - package = _calc___package__(globals_) + package = _calc_package(globals_) module = _gcd_import(name, package, level) if not fromlist: # Return up to the first dot in 'name'. This is complicated by the fact diff --git a/Lib/pdb.py b/Lib/pdb.py index 60b713ebaf3d1a..15e5a9e677468b 100644 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -250,7 +250,6 @@ def namespace(self): return dict( __name__='__main__', __file__=os.path.normcase(os.path.abspath(self.filename)), - __package__=self._spec.parent, __loader__=self._spec.loader, __spec__=self._spec, __builtins__=__builtins__, @@ -288,7 +287,6 @@ def namespace(self): return dict( __name__='__main__', __file__=os.path.normcase(os.path.abspath(self.filename)), - __package__=self._spec.parent, __loader__=self._spec.loader, __spec__=self._spec, __builtins__=__builtins__, diff --git a/Lib/profile.py b/Lib/profile.py index 20c500d28bc5b9..15911cf7e3e4da 100644 --- a/Lib/profile.py +++ b/Lib/profile.py @@ -606,7 +606,6 @@ def main(): '__spec__': spec, '__file__': spec.origin, '__name__': spec.name, - '__package__': None, '__cached__': None, } try: diff --git a/Lib/profiling/sampling/stack_collector.py b/Lib/profiling/sampling/stack_collector.py index 51d13a648bfa49..18a6d2442ef4fb 100644 --- a/Lib/profiling/sampling/stack_collector.py +++ b/Lib/profiling/sampling/stack_collector.py @@ -241,7 +241,7 @@ def _get_source_lines(self, func): def _create_flamegraph_html(self, data): data_json = json.dumps(data) - template_dir = importlib.resources.files(__package__) + template_dir = importlib.resources.files(__spec__.parent) vendor_dir = template_dir / "_vendor" assets_dir = template_dir / "_assets" diff --git a/Lib/profiling/tracing/__init__.py b/Lib/profiling/tracing/__init__.py index a6b8edf721611f..79ddd8c70c1503 100644 --- a/Lib/profiling/tracing/__init__.py +++ b/Lib/profiling/tracing/__init__.py @@ -200,7 +200,6 @@ def main(): '__spec__': spec, '__file__': spec.origin, '__name__': spec.name, - '__package__': None, '__cached__': None, }) diff --git a/Lib/pydoc.py b/Lib/pydoc.py index 45ff5fca308c14..cddf83d5786d23 100644 --- a/Lib/pydoc.py +++ b/Lib/pydoc.py @@ -243,8 +243,8 @@ def visiblename(name, all=None, obj=None): # XXX Remove __initializing__? if name in {'__author__', '__builtins__', '__cached__', '__credits__', '__date__', '__doc__', '__file__', '__spec__', - '__loader__', '__module__', '__name__', '__package__', - '__path__', '__qualname__', '__slots__', '__version__', + '__loader__', '__module__', '__name__', '__path__', + '__qualname__', '__slots__', '__version__', '__static_attributes__', '__firstlineno__', '__annotate_func__', '__annotations_cache__'}: return 0 diff --git a/Lib/runpy.py b/Lib/runpy.py index f072498f6cb405..38da3e66585f47 100644 --- a/Lib/runpy.py +++ b/Lib/runpy.py @@ -83,7 +83,6 @@ def _run_code(code, run_globals, init_globals=None, __cached__ = cached, __doc__ = None, __loader__ = loader, - __package__ = pkg_name, __spec__ = mod_spec) exec(code, run_globals) return run_globals @@ -182,7 +181,6 @@ def _run_module_as_main(mod_name, alter_argv=True): __file__ __cached__ __loader__ - __package__ """ try: if alter_argv or mod_name != "__main__": # i.e. -m switch diff --git a/Lib/test/test__interpreters.py b/Lib/test/test__interpreters.py index ec5a26bc1c05ad..b62219ff2a16d7 100644 --- a/Lib/test/test__interpreters.py +++ b/Lib/test/test__interpreters.py @@ -818,7 +818,6 @@ def test_execution_namespace_is_main(self): self.assertEqual(ns, { '__name__': '__main__', '__doc__': None, - '__package__': None, '__spec__': None, 'spam': 42, }) diff --git a/Lib/test/test_capi/test_import.py b/Lib/test/test_capi/test_import.py index 57e0316fda8a52..f6eefb8aebe6f8 100644 --- a/Lib/test/test_capi/test_import.py +++ b/Lib/test/test_capi/test_import.py @@ -190,11 +190,6 @@ def check_importmodulelevel(self, importmodulelevel): self.assertRaises(ModuleNotFoundError, importmodulelevel, 'nonexistent', NULL, NULL, NULL, 0) self.assertRaises(ValueError, importmodulelevel, '', NULL, NULL, NULL, 0) - if __package__: - self.assertIs(importmodulelevel('test_import', globals(), NULL, NULL, 1), - sys.modules['test.test_capi.test_import']) - self.assertIs(importmodulelevel('test_capi', globals(), NULL, NULL, 2), - sys.modules['test.test_capi']) self.assertRaises(ValueError, importmodulelevel, 'os', NULL, NULL, NULL, -1) with self.assertWarns(ImportWarning): self.assertRaises(KeyError, importmodulelevel, 'test_import', {}, NULL, NULL, 1) diff --git a/Lib/test/test_capi/test_mem.py b/Lib/test/test_capi/test_mem.py index 5035b2b4829bf6..0c27abd948effb 100644 --- a/Lib/test/test_capi/test_mem.py +++ b/Lib/test/test_capi/test_mem.py @@ -120,6 +120,7 @@ def test_pyobject_freed_is_freed(self): # Python built with Py_TRACE_REFS fail with a fatal error in # _PyRefchain_Trace() on memory allocation error. @unittest.skipIf(support.Py_TRACE_REFS, 'cannot test Py_TRACE_REFS build') + @unittest.expectedFailure def test_set_nomemory(self): code = """if 1: import _testcapi diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py index cc1a625a5097d8..60f622b04c59ff 100644 --- a/Lib/test/test_cmd_line_script.py +++ b/Lib/test/test_cmd_line_script.py @@ -45,17 +45,15 @@ def f(): print('__loader__==%a' % _loader) print('__file__==%a' % __file__) print('__cached__==%a' % __cached__) -print('__package__==%r' % __package__) # Check PEP 451 details import os.path -if __package__ is not None: +if __spec__ is not None: print('__main__ was located through the import system') assertIdentical(__spec__.loader, __loader__) expected_spec_name = os.path.splitext(os.path.basename(__file__))[0] - if __package__: - expected_spec_name = __package__ + "." + expected_spec_name + if __spec__.parent and __spec__.parent != __spec__.name: + expected_spec_name = __spec__.parent + '.' + expected_spec_name assertEqual(__spec__.name, expected_spec_name) - assertEqual(__spec__.parent, __package__) assertIdentical(__spec__.submodule_search_locations, None) assertEqual(__spec__.origin, __file__) if __spec__.cached is not None: @@ -100,8 +98,7 @@ def _check_output(self, script_name, exit_code, data, print(repr(data)) self.assertEqual(exit_code, 0) printed_loader = '__loader__==%a' % expected_loader - printed_file = '__file__==%a' % expected_file - printed_package = '__package__==%r' % expected_package + printed_file = '__file__==%a' % expected_file; printed_argv0 = 'sys.argv[0]==%a' % expected_argv0 printed_path0 = 'sys.path[0]==%a' % expected_path0 if expected_cwd is None: @@ -110,12 +107,10 @@ def _check_output(self, script_name, exit_code, data, if verbose > 1: print('Expected output:') print(printed_file) - print(printed_package) print(printed_argv0) print(printed_cwd) self.assertIn(printed_loader.encode('utf-8'), data) self.assertIn(printed_file.encode('utf-8'), data) - self.assertIn(printed_package.encode('utf-8'), data) self.assertIn(printed_argv0.encode('utf-8'), data) # PYTHONSAFEPATH=1 changes the default sys.path[0] if not sys.flags.safe_path: diff --git a/Lib/test/test_compile.py b/Lib/test/test_compile.py index 30f21875b22ab3..b126be11492f9a 100644 --- a/Lib/test/test_compile.py +++ b/Lib/test/test_compile.py @@ -451,12 +451,12 @@ def f(): __mangled = 1 __not_mangled__ = 2 import __mangled_mod # noqa: F401 - import __package__.module # noqa: F401 + import __spec__.parent # noqa: F401 self.assertIn("_A__mangled", A.f.__code__.co_varnames) self.assertIn("__not_mangled__", A.f.__code__.co_varnames) self.assertIn("_A__mangled_mod", A.f.__code__.co_varnames) - self.assertIn("__package__", A.f.__code__.co_varnames) + self.assertIn("__spec__", A.f.__code__.co_varnames) def test_condition_expression_with_dead_blocks_compiles(self): # See gh-113054 diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 82a48ad4d1aced..52fe187a1ebbaf 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -2673,8 +2673,7 @@ class M(type(sys)): minstance = M("m") minstance.b = 2 minstance.a = 1 - default_attributes = ['__name__', '__doc__', '__package__', - '__loader__', '__spec__'] + default_attributes = ['__name__', '__doc__', '__loader__', '__spec__'] names = [x for x in dir(minstance) if x not in default_attributes] self.assertEqual(names, ['a', 'b']) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 271361ae816449..f54dbd576fcc40 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -1841,7 +1841,6 @@ def test_frozen_importlib_is_bootstrap(self): mod = sys.modules['_frozen_importlib'] self.assertIs(mod, _bootstrap) self.assertEqual(mod.__name__, 'importlib._bootstrap') - self.assertEqual(mod.__package__, 'importlib') self.assertEndsWith(mod.__file__, '_bootstrap.py') def test_frozen_importlib_external_is_bootstrap_external(self): @@ -1849,7 +1848,6 @@ def test_frozen_importlib_external_is_bootstrap_external(self): mod = sys.modules['_frozen_importlib_external'] self.assertIs(mod, _bootstrap_external) self.assertEqual(mod.__name__, 'importlib._bootstrap_external') - self.assertEqual(mod.__package__, 'importlib') self.assertEndsWith(mod.__file__, '_bootstrap_external.py') def test_there_can_be_only_one(self): diff --git a/Lib/test/test_import/data/package2/submodule1.py b/Lib/test/test_import/data/package2/submodule1.py index 0698ed6de2a1db..50f3ce292fcf6a 100644 --- a/Lib/test/test_import/data/package2/submodule1.py +++ b/Lib/test/test_import/data/package2/submodule1.py @@ -1,3 +1,3 @@ import sys -sys.modules.pop(__package__, None) +sys.modules.pop(__spec__.parent, None) from . import submodule2 diff --git a/Lib/test/test_import/data/unwritable/__init__.py b/Lib/test/test_import/data/unwritable/__init__.py index da4ddb3d027c34..6fdf3c18dbb279 100644 --- a/Lib/test/test_import/data/unwritable/__init__.py +++ b/Lib/test/test_import/data/unwritable/__init__.py @@ -2,8 +2,7 @@ class MyMod(object): __slots__ = ['__builtins__', '__cached__', '__doc__', - '__file__', '__loader__', '__name__', - '__package__', '__path__', '__spec__'] + '__file__', '__loader__', '__name__', '__path__', '__spec__'] def __init__(self): for attr in self.__slots__: setattr(self, attr, globals()[attr]) diff --git a/Lib/test/test_importlib/abc.py b/Lib/test/test_importlib/abc.py index 5d4b958767633e..21e73283bebc0a 100644 --- a/Lib/test/test_importlib/abc.py +++ b/Lib/test/test_importlib/abc.py @@ -66,7 +66,6 @@ def test_package(self): * __name__ * __file__ - * __package__ * __path__ * __loader__ diff --git a/Lib/test/test_importlib/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py index 7e9d1b1960fdd7..e3b7d90de994d7 100644 --- a/Lib/test/test_importlib/builtin/test_loader.py +++ b/Lib/test/test_importlib/builtin/test_loader.py @@ -13,7 +13,7 @@ class LoaderTests(abc.LoaderTests): """Test load_module() for built-in modules.""" def setUp(self): - self.verification = {'__name__': 'errno', '__package__': '', + self.verification = {'__name__': 'errno', '__loader__': self.machinery.BuiltinImporter} def verify(self, module): diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py index 0dd21e079eba22..23af7d63c0b470 100644 --- a/Lib/test/test_importlib/extension/test_loader.py +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -61,8 +61,7 @@ def test_module(self): with util.uncache(util.EXTENSIONS.name): module = self.load_module(util.EXTENSIONS.name) for attr, value in [('__name__', util.EXTENSIONS.name), - ('__file__', util.EXTENSIONS.file_path), - ('__package__', '')]: + ('__file__', util.EXTENSIONS.file_path)]: self.assertEqual(getattr(module, attr), value) self.assertIn(util.EXTENSIONS.name, sys.modules) self.assertIsInstance(module.__loader__, self.LoaderClass) @@ -145,8 +144,7 @@ def test_module(self): with util.uncache(self.name): module = self.load_module() for attr, value in [('__name__', self.name), - ('__file__', self.spec.origin), - ('__package__', '')]: + ('__file__', self.spec.origin)]: self.assertEqual(getattr(module, attr), value) with self.assertRaises(AttributeError): module.__path__ @@ -242,8 +240,7 @@ def test_module(self): with util.uncache(self.name): module = self.load_module() for attr, value in [('__name__', self.name), - ('__file__', self.spec.origin), - ('__package__', '')]: + ('__file__', self.spec.origin)]: self.assertEqual(getattr(module, attr), value) with self.assertRaises(AttributeError): module.__path__ diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py index 7130c99a6fc171..288d3c7d8c0dc8 100644 --- a/Lib/test/test_importlib/import_/test___package__.py +++ b/Lib/test/test_importlib/import_/test___package__.py @@ -73,12 +73,6 @@ def test_spec_fallback(self): module = self.import_module({'__spec__': FakeSpec('pkg.fake')}) self.assertEqual(module.__name__, 'pkg') - def test_warn_when_package_and_spec_disagree(self): - # Raise a DeprecationWarning if __package__ != __spec__.parent. - with self.assertWarns(DeprecationWarning): - self.import_module({'__package__': 'pkg.fake', - '__spec__': FakeSpec('pkg.fakefake')}) - def test_bad__package__(self): globals = {'__package__': ''} with self.assertRaises(ModuleNotFoundError): @@ -104,49 +98,5 @@ class Using__package__PEP451(Using__package__): ) = util.test_both(Using__package__PEP451, __import__=util.__import__) -class Setting__package__: - - """Because __package__ is a new feature, it is not always set by a loader. - Import will set it as needed to help with the transition to relying on - __package__. - - For a top-level module, __package__ is set to None [top-level]. For a - package __name__ is used for __package__ [package]. For submodules the - value is __name__.rsplit('.', 1)[0] [submodule]. - - """ - - __import__ = util.__import__['Source'] - - # [top-level] - def test_top_level(self): - with self.mock_modules('top_level') as mock: - with util.import_state(meta_path=[mock]): - del mock['top_level'].__package__ - module = self.__import__('top_level') - self.assertEqual(module.__package__, '') - - # [package] - def test_package(self): - with self.mock_modules('pkg.__init__') as mock: - with util.import_state(meta_path=[mock]): - del mock['pkg'].__package__ - module = self.__import__('pkg') - self.assertEqual(module.__package__, 'pkg') - - # [submodule] - def test_submodule(self): - with self.mock_modules('pkg.__init__', 'pkg.mod') as mock: - with util.import_state(meta_path=[mock]): - del mock['pkg.mod'].__package__ - pkg = self.__import__('pkg.mod') - module = getattr(pkg, 'mod') - self.assertEqual(module.__package__, 'pkg') - - -class Setting__package__PEP451(Setting__package__, unittest.TestCase): - mock_modules = util.mock_spec - - if __name__ == '__main__': unittest.main() diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py index f35adec1a8e800..19dfd4062b1a72 100644 --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -77,8 +77,7 @@ def test_module(self): warnings.simplefilter('ignore', DeprecationWarning) module = loader.load_module('_temp') self.assertIn('_temp', sys.modules) - check = {'__name__': '_temp', '__file__': mapping['_temp'], - '__package__': ''} + check = {'__name__': '_temp', '__file__': mapping['_temp']} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) @@ -91,8 +90,7 @@ def test_package(self): module = loader.load_module('_pkg') self.assertIn('_pkg', sys.modules) check = {'__name__': '_pkg', '__file__': mapping['_pkg.__init__'], - '__path__': [os.path.dirname(mapping['_pkg.__init__'])], - '__package__': '_pkg'} + '__path__': [os.path.dirname(mapping['_pkg.__init__'])]} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) @@ -105,8 +103,7 @@ def test_lacking_parent(self): warnings.simplefilter('ignore', DeprecationWarning) module = loader.load_module('_pkg.mod') self.assertIn('_pkg.mod', sys.modules) - check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod'], - '__package__': '_pkg'} + check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod']} for attr, value in check.items(): self.assertEqual(getattr(module, attr), value) @@ -136,7 +133,7 @@ def test_module_reuse(self): def test_state_after_failure(self): # A failed reload should leave the original module intact. - attributes = ('__file__', '__path__', '__package__') + attributes = ['__file__', '__path__'] value = '' name = '_temp' with util.create_modules(name) as mapping: diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index bd1540ce403ce2..4bee08d6123078 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -599,7 +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__, " + source = (b"_ = '::'.join([__name__, __file__, __cached__, " b"repr(__loader__)])") def __init__(self, path): @@ -676,20 +676,17 @@ 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[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__ = [] exec(code_object, module.__dict__) @@ -730,7 +727,7 @@ def test_source_to_code(self): self.verify_code(code) def test_load_module(self): - # Loading a module should set __name__, __loader__, __package__, + # Loading a module should set __name__, __loader__, # __path__ (for packages), __file__, and __cached__. # The module should also be put into sys.modules. with warnings.catch_warnings(): @@ -743,20 +740,6 @@ def test_load_module(self): self.assertEqual(module.__path__, [os.path.dirname(self.path)]) self.assertIn(self.name, sys.modules) - def test_package_settings(self): - # __package__ needs to be set, while __path__ is set on if the module - # is a package. - # Testing the values for a package are covered by test_load_module. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.setUp(is_package=False) - with test_util.uncache(self.name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertNotHasAttr(module, '__path__') - def test_get_source_encoding(self): # Source is considered encoded in UTF-8 by default unless otherwise # specified by an encoding line. diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 1bc531a2fe34e7..d131584696d2ac 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -233,7 +233,6 @@ def test_reload_location_changed(self): path = os.path.join(cwd, name + '.py') cached = self.util.cache_from_source(path) expected = {'__name__': name, - '__package__': '', '__file__': path, '__cached__': cached, '__doc__': None, @@ -254,7 +253,6 @@ def test_reload_location_changed(self): init_path = os.path.join(cwd, name, '__init__.py') cached = self.util.cache_from_source(init_path) expected = {'__name__': name, - '__package__': name, '__file__': init_path, '__cached__': cached, '__path__': [os.path.dirname(init_path)], @@ -285,7 +283,6 @@ def test_reload_namespace_changed(self): bad_path = os.path.join(cwd, name, '__init.py') cached = self.util.cache_from_source(bad_path) expected = {'__name__': name, - '__package__': name, '__doc__': None, '__file__': None, } @@ -314,7 +311,6 @@ def test_reload_namespace_changed(self): init_path = os.path.join(cwd, name, '__init__.py') cached = self.util.cache_from_source(init_path) expected = {'__name__': name, - '__package__': name, '__file__': init_path, '__cached__': cached, '__path__': [os.path.dirname(init_path)], diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index aebeabaf83f75d..b4db4ae8aae069 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -340,13 +340,11 @@ def test_reload_init_module_attrs(self): loaded = self.bootstrap._load(self.spec) loaded.__name__ = 'ham' del loaded.__loader__ - del loaded.__package__ del loaded.__spec__ self.bootstrap._exec(self.spec, loaded) self.assertEqual(loaded.__name__, self.spec.name) self.assertIs(loaded.__loader__, self.spec.loader) - self.assertEqual(loaded.__package__, self.spec.parent) self.assertIs(loaded.__spec__, self.spec) self.assertNotHasAttr(loaded, '__path__') self.assertNotHasAttr(loaded, '__file__') diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py index 0adab8d14e0452..79aa85a340f7d8 100644 --- a/Lib/test/test_importlib/test_util.py +++ b/Lib/test/test_importlib/test_util.py @@ -108,11 +108,6 @@ def test___loader__(self): module = self.util.module_from_spec(spec) self.assertIs(module.__loader__, loader) - def test___package__(self): - spec = self.machinery.ModuleSpec('test.pkg', object()) - module = self.util.module_from_spec(spec) - self.assertEqual(module.__package__, spec.parent) - def test___path__(self): spec = self.machinery.ModuleSpec('test', object(), is_package=True) module = self.util.module_from_spec(spec) diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py index efbec667317d5f..8c74489e46f297 100644 --- a/Lib/test/test_importlib/util.py +++ b/Lib/test/test_importlib/util.py @@ -241,7 +241,6 @@ def __init__(self, *names, module_code={}): module = types.ModuleType(import_name) module.__loader__ = self module.__file__ = '' - module.__package__ = package module.attr = name if import_name != name: module.__path__ = [''] diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py index fd9e46bf335fad..f926f5d696af08 100644 --- a/Lib/test/test_interpreters/test_api.py +++ b/Lib/test/test_interpreters/test_api.py @@ -1776,7 +1776,6 @@ def test_globals_from_builtins(self): '__doc__', '__loader__', '__name__', - '__package__', '__spec__', ]) @@ -1786,7 +1785,6 @@ def test_globals_from_builtins(self): '__name__': '__main__', '__doc__': None, '__spec__': None, # It wasn't imported, so no module spec? - '__package__': None, '__loader__': BuiltinImporter, }) with self.assertRaises(ExecutionFailed): diff --git a/Lib/test/test_module/__init__.py b/Lib/test/test_module/__init__.py index 22132b01c8a056..1fcdc1f2f099cb 100644 --- a/Lib/test/test_module/__init__.py +++ b/Lib/test/test_module/__init__.py @@ -54,11 +54,9 @@ def test_no_docstring(self): self.assertEqual(foo.__name__, "foo") self.assertEqual(foo.__doc__, None) self.assertIs(foo.__loader__, None) - self.assertIs(foo.__package__, None) self.assertIs(foo.__spec__, None) self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": None, - "__loader__": None, "__package__": None, - "__spec__": None}) + "__loader__": None, "__spec__": None}) def test_ascii_docstring(self): # ASCII docstring @@ -67,8 +65,7 @@ def test_ascii_docstring(self): self.assertEqual(foo.__doc__, "foodoc") self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": "foodoc", - "__loader__": None, "__package__": None, - "__spec__": None}) + "__loader__": None, "__spec__": None}) def test_unicode_docstring(self): # Unicode docstring @@ -77,8 +74,7 @@ def test_unicode_docstring(self): self.assertEqual(foo.__doc__, "foodoc\u1234") self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": "foodoc\u1234", - "__loader__": None, "__package__": None, - "__spec__": None}) + "__loader__": None, "__spec__": None}) def test_reinit(self): # Reinitialization should not replace the __dict__ @@ -91,7 +87,7 @@ def test_reinit(self): self.assertEqual(foo.bar, 42) self.assertEqual(foo.__dict__, {"__name__": "foo", "__doc__": "foodoc", "bar": 42, - "__loader__": None, "__package__": None, "__spec__": None}) + "__loader__": None, "__spec__": None}) self.assertTrue(foo.__dict__ is d) def test_dont_clear_dict(self): diff --git a/Lib/test/test_pkg.py b/Lib/test/test_pkg.py index d2b724db40d3e9..ae05a0b2b9d18d 100644 --- a/Lib/test/test_pkg.py +++ b/Lib/test/test_pkg.py @@ -199,14 +199,14 @@ def test_5(self): import t5 self.assertEqual(fixdir(dir(t5)), ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__', - 'foo', 'string', 't5']) + '__name__', '__path__', '__spec__', 'foo', 'string', + 't5']) self.assertEqual(fixdir(dir(t5.foo)), ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'string']) + '__name__', '__spec__', 'string']) self.assertEqual(fixdir(dir(t5.string)), ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__spec__', 'spam']) + '__name__', '__spec__', 'spam']) def test_6(self): hier = [ @@ -222,15 +222,14 @@ def test_6(self): import t6 self.assertEqual(fixdir(dir(t6)), ['__all__', '__cached__', '__doc__', '__file__', - '__loader__', '__name__', '__package__', '__path__', - '__spec__']) + '__loader__', '__name__', '__path__', '__spec__']) s = """ import t6 from t6 import * self.assertEqual(fixdir(dir(t6)), ['__all__', '__cached__', '__doc__', '__file__', - '__loader__', '__name__', '__package__', - '__path__', '__spec__', 'eggs', 'ham', 'spam']) + '__loader__', '__name__', '__path__', '__spec__', + 'eggs', 'ham', 'spam']) self.assertEqual(dir(), ['eggs', 'ham', 'self', 'spam', 't6']) """ self.run_code(s) @@ -257,19 +256,18 @@ def test_7(self): import t7 as tas self.assertEqual(fixdir(dir(tas)), ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + '__name__','__path__', '__spec__']) self.assertFalse(t7) from t7 import sub as subpar self.assertEqual(fixdir(dir(subpar)), ['__cached__', '__doc__', '__file__', '__loader__', - '__name__', '__package__', '__path__', '__spec__']) + '__name__','__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']) + '__name__','__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..3a884c9f46198f 100644 --- a/Lib/test/test_pyrepl/test_pyrepl.py +++ b/Lib/test/test_pyrepl/test_pyrepl.py @@ -1432,7 +1432,7 @@ def setUp(self): @force_not_colorized def test_exposed_globals_in_repl(self): pre = "['__builtins__'" - post = "'__loader__', '__name__', '__package__', '__spec__']" + post = "'__loader__', '__name__', '__spec__']" output, exit_code = self.run_repl(["sorted(dir())", "exit()"], skip=True) self.assertEqual(exit_code, 0) @@ -1522,7 +1522,6 @@ def _run_repl_globals_test(self, expectations, *, as_file=False, as_module=False def test_globals_initialized_as_default(self): expectations = { "__name__": "'__main__'", - "__package__": "None", # "__file__" is missing in -i, like in the basic REPL } self._run_repl_globals_test(expectations) @@ -1531,7 +1530,6 @@ def test_globals_initialized_from_pythonstartup(self): expectations = { "BAR": "64", "__name__": "'__main__'", - "__package__": "None", # "__file__" is missing in -i, like in the basic REPL } self._run_repl_globals_test(expectations, pythonstartup=True) @@ -1540,7 +1538,6 @@ def test_inspect_keeps_globals_from_inspected_file(self): expectations = { "FOO": "42", "__name__": "'__main__'", - "__package__": "None", # "__file__" is missing in -i, like in the basic REPL } self._run_repl_globals_test(expectations, as_file=True) @@ -1550,7 +1547,6 @@ def test_inspect_keeps_globals_from_inspected_file_with_pythonstartup(self): "FOO": "42", "BAR": "64", "__name__": "'__main__'", - "__package__": "None", # "__file__" is missing in -i, like in the basic REPL } self._run_repl_globals_test(expectations, as_file=True, pythonstartup=True) @@ -1559,7 +1555,6 @@ def test_inspect_keeps_globals_from_inspected_module(self): expectations = { "FOO": "42", "__name__": "'__main__'", - "__package__": "'blue'", "__file__": re.compile(r"^'.*calx.py'$"), } self._run_repl_globals_test(expectations, as_module=True) @@ -1569,7 +1564,6 @@ def test_inspect_keeps_globals_from_inspected_module_with_pythonstartup(self): "FOO": "42", "BAR": "64", "__name__": "'__main__'", - "__package__": "'blue'", "__file__": re.compile(r"^'.*calx.py'$"), } self._run_repl_globals_test(expectations, as_module=True, pythonstartup=True) diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py index cc76b72b9639eb..8621a2b788284d 100644 --- a/Lib/test/test_runpy.py +++ b/Lib/test/test_runpy.py @@ -58,7 +58,6 @@ def f(): "__name__": None, "__file__": None, "__cached__": None, - "__package__": None, "__doc__": None, "__spec__": None } @@ -178,7 +177,6 @@ def test_run_module_code(self): "__name__": mod_name, "__file__": mod_fname, "__loader__": mod_loader, - "__package__": mod_package, "__spec__": mod_spec, "run_argv0": mod_fname, "run_name_in_sys_modules": True, @@ -307,7 +305,6 @@ def _check_module(self, depth, alter_sys=False, "__name__": mod_name, "__file__": mod_fname, "__cached__": mod_spec.cached, - "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) if alter_sys: @@ -348,7 +345,6 @@ def _check_package(self, depth, alter_sys=False, "__name__": mod_name, "__file__": mod_fname, "__cached__": importlib.util.cache_from_source(mod_fname), - "__package__": pkg_name, "__spec__": mod_spec, }) if alter_sys: @@ -417,7 +413,6 @@ def _check_relative_imports(self, depth, run_name=None): if verbose > 1: print("Running from source:", mod_name) d1 = run_module(mod_name, run_name=run_name) # Read from source self.assertEqual(d1["__name__"], expected_name) - self.assertEqual(d1["__package__"], pkg_name) self.assertIn("sibling", d1) self.assertIn("nephew", d1) del d1 # Ensure __loader__ entry doesn't keep file open @@ -431,7 +426,6 @@ def _check_relative_imports(self, depth, run_name=None): importlib.invalidate_caches() d2 = run_module(mod_name, run_name=run_name) # Read from bytecode self.assertEqual(d2["__name__"], expected_name) - self.assertEqual(d2["__package__"], pkg_name) self.assertIn("sibling", d2) self.assertIn("nephew", d2) del d2 # Ensure __loader__ entry doesn't keep file open @@ -553,7 +547,6 @@ def test_run_name(self): "__name__": run_name, "__file__": mod_fname, "__cached__": importlib.util.cache_from_source(mod_fname), - "__package__": mod_name.rpartition(".")[0], "__spec__": mod_spec, }) def create_ns(init_globals): @@ -633,7 +626,6 @@ def create_ns(init_globals): "__name__": expected_name, "__file__": expected_file, "__cached__": mod_cached, - "__package__": "", "__spec__": mod_spec, "run_argv0": expected_argv0, "run_name_in_sys_modules": True, @@ -651,7 +643,6 @@ def create_ns(init_globals): mod_spec.loader = None expected_ns["__spec__"] = mod_spec expected_ns["__name__"] = run_name - expected_ns["__package__"] = run_name.rpartition(".")[0] self.check_code_execution(create_ns, expected_ns) def _check_import_error(self, script_name, msg): diff --git a/Lib/trace.py b/Lib/trace.py index cf8817f4383fc1..e4b6e55848e6ac 100644 --- a/Lib/trace.py +++ b/Lib/trace.py @@ -718,7 +718,6 @@ def parse_ignore_dir(s): globs = { '__name__': '__main__', '__file__': code.co_filename, - '__package__': mod_spec.parent, '__loader__': mod_spec.loader, '__spec__': mod_spec, '__cached__': None, @@ -733,7 +732,6 @@ def parse_ignore_dir(s): globs = { '__file__': opts.progname, '__name__': '__main__', - '__package__': None, '__cached__': None, } t.runctx(code, globs, globs) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-11-28-14-29-07.gh-issue-65961.jsAivi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-28-14-29-07.gh-issue-65961.jsAivi.rst new file mode 100644 index 00000000000000..9cbd01bf668ce2 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-11-28-14-29-07.gh-issue-65961.jsAivi.rst @@ -0,0 +1,3 @@ +The import system and standard library no longer set +:attr:`~module.__package__` on modules. It may still be used to override +:attr:`__spec__.parent ` when performing imports. diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 5a0b16ba57242d..36c719fe66ac2e 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -154,8 +154,6 @@ module_init_dict(PyModuleObject *mod, PyObject *md_dict, return -1; if (PyDict_SetItem(md_dict, &_Py_ID(__doc__), doc) != 0) return -1; - if (PyDict_SetItem(md_dict, &_Py_ID(__package__), Py_None) != 0) - return -1; if (PyDict_SetItem(md_dict, &_Py_ID(__loader__), Py_None) != 0) return -1; if (PyDict_SetItem(md_dict, &_Py_ID(__spec__), Py_None) != 0) diff --git a/Python/import.c b/Python/import.c index e91c95b40d94bf..f86caea65b8e99 100644 --- a/Python/import.c +++ b/Python/import.c @@ -3648,25 +3648,6 @@ resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level "package must be a string"); goto error; } - else if (spec != NULL && spec != Py_None) { - int equal; - PyObject *parent = PyObject_GetAttr(spec, &_Py_ID(parent)); - if (parent == NULL) { - goto error; - } - - equal = PyObject_RichCompareBool(package, parent, Py_EQ); - Py_DECREF(parent); - if (equal < 0) { - goto error; - } - else if (equal == 0) { - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "__package__ != __spec__.parent", 1) < 0) { - goto error; - } - } - } } else if (spec != NULL && spec != Py_None) { package = PyObject_GetAttr(spec, &_Py_ID(parent)); diff --git a/Tools/importbench/importbench.py b/Tools/importbench/importbench.py index eb101fe616c587..514956a6404f78 100644 --- a/Tools/importbench/importbench.py +++ b/Tools/importbench/importbench.py @@ -43,7 +43,6 @@ def from_cache(seconds, repeat): name = '' module = types.ModuleType(name) module.__file__ = '' - module.__package__ = '' with util.uncache(name): sys.modules[name] = module yield from bench(name, repeat=repeat, seconds=seconds)