classification
Title: pathlib.Path.exists() on non-existent drive raises WinError instead of returning False
Type: behavior Stage: resolved
Components: Library (Lib), Windows Versions: Python 3.8, Python 3.7
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: steve.dower Nosy List: Jordan Hueckstaedt, eryksun, miss-islington, paul.moore, pitrou, steve.dower, tim.golden, zach.ware
Priority: normal Keywords: patch, patch, patch

Created on 2019-01-09 03:00 by Jordan Hueckstaedt, last changed 2019-02-04 07:33 by steve.dower. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 11746 merged steve.dower, 2019-02-03 00:25
PR 11746 merged steve.dower, 2019-02-03 00:25
PR 11746 merged steve.dower, 2019-02-03 00:25
PR 11752 merged miss-islington, 2019-02-04 07:08
PR 11752 merged miss-islington, 2019-02-04 07:08
PR 11752 merged miss-islington, 2019-02-04 07:08
Messages (6)
msg333275 - (view) Author: Jordan Hueckstaedt (Jordan Hueckstaedt) Date: 2019-01-09 03:00
Tested in 3.7.0 on windows 10.
This looks related to https://bugs.python.org/issue22759


>>> import pathlib
>>> pathlib.Path(r"E:\Whatever\blah.txt").exists()  # This drive doesn't exist
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\jordanhu\AppData\Local\Continuum\anaconda2\envs\py3\lib\pathlib.py", line 1318, in exists
    self.stat()
  File "C:\Users\jordanhu\AppData\Local\Continuum\anaconda2\envs\py3\lib\pathlib.py", line 1140, in stat
    return self._accessor.stat(self)
PermissionError: [WinError 21] The device is not ready: 'E:\\Whatever\\blah.txt'
>>> pathlib.Path(r"C:\Whatever\blah.txt").exists() # This drive exists
False
msg333724 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2019-01-15 18:25
In issue 22759 there was some logic applied for which errors to forward rather than hide.

I'm inclined to agree that this one should be hidden, but it may have to be done by checking the winerror field rather than the exception type, since other PermissionErrors may mean the file is guaranteed to exist (but you can't touch it) or that the path exists up to the point where you are not allowed to see.

I'd happily argue that since these permissions indicate that the file does not exist *for the current user* and so they should be swallowed more broadly, but I'll let Antoine make the call.
msg333729 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2019-01-15 18:52
I think exists() should simply return False here.  There's no reason a non-existing drive should fail differently than a non-existing parent directory.
msg333748 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2019-01-16 01:36
> There's no reason a non-existing drive should fail differently than 
> a non-existing parent directory.

The drive exists (or should) if we're getting ERROR_NOT_READY (21). It's likely a removable media device, such as an optical disc or card reader, and there's no media in the device. 

If a logical drive isn't defined at all, we should get ERROR_PATH_NOT_FOUND (from the NT status value STATUS_OBJECT_PATH_NOT_FOUND). This gets mapped to the errno value ENOENT, which is already handled. For example:

    >>> os.stat('Q:/')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FileNotFoundError: [WinError 3] The system cannot find the path specified: 'Q:/'

    >>> pathlib.Path('Q:/whatever/blah.txt').exists()
    False

Similarly if a UNC 'drive' doesn't exist, we should get ERROR_BAD_NET_NAME (from NT STATUS_BAD_NETWORK_NAME), which is also mapped to ENOENT:

    >>> os.stat('//some/where')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    FileNotFoundError: [WinError 67] The network name cannot be found: '//some/where'

    >>> pathlib.Path('//some/where/whatever/blah.txt').exists()
    False
msg334811 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2019-02-04 07:08
New changeset 2f6fae6e510dba653391cb510a2aca8322eec03b by Steve Dower in branch 'master':
bpo-35692: pathlib no longer raises when checking file and directory existence on drives that are not ready (GH-11746)
https://github.com/python/cpython/commit/2f6fae6e510dba653391cb510a2aca8322eec03b
msg334814 - (view) Author: miss-islington (miss-islington) Date: 2019-02-04 07:27
New changeset 69af4395a25481e9de4009c816b6d1f032a2d8eb by Miss Islington (bot) in branch '3.7':
bpo-35692: pathlib no longer raises when checking file and directory existence on drives that are not ready (GH-11746)
https://github.com/python/cpython/commit/69af4395a25481e9de4009c816b6d1f032a2d8eb
History
Date User Action Args
2019-02-04 07:33:25steve.dowersetkeywords: patch, patch, patch
status: open -> closed
resolution: fixed
stage: patch review -> resolved
2019-02-04 07:27:39miss-islingtonsetnosy: + miss-islington
messages: + msg334814
2019-02-04 07:09:14miss-islingtonsetpull_requests: + pull_request11688
2019-02-04 07:09:01miss-islingtonsetpull_requests: + pull_request11687
2019-02-04 07:08:47miss-islingtonsetpull_requests: + pull_request11686
2019-02-04 07:08:22steve.dowersetmessages: + msg334811
2019-02-03 00:26:12steve.dowersetkeywords: patch, patch, patch
assignee: steve.dower
2019-02-03 00:25:58steve.dowersetkeywords: + patch
stage: needs patch -> patch review
pull_requests: + pull_request11674
2019-02-03 00:25:44steve.dowersetkeywords: + patch
stage: needs patch -> needs patch
pull_requests: + pull_request11673
2019-02-03 00:25:31steve.dowersetkeywords: + patch
stage: needs patch -> needs patch
pull_requests: + pull_request11672
2019-01-16 01:36:13eryksunsetmessages: + msg333748
2019-01-15 18:52:55pitrousetstage: needs patch
messages: + msg333729
versions: + Python 3.8
2019-01-15 18:25:27steve.dowersetnosy: + pitrou
messages: + msg333724
2019-01-09 19:17:24brett.cannonsetnosy: + paul.moore, tim.golden, zach.ware, steve.dower
components: + Library (Lib), Windows
2019-01-09 03:18:26xtreaksetnosy: + eryksun
2019-01-09 03:00:15Jordan Hueckstaedtcreate