Issue #14605: Use None in sys.path_importer_cache to represent no
finder instead of using some (now non-existent) implicit finder.
This commit is contained in:
parent
9e66ac683c
commit
aa93642a35
|
@ -766,17 +766,14 @@ class PathFinder:
|
|||
except ImportError:
|
||||
continue
|
||||
else:
|
||||
raise ImportError("no path hook found for {0}".format(path),
|
||||
path=path)
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def _path_importer_cache(cls, path):
|
||||
"""Get the finder for the path from sys.path_importer_cache.
|
||||
|
||||
If the path is not in the cache, find the appropriate finder and cache
|
||||
it. Because of NullImporter, some finder should be returned. The only
|
||||
explicit fail case is if None is cached but the path cannot be used for
|
||||
the default hook, for which ImportError is raised.
|
||||
it. If no finder is available, store None.
|
||||
|
||||
"""
|
||||
if path == '':
|
||||
|
@ -786,15 +783,6 @@ class PathFinder:
|
|||
except KeyError:
|
||||
finder = cls._path_hooks(path)
|
||||
sys.path_importer_cache[path] = finder
|
||||
else:
|
||||
if finder is None:
|
||||
msg = ("'None' in sys.path_importer_cache[{!r}], so retrying "
|
||||
"finder search; in future versions of Python 'None' "
|
||||
"will represent no finder".format(path))
|
||||
_warnings.warn(msg, ImportWarning)
|
||||
del sys.path_importer_cache[path]
|
||||
finder = cls._path_hooks(path)
|
||||
sys.path_importer_cache[path] = finder
|
||||
return finder
|
||||
|
||||
@classmethod
|
||||
|
@ -804,11 +792,8 @@ class PathFinder:
|
|||
if path is None:
|
||||
path = sys.path
|
||||
for entry in path:
|
||||
try:
|
||||
finder = cls._path_importer_cache(entry)
|
||||
except ImportError:
|
||||
continue
|
||||
if finder:
|
||||
finder = cls._path_importer_cache(entry)
|
||||
if finder is not None:
|
||||
loader = finder.find_module(fullname)
|
||||
if loader:
|
||||
return loader
|
||||
|
@ -1192,6 +1177,5 @@ def _install(sys_module, _imp_module):
|
|||
supported_loaders = [(ExtensionFileLoader, _suffix_list(3), False),
|
||||
(SourceFileLoader, _suffix_list(1), True),
|
||||
(SourcelessFileLoader, _suffix_list(2), True)]
|
||||
sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders),
|
||||
_imp.NullImporter])
|
||||
sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
|
||||
sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder])
|
||||
|
|
|
@ -66,36 +66,18 @@ class FinderTests(unittest.TestCase):
|
|||
self.assertTrue(sys.path_importer_cache[path] is importer)
|
||||
|
||||
def test_empty_path_hooks(self):
|
||||
# Test that if sys.path_hooks is empty a warning is raised and
|
||||
# PathFinder returns None.
|
||||
# tried again (with a warning).
|
||||
# Test that if sys.path_hooks is empty a warning is raised,
|
||||
# sys.path_importer_cache gets None set, and PathFinder returns None.
|
||||
path_entry = 'bogus_path'
|
||||
with util.import_state(path_importer_cache={}, path_hooks=[],
|
||||
path=['bogus_path']):
|
||||
path=[path_entry]):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
self.assertIsNone(machinery.PathFinder.find_module('os'))
|
||||
self.assertNotIn('os', sys.path_importer_cache)
|
||||
self.assertIsNone(sys.path_importer_cache[path_entry])
|
||||
self.assertEqual(len(w), 1)
|
||||
self.assertTrue(issubclass(w[-1].category, ImportWarning))
|
||||
|
||||
def test_path_importer_cache_has_None_continues(self):
|
||||
# Test that having None in sys.path_importer_cache causes the search to
|
||||
# continue.
|
||||
path = '<test path>'
|
||||
module = '<test module>'
|
||||
importer = util.mock_modules(module)
|
||||
with util.import_state(path=['1', '2'],
|
||||
path_importer_cache={'1': None, '2': importer},
|
||||
path_hooks=[imp.NullImporter]):
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter('always')
|
||||
loader = machinery.PathFinder.find_module(module)
|
||||
self.assertTrue(loader is importer)
|
||||
self.assertEqual(len(w), 1)
|
||||
warned = w[0]
|
||||
self.assertTrue(issubclass(warned.category, ImportWarning))
|
||||
self.assertIn(repr(None), str(warned.message))
|
||||
|
||||
def test_path_importer_cache_empty_string(self):
|
||||
# The empty string should create a finder using the cwd.
|
||||
path = ''
|
||||
|
|
|
@ -9,6 +9,7 @@ importers when locating support scripts as well as when importing modules.
|
|||
# Written by Nick Coghlan <ncoghlan at gmail.com>
|
||||
# to implement PEP 338 (Executing Modules as Scripts)
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import imp
|
||||
|
@ -206,11 +207,7 @@ def _get_importer(path_name):
|
|||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
# The following check looks a bit odd. The trick is that
|
||||
# NullImporter throws ImportError if the supplied path is a
|
||||
# *valid* directory entry (and hence able to be handled
|
||||
# by the standard import machinery)
|
||||
importer = imp.NullImporter(path_name)
|
||||
importer = None
|
||||
cache[path_name] = importer
|
||||
return importer
|
||||
|
||||
|
@ -237,7 +234,7 @@ def run_path(path_name, init_globals=None, run_name=None):
|
|||
if run_name is None:
|
||||
run_name = "<run_path>"
|
||||
importer = _get_importer(path_name)
|
||||
if isinstance(importer, imp.NullImporter):
|
||||
if isinstance(importer, (type(None), imp.NullImporter)):
|
||||
# Not a valid sys.path entry, so run the code directly
|
||||
# execfile() doesn't help as we want to allow compiled files
|
||||
code = _get_code_from_file(path_name)
|
||||
|
|
|
@ -14,9 +14,9 @@ Core and Builtins
|
|||
sys.meta_path is found to be empty, raise ImportWarning.
|
||||
|
||||
- Issue #14605: No longer have implicit entries in sys.path_hooks. If
|
||||
sys.path_hooks is found to be empty, a warning will be raised. If None is
|
||||
found in sys.path_importer_cache, a warning is raised and a search on
|
||||
sys.path_hooks is attempted.
|
||||
sys.path_hooks is found to be empty, a warning will be raised. None is now
|
||||
inserted into sys.path_importer_cache if no finder was discovered. This also
|
||||
means imp.NullImporter is no longer implicitly used.
|
||||
|
||||
- Issue #13903: Implement PEP 412. Individual dictionary instances can now share
|
||||
their keys with other dictionaries. Classes take advantage of this to share
|
||||
|
|
|
@ -224,7 +224,7 @@ RunMainFromImporter(wchar_t *filename)
|
|||
if (importer == NULL)
|
||||
goto error;
|
||||
|
||||
if (importer->ob_type == &PyNullImporter_Type) {
|
||||
if (importer == Py_None) {
|
||||
Py_DECREF(argv0);
|
||||
Py_DECREF(importer);
|
||||
return -1;
|
||||
|
|
|
@ -1186,15 +1186,7 @@ get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks,
|
|||
PyErr_Clear();
|
||||
}
|
||||
if (importer == NULL) {
|
||||
importer = PyObject_CallFunctionObjArgs(
|
||||
(PyObject *)&PyNullImporter_Type, p, NULL
|
||||
);
|
||||
if (importer == NULL) {
|
||||
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
|
||||
PyErr_Clear();
|
||||
return Py_None;
|
||||
}
|
||||
}
|
||||
return Py_None;
|
||||
}
|
||||
if (importer != NULL) {
|
||||
int err = PyDict_SetItem(path_importer_cache, p, importer);
|
||||
|
|
2187
Python/importlib.h
2187
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue