mirror of
https://github.com/python/cpython.git
synced 2025-10-05 06:31:48 +00:00
[3.6] bpo-21720: Restore the Python 2.7 logic in handling a fromlist. (GH-4118) (#4128)
BytesWarning no longer emitted when the fromlist argument of
__import__() or the __all__ attribute of the module contain bytes
instances..
(cherry picked from commit 41c56940c6
)
This commit is contained in:
parent
614ea48986
commit
2b5cbbb13c
4 changed files with 1653 additions and 1591 deletions
|
@ -994,7 +994,7 @@ def _gcd_import(name, package=None, level=0):
|
||||||
return _find_and_load(name, _gcd_import)
|
return _find_and_load(name, _gcd_import)
|
||||||
|
|
||||||
|
|
||||||
def _handle_fromlist(module, fromlist, import_):
|
def _handle_fromlist(module, fromlist, import_, *, recursive=False):
|
||||||
"""Figure out what __import__ should return.
|
"""Figure out what __import__ should return.
|
||||||
|
|
||||||
The import_ parameter is a callable which takes the name of module to
|
The import_ parameter is a callable which takes the name of module to
|
||||||
|
@ -1005,13 +1005,19 @@ def _handle_fromlist(module, fromlist, import_):
|
||||||
# The hell that is fromlist ...
|
# The hell that is fromlist ...
|
||||||
# If a package was imported, try to import stuff from fromlist.
|
# If a package was imported, try to import stuff from fromlist.
|
||||||
if hasattr(module, '__path__'):
|
if hasattr(module, '__path__'):
|
||||||
if '*' in fromlist:
|
|
||||||
fromlist = list(fromlist)
|
|
||||||
fromlist.remove('*')
|
|
||||||
if hasattr(module, '__all__'):
|
|
||||||
fromlist.extend(module.__all__)
|
|
||||||
for x in fromlist:
|
for x in fromlist:
|
||||||
if not hasattr(module, x):
|
if not isinstance(x, str):
|
||||||
|
if recursive:
|
||||||
|
where = module.__name__ + '.__all__'
|
||||||
|
else:
|
||||||
|
where = "``from list''"
|
||||||
|
raise TypeError(f"Item in {where} must be str, "
|
||||||
|
f"not {type(x).__name__}")
|
||||||
|
elif x == '*':
|
||||||
|
if not recursive and hasattr(module, '__all__'):
|
||||||
|
_handle_fromlist(module, module.__all__, import_,
|
||||||
|
recursive=True)
|
||||||
|
elif not hasattr(module, x):
|
||||||
from_name = '{}.{}'.format(module.__name__, x)
|
from_name = '{}.{}'.format(module.__name__, x)
|
||||||
try:
|
try:
|
||||||
_call_with_frames_removed(import_, from_name)
|
_call_with_frames_removed(import_, from_name)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
"""Test that the semantics relating to the 'fromlist' argument are correct."""
|
"""Test that the semantics relating to the 'fromlist' argument are correct."""
|
||||||
from .. import util
|
from .. import util
|
||||||
|
import warnings
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,6 +74,13 @@ class HandlingFromlist:
|
||||||
self.assertTrue(hasattr(module, 'module'))
|
self.assertTrue(hasattr(module, 'module'))
|
||||||
self.assertEqual(module.module.__name__, 'pkg.module')
|
self.assertEqual(module.module.__name__, 'pkg.module')
|
||||||
|
|
||||||
|
def test_nonexistent_from_package(self):
|
||||||
|
with util.mock_modules('pkg.__init__') as importer:
|
||||||
|
with util.import_state(meta_path=[importer]):
|
||||||
|
module = self.__import__('pkg', fromlist=['non_existent'])
|
||||||
|
self.assertEqual(module.__name__, 'pkg')
|
||||||
|
self.assertFalse(hasattr(module, 'non_existent'))
|
||||||
|
|
||||||
def test_module_from_package_triggers_ModuleNotFoundError(self):
|
def test_module_from_package_triggers_ModuleNotFoundError(self):
|
||||||
# If a submodule causes an ModuleNotFoundError because it tries
|
# If a submodule causes an ModuleNotFoundError because it tries
|
||||||
# to import a module which doesn't exist, that should let the
|
# to import a module which doesn't exist, that should let the
|
||||||
|
@ -122,6 +130,41 @@ class HandlingFromlist:
|
||||||
self.assertEqual(module.module1.__name__, 'pkg.module1')
|
self.assertEqual(module.module1.__name__, 'pkg.module1')
|
||||||
self.assertEqual(module.module2.__name__, 'pkg.module2')
|
self.assertEqual(module.module2.__name__, 'pkg.module2')
|
||||||
|
|
||||||
|
def test_nonexistent_in_all(self):
|
||||||
|
with util.mock_modules('pkg.__init__') as importer:
|
||||||
|
with util.import_state(meta_path=[importer]):
|
||||||
|
importer['pkg'].__all__ = ['non_existent']
|
||||||
|
module = self.__import__('pkg', fromlist=['*'])
|
||||||
|
self.assertEqual(module.__name__, 'pkg')
|
||||||
|
self.assertFalse(hasattr(module, 'non_existent'))
|
||||||
|
|
||||||
|
def test_star_in_all(self):
|
||||||
|
with util.mock_modules('pkg.__init__') as importer:
|
||||||
|
with util.import_state(meta_path=[importer]):
|
||||||
|
importer['pkg'].__all__ = ['*']
|
||||||
|
module = self.__import__('pkg', fromlist=['*'])
|
||||||
|
self.assertEqual(module.__name__, 'pkg')
|
||||||
|
self.assertFalse(hasattr(module, '*'))
|
||||||
|
|
||||||
|
def test_invalid_type(self):
|
||||||
|
with util.mock_modules('pkg.__init__') as importer:
|
||||||
|
with util.import_state(meta_path=[importer]), \
|
||||||
|
warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('error', BytesWarning)
|
||||||
|
with self.assertRaisesRegex(TypeError, r'\bfrom\b'):
|
||||||
|
self.__import__('pkg', fromlist=[b'attr'])
|
||||||
|
with self.assertRaisesRegex(TypeError, r'\bfrom\b'):
|
||||||
|
self.__import__('pkg', fromlist=iter([b'attr']))
|
||||||
|
|
||||||
|
def test_invalid_type_in_all(self):
|
||||||
|
with util.mock_modules('pkg.__init__') as importer:
|
||||||
|
with util.import_state(meta_path=[importer]), \
|
||||||
|
warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('error', BytesWarning)
|
||||||
|
importer['pkg'].__all__ = [b'attr']
|
||||||
|
with self.assertRaisesRegex(TypeError, r'\bpkg\.__all__\b'):
|
||||||
|
self.__import__('pkg', fromlist=['*'])
|
||||||
|
|
||||||
|
|
||||||
(Frozen_FromList,
|
(Frozen_FromList,
|
||||||
Source_FromList
|
Source_FromList
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
BytesWarning no longer emitted when the *fromlist* argument of
|
||||||
|
``__import__()`` or the ``__all__`` attribute of the module contain bytes
|
||||||
|
instances.
|
3178
Python/importlib.h
3178
Python/importlib.h
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue