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

Created on 2019-01-09 03:00 by Jordan Hueckstaedt, last changed 2019-01-16 01:36 by eryksun.

Messages (4)
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
History
Date User Action Args
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