Skip to content
Permalink
Browse files

bpo-21720: Restore the Python 2.7 logic in handling a fromlist. (#4118)

BytesWarning no longer emitted when the fromlist argument of
__import__() or the __all__ attribute of the module contain bytes
instances.
  • Loading branch information
serhiy-storchaka committed Oct 26, 2017
1 parent 4eaf7f9 commit 41c56940c6edf3ea169332a6b039b6c8796f0475
@@ -994,7 +994,7 @@ def _gcd_import(name, package=None, level=0):
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.
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 ...
# If a package was imported, try to import stuff from fromlist.
if hasattr(module, '__path__'):
if '*' in fromlist:
fromlist = list(fromlist)
fromlist.remove('*')
if hasattr(module, '__all__'):
fromlist.extend(module.__all__)
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)
try:
_call_with_frames_removed(import_, from_name)
@@ -1,5 +1,6 @@
"""Test that the semantics relating to the 'fromlist' argument are correct."""
from .. import util
import warnings
import unittest


@@ -73,6 +74,13 @@ def test_module_from_package(self):
self.assertTrue(hasattr(module, '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):
# If a submodule causes an ModuleNotFoundError because it tries
# to import a module which doesn't exist, that should let the
@@ -122,6 +130,41 @@ def test_star_with_others(self):
self.assertEqual(module.module1.__name__, 'pkg.module1')
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,
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.

0 comments on commit 41c5694

Please sign in to comment.
You can’t perform that action at this time.