Commit aa93642a authored by Brett Cannon's avatar Brett Cannon

Issue #14605: Use None in sys.path_importer_cache to represent no

finder instead of using some (now non-existent) implicit finder.
parent 9e66ac68
...@@ -766,17 +766,14 @@ class PathFinder: ...@@ -766,17 +766,14 @@ class PathFinder:
except ImportError: except ImportError:
continue continue
else: else:
raise ImportError("no path hook found for {0}".format(path), return None
path=path)
@classmethod @classmethod
def _path_importer_cache(cls, path): def _path_importer_cache(cls, path):
"""Get the finder for the path from sys.path_importer_cache. """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 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 it. If no finder is available, store None.
explicit fail case is if None is cached but the path cannot be used for
the default hook, for which ImportError is raised.
""" """
if path == '': if path == '':
...@@ -786,15 +783,6 @@ class PathFinder: ...@@ -786,15 +783,6 @@ class PathFinder:
except KeyError: except KeyError:
finder = cls._path_hooks(path) finder = cls._path_hooks(path)
sys.path_importer_cache[path] = finder 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 return finder
@classmethod @classmethod
...@@ -804,11 +792,8 @@ class PathFinder: ...@@ -804,11 +792,8 @@ class PathFinder:
if path is None: if path is None:
path = sys.path path = sys.path
for entry in path: for entry in path:
try: finder = cls._path_importer_cache(entry)
finder = cls._path_importer_cache(entry) if finder is not None:
except ImportError:
continue
if finder:
loader = finder.find_module(fullname) loader = finder.find_module(fullname)
if loader: if loader:
return loader return loader
...@@ -1192,6 +1177,5 @@ def _install(sys_module, _imp_module): ...@@ -1192,6 +1177,5 @@ def _install(sys_module, _imp_module):
supported_loaders = [(ExtensionFileLoader, _suffix_list(3), False), supported_loaders = [(ExtensionFileLoader, _suffix_list(3), False),
(SourceFileLoader, _suffix_list(1), True), (SourceFileLoader, _suffix_list(1), True),
(SourcelessFileLoader, _suffix_list(2), True)] (SourcelessFileLoader, _suffix_list(2), True)]
sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders), sys.path_hooks.extend([FileFinder.path_hook(*supported_loaders)])
_imp.NullImporter])
sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder]) sys.meta_path.extend([BuiltinImporter, FrozenImporter, PathFinder])
...@@ -66,36 +66,18 @@ class FinderTests(unittest.TestCase): ...@@ -66,36 +66,18 @@ class FinderTests(unittest.TestCase):
self.assertTrue(sys.path_importer_cache[path] is importer) self.assertTrue(sys.path_importer_cache[path] is importer)
def test_empty_path_hooks(self): def test_empty_path_hooks(self):
# Test that if sys.path_hooks is empty a warning is raised and # Test that if sys.path_hooks is empty a warning is raised,
# PathFinder returns None. # sys.path_importer_cache gets None set, and PathFinder returns None.
# tried again (with a warning). path_entry = 'bogus_path'
with util.import_state(path_importer_cache={}, path_hooks=[], with util.import_state(path_importer_cache={}, path_hooks=[],
path=['bogus_path']): path=[path_entry]):
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always') warnings.simplefilter('always')
self.assertIsNone(machinery.PathFinder.find_module('os')) 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.assertEqual(len(w), 1)
self.assertTrue(issubclass(w[-1].category, ImportWarning)) 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): def test_path_importer_cache_empty_string(self):
# The empty string should create a finder using the cwd. # The empty string should create a finder using the cwd.
path = '' path = ''
......
...@@ -9,6 +9,7 @@ importers when locating support scripts as well as when importing modules. ...@@ -9,6 +9,7 @@ importers when locating support scripts as well as when importing modules.
# Written by Nick Coghlan <ncoghlan at gmail.com> # Written by Nick Coghlan <ncoghlan at gmail.com>
# to implement PEP 338 (Executing Modules as Scripts) # to implement PEP 338 (Executing Modules as Scripts)
import os import os
import sys import sys
import imp import imp
...@@ -206,11 +207,7 @@ def _get_importer(path_name): ...@@ -206,11 +207,7 @@ def _get_importer(path_name):
except ImportError: except ImportError:
pass pass
else: else:
# The following check looks a bit odd. The trick is that importer = None
# 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)
cache[path_name] = importer cache[path_name] = importer
return importer return importer
...@@ -237,7 +234,7 @@ def run_path(path_name, init_globals=None, run_name=None): ...@@ -237,7 +234,7 @@ def run_path(path_name, init_globals=None, run_name=None):
if run_name is None: if run_name is None:
run_name = "<run_path>" run_name = "<run_path>"
importer = _get_importer(path_name) 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 # Not a valid sys.path entry, so run the code directly
# execfile() doesn't help as we want to allow compiled files # execfile() doesn't help as we want to allow compiled files
code = _get_code_from_file(path_name) code = _get_code_from_file(path_name)
......
...@@ -14,9 +14,9 @@ Core and Builtins ...@@ -14,9 +14,9 @@ Core and Builtins
sys.meta_path is found to be empty, raise ImportWarning. sys.meta_path is found to be empty, raise ImportWarning.
- Issue #14605: No longer have implicit entries in sys.path_hooks. If - 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 sys.path_hooks is found to be empty, a warning will be raised. None is now
found in sys.path_importer_cache, a warning is raised and a search on inserted into sys.path_importer_cache if no finder was discovered. This also
sys.path_hooks is attempted. means imp.NullImporter is no longer implicitly used.
- Issue #13903: Implement PEP 412. Individual dictionary instances can now share - Issue #13903: Implement PEP 412. Individual dictionary instances can now share
their keys with other dictionaries. Classes take advantage of this to share their keys with other dictionaries. Classes take advantage of this to share
......
...@@ -224,7 +224,7 @@ RunMainFromImporter(wchar_t *filename) ...@@ -224,7 +224,7 @@ RunMainFromImporter(wchar_t *filename)
if (importer == NULL) if (importer == NULL)
goto error; goto error;
if (importer->ob_type == &PyNullImporter_Type) { if (importer == Py_None) {
Py_DECREF(argv0); Py_DECREF(argv0);
Py_DECREF(importer); Py_DECREF(importer);
return -1; return -1;
......
...@@ -1186,15 +1186,7 @@ get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks, ...@@ -1186,15 +1186,7 @@ get_path_importer(PyObject *path_importer_cache, PyObject *path_hooks,
PyErr_Clear(); PyErr_Clear();
} }
if (importer == NULL) { if (importer == NULL) {
importer = PyObject_CallFunctionObjArgs( return Py_None;
(PyObject *)&PyNullImporter_Type, p, NULL
);
if (importer == NULL) {
if (PyErr_ExceptionMatches(PyExc_ImportError)) {
PyErr_Clear();
return Py_None;
}
}
} }
if (importer != NULL) { if (importer != NULL) {
int err = PyDict_SetItem(path_importer_cache, p, importer); int err = PyDict_SetItem(path_importer_cache, p, importer);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment