diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2017-10-26 07:41:59 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-26 07:41:59 (GMT) |
commit | 41c56940c6edf3ea169332a6b039b6c8796f0475 (patch) | |
tree | 749eafdafa42c822e8251d045e7853daa148bf13 /Lib | |
parent | 4eaf7f949069882e385f2297c9e70031caf9144c (diff) | |
download | cpython-41c56940c6edf3ea169332a6b039b6c8796f0475.zip cpython-41c56940c6edf3ea169332a6b039b6c8796f0475.tar.gz cpython-41c56940c6edf3ea169332a6b039b6c8796f0475.tar.bz2 |
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.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/importlib/_bootstrap.py | 20 | ||||
-rw-r--r-- | Lib/test/test_importlib/import_/test_fromlist.py | 43 |
2 files changed, 56 insertions, 7 deletions
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 76e1be5..5df6aa0 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -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) diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py index 1464003..018c172 100644 --- a/Lib/test/test_importlib/import_/test_fromlist.py +++ b/Lib/test/test_importlib/import_/test_fromlist.py @@ -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 @@ class HandlingFromlist: 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 @@ class HandlingFromlist: 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 |