Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c206e53

Browse filesBrowse files
gh-65961: Raise DeprecationWarning when __package__ differs from __spec__.parent (#97879)
Also remove `importlib.util.set_package()` which was already slated for removal. Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
1 parent 2016bc5 commit c206e53
Copy full SHA for c206e53

File tree

9 files changed

+45
-102
lines changed
Filter options

9 files changed

+45
-102
lines changed

‎Doc/library/importlib.rst

Copy file name to clipboardExpand all lines: Doc/library/importlib.rst
-9Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,15 +1378,6 @@ an :term:`importer`.
13781378
.. deprecated:: 3.4
13791379
The import machinery takes care of this automatically.
13801380

1381-
.. decorator:: set_package
1382-
1383-
A :term:`decorator` for :meth:`importlib.abc.Loader.load_module` to set the
1384-
:attr:`__package__` attribute on the returned module. If :attr:`__package__`
1385-
is set and has a value other than ``None`` it will not be changed.
1386-
1387-
.. deprecated:: 3.4
1388-
The import machinery takes care of this automatically.
1389-
13901381
.. function:: spec_from_loader(name, loader, *, origin=None, is_package=None)
13911382

13921383
A factory function for creating a :class:`~importlib.machinery.ModuleSpec`

‎Doc/reference/import.rst

Copy file name to clipboardExpand all lines: Doc/reference/import.rst
+24-6Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,6 @@ of what happens during the loading portion of import::
358358
sys.modules[spec.name] = module
359359
elif not hasattr(spec.loader, 'exec_module'):
360360
module = spec.loader.load_module(spec.name)
361-
# Set __loader__ and __package__ if missing.
362361
else:
363362
sys.modules[spec.name] = module
364363
try:
@@ -539,6 +538,10 @@ The import machinery fills in these attributes on each module object
539538
during loading, based on the module's spec, before the loader executes
540539
the module.
541540

541+
It is **strongly** recommended that you rely on :attr:`__spec__` and
542+
its attributes instead of any of the other individual attributes
543+
listed below.
544+
542545
.. attribute:: __name__
543546

544547
The ``__name__`` attribute must be set to the fully qualified name of
@@ -552,24 +555,36 @@ the module.
552555
for introspection, but can be used for additional loader-specific
553556
functionality, for example getting data associated with a loader.
554557

558+
It is **strongly** recommended that you rely on :attr:`__spec__`
559+
instead instead of this attribute.
560+
555561
.. attribute:: __package__
556562

557-
The module's ``__package__`` attribute must be set. Its value must
563+
The module's ``__package__`` attribute may be set. Its value must
558564
be a string, but it can be the same value as its ``__name__``. When
559565
the module is a package, its ``__package__`` value should be set to
560566
its ``__name__``. When the module is not a package, ``__package__``
561567
should be set to the empty string for top-level modules, or for
562568
submodules, to the parent package's name. See :pep:`366` for further
563569
details.
564570

565-
This attribute is used instead of ``__name__`` to calculate explicit
566-
relative imports for main modules, as defined in :pep:`366`. It is
567-
expected to have the same value as ``__spec__.parent``.
571+
It is **strongly** recommended that you rely on :attr:`__spec__`
572+
instead instead of this attribute.
568573

569574
.. versionchanged:: 3.6
570575
The value of ``__package__`` is expected to be the same as
571576
``__spec__.parent``.
572577

578+
.. versionchanged:: 3.10
579+
:exc:`ImportWarning` is raised if import falls back to
580+
``__package__`` instead of
581+
:attr:`~importlib.machinery.ModuleSpec.parent`.
582+
583+
.. versionchanged:: 3.12
584+
Raise :exc:`DeprecationWarning` instead of :exc:`ImportWarning`
585+
when falling back to ``__package__``.
586+
587+
573588
.. attribute:: __spec__
574589

575590
The ``__spec__`` attribute must be set to the module spec that was
@@ -578,7 +593,7 @@ the module.
578593
interpreter startup <programs>`. The one exception is ``__main__``,
579594
where ``__spec__`` is :ref:`set to None in some cases <main_spec>`.
580595

581-
When ``__package__`` is not defined, ``__spec__.parent`` is used as
596+
When ``__spec__.parent`` is not set, ``__package__`` is used as
582597
a fallback.
583598

584599
.. versionadded:: 3.4
@@ -623,6 +638,9 @@ the module.
623638
if a loader can load from a cached module but otherwise does not load
624639
from a file, that atypical scenario may be appropriate.
625640

641+
It is **strongly** recommended that you rely on :attr:`__spec__`
642+
instead instead of ``__cached__``.
643+
626644
.. _package-path-rules:
627645

628646
module.__path__

‎Doc/whatsnew/3.12.rst

Copy file name to clipboardExpand all lines: Doc/whatsnew/3.12.rst
+12Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ Deprecated
215215
may be removed in a future version of Python. Use the single-arg versions
216216
of these functions instead. (Contributed by Ofey Chan in :gh:`89874`.)
217217

218+
* :exc:`DeprecationWarning` is now raised when ``__package__`` on a
219+
module differs from ``__spec__.parent`` (previously it was
220+
:exc:`ImportWarning`).
221+
(Contributed by Brett Cannon in :gh:`65961`.)
222+
218223

219224
Pending Removal in Python 3.13
220225
------------------------------
@@ -275,6 +280,9 @@ Pending Removal in Python 3.14
275280
* Creating :c:data:`immutable types <Py_TPFLAGS_IMMUTABLETYPE>` with mutable
276281
bases using the C API.
277282

283+
* ``__package__`` will cease to be set or taken into consideration by
284+
the import system (:gh:`97879`).
285+
278286

279287
Pending Removal in Future Versions
280288
----------------------------------
@@ -432,6 +440,10 @@ Removed
432440
* References to, and support for ``module_repr()`` has been eradicated.
433441

434442

443+
* ``importlib.util.set_package`` has been removed.
444+
(Contributed by Brett Cannon in :gh:`65961`.)
445+
446+
435447
Porting to Python 3.12
436448
======================
437449

‎Lib/importlib/_bootstrap.py

Copy file name to clipboardExpand all lines: Lib/importlib/_bootstrap.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,7 @@ def _calc___package__(globals):
12281228
if spec is not None and package != spec.parent:
12291229
_warnings.warn("__package__ != __spec__.parent "
12301230
f"({package!r} != {spec.parent!r})",
1231-
ImportWarning, stacklevel=3)
1231+
DeprecationWarning, stacklevel=3)
12321232
return package
12331233
elif spec is not None:
12341234
return spec.parent

‎Lib/importlib/util.py

Copy file name to clipboardExpand all lines: Lib/importlib/util.py
-20Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -141,26 +141,6 @@ def _module_to_load(name):
141141
module.__initializing__ = False
142142

143143

144-
def set_package(fxn):
145-
"""Set __package__ on the returned module.
146-
147-
This function is deprecated.
148-
149-
"""
150-
@functools.wraps(fxn)
151-
def set_package_wrapper(*args, **kwargs):
152-
warnings.warn('The import system now takes care of this automatically; '
153-
'this decorator is slated for removal in Python 3.12',
154-
DeprecationWarning, stacklevel=2)
155-
module = fxn(*args, **kwargs)
156-
if getattr(module, '__package__', None) is None:
157-
module.__package__ = module.__name__
158-
if not hasattr(module, '__path__'):
159-
module.__package__ = module.__package__.rpartition('.')[0]
160-
return module
161-
return set_package_wrapper
162-
163-
164144
def set_loader(fxn):
165145
"""Set __loader__ on the returned module.
166146

‎Lib/test/test_importlib/import_/test___package__.py

Copy file name to clipboardExpand all lines: Lib/test/test_importlib/import_/test___package__.py
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ def test_spec_fallback(self):
7474
self.assertEqual(module.__name__, 'pkg')
7575

7676
def test_warn_when_package_and_spec_disagree(self):
77-
# Raise an ImportWarning if __package__ != __spec__.parent.
78-
with self.assertWarns(ImportWarning):
77+
# Raise a DeprecationWarning if __package__ != __spec__.parent.
78+
with self.assertWarns(DeprecationWarning):
7979
self.import_module({'__package__': 'pkg.fake',
8080
'__spec__': FakeSpec('pkg.fakefake')})
8181

‎Lib/test/test_importlib/test_util.py

Copy file name to clipboardExpand all lines: Lib/test/test_importlib/test_util.py
-63Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -252,69 +252,6 @@ def load_module(self, module):
252252
) = util.test_both(ModuleForLoaderTests, util=importlib_util)
253253

254254

255-
class SetPackageTests:
256-
257-
"""Tests for importlib.util.set_package."""
258-
259-
def verify(self, module, expect):
260-
"""Verify the module has the expected value for __package__ after
261-
passing through set_package."""
262-
fxn = lambda: module
263-
wrapped = self.util.set_package(fxn)
264-
with warnings.catch_warnings():
265-
warnings.simplefilter('ignore', DeprecationWarning)
266-
wrapped()
267-
self.assertTrue(hasattr(module, '__package__'))
268-
self.assertEqual(expect, module.__package__)
269-
270-
def test_top_level(self):
271-
# __package__ should be set to the empty string if a top-level module.
272-
# Implicitly tests when package is set to None.
273-
module = types.ModuleType('module')
274-
module.__package__ = None
275-
self.verify(module, '')
276-
277-
def test_package(self):
278-
# Test setting __package__ for a package.
279-
module = types.ModuleType('pkg')
280-
module.__path__ = ['<path>']
281-
module.__package__ = None
282-
self.verify(module, 'pkg')
283-
284-
def test_submodule(self):
285-
# Test __package__ for a module in a package.
286-
module = types.ModuleType('pkg.mod')
287-
module.__package__ = None
288-
self.verify(module, 'pkg')
289-
290-
def test_setting_if_missing(self):
291-
# __package__ should be set if it is missing.
292-
module = types.ModuleType('mod')
293-
if hasattr(module, '__package__'):
294-
delattr(module, '__package__')
295-
self.verify(module, '')
296-
297-
def test_leaving_alone(self):
298-
# If __package__ is set and not None then leave it alone.
299-
for value in (True, False):
300-
module = types.ModuleType('mod')
301-
module.__package__ = value
302-
self.verify(module, value)
303-
304-
def test_decorator_attrs(self):
305-
def fxn(module): pass
306-
with warnings.catch_warnings():
307-
warnings.simplefilter('ignore', DeprecationWarning)
308-
wrapped = self.util.set_package(fxn)
309-
self.assertEqual(wrapped.__name__, fxn.__name__)
310-
self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
311-
312-
313-
(Frozen_SetPackageTests,
314-
Source_SetPackageTests
315-
) = util.test_both(SetPackageTests, util=importlib_util)
316-
317-
318255
class SetLoaderTests:
319256

320257
"""Tests importlib.util.set_loader()."""
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
When ``__package__`` is different than ``__spec__.parent``, raise a
2+
``DeprecationWarning`` instead of ``ImportWarning``.
3+
4+
Also remove ``importlib.util.set_package()`` which was scheduled for
5+
removal.

‎Python/import.c

Copy file name to clipboardExpand all lines: Python/import.c
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1573,7 +1573,7 @@ resolve_name(PyThreadState *tstate, PyObject *name, PyObject *globals, int level
15731573
goto error;
15741574
}
15751575
else if (equal == 0) {
1576-
if (PyErr_WarnEx(PyExc_ImportWarning,
1576+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
15771577
"__package__ != __spec__.parent", 1) < 0) {
15781578
goto error;
15791579
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.