Issue #22834: Have import suppress FileNotFoundError when the current

working directory no longer exists.

Thanks to Martin Panter for the bug report.
This commit is contained in:
Brett Cannon 2014-11-21 12:19:28 -05:00
parent 8314690a26
commit b6e2556d8f
7 changed files with 1043 additions and 1001 deletions

View file

@ -794,6 +794,11 @@ find and load modules.
.. versionadded:: 3.4
.. versionchanged:: 3.5
If the current working directory -- represented by an empty string --
is no longer valid then ``None`` is returned but no value is cached
in :data:`sys.path_importer_cache`.
.. classmethod:: find_module(fullname, path=None)
A legacy wrapper around :meth:`find_spec`.

View file

@ -754,6 +754,15 @@ hook` callables on :data:`sys.path_hooks`, then the following protocol is used
to ask the finder for a module spec, which is then used when loading the
module.
The current working directory -- denoted by an empty string -- is handled
slightly differently from other entries on :data:`sys.path`. First, if the
current working directory is found to not exist, no value is stored in
:data:`sys.path_importer_cache`. Second, the value for the current working
directory is looked up fresh for each module lookup. Third, the path used for
:data:`sys.path_importer_cache` and returned by
:meth:`importlib.machinery.PathFinder.find_spec` will be the actual current
working directory and not the empty string.
Path entry finder protocol
--------------------------

View file

@ -436,6 +436,12 @@ Changes in the Python API
bytes-like object is required, not 'sometype'". (Contributed by Ezio Melotti
in :issue:`16518`.)
* If the current directory is set to a directory that no longer exists then
:exc:`FileNotFoundError` will no longer be raised and instead
:meth:`~importlib.machinery.FileFinder.find_spec` will return ``None``
**without** caching ``None`` in :data:`sys.path_importer_cache` which is
different than the typical case (:issue:`22834`).
Changes in the C API
--------------------

View file

@ -1825,7 +1825,12 @@ def _path_importer_cache(cls, path):
"""
if path == '':
path = _os.getcwd()
try:
path = _os.getcwd()
except FileNotFoundError:
# Don't cache the failure as the cwd can easily change to
# a valid directory later on.
return None
try:
finder = sys.path_importer_cache[path]
except KeyError:

View file

@ -5,6 +5,7 @@
import os
import sys
import tempfile
from types import ModuleType
import unittest
import warnings
@ -158,6 +159,17 @@ def find_spec(self, fullname, target=None):
got = self.machinery.PathFinder.find_spec('whatever', [path])
self.assertEqual(got, success_finder.spec)
def test_deleted_cwd(self):
# Issue #22834
self.addCleanup(os.chdir, os.getcwd())
with tempfile.TemporaryDirectory() as path:
os.chdir(path)
with util.import_state(path=['']):
# Do not want FileNotFoundError raised.
self.assertIsNone(self.machinery.PathFinder.find_spec('whatever'))
(Frozen_FinderTests,
Source_FinderTests

View file

@ -10,6 +10,9 @@ Release date: TBA
Core and Builtins
-----------------
- Issue #22834: If the current working directory ends up being set to a
non-existent directory then import will no longer raise FileNotFoundError.
- Issue #22869: Move the interpreter startup & shutdown code to a new
dedicated pylifecycle.c module
@ -235,7 +238,7 @@ Library
- Issue #22776: Brought excluded code into the scope of a try block in
SysLogHandler.emit().
- Issue #22665: Add missing get_terminal_size and SameFileError to
shutil.__all__.

File diff suppressed because it is too large Load diff