classification
Title: No way to specify "File name too long" error in except statement.
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.7
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: Max Staff, eryksun, pitrou, r.david.murray, steven.daprano
Priority: normal Keywords:

Created on 2017-06-12 18:49 by Max Staff, last changed 2017-06-13 17:28 by r.david.murray. This issue is now closed.

Messages (8)
msg295810 - (view) Author: Max Staff (Max Staff) Date: 2017-06-12 18:49
There are different ways to catch exceptions of the type "OSError": By using "except OSError as e:" and then checking the errno or by using "except FileNotFoundError e:" or "except FileExistsError e:" or whatever error one wants to catch. There's no such way for above mentioned error that occurs when a filename is too long for the filesystem/OS.
msg295814 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-06-12 19:25
There appears to be an errno for file name too long, so I presume you are making a feature request for a new exception class.  I believe Antoine tried to strike a balance between the utility of the sub-exceptions and their number, so you'll have to make an argument for its utility.
msg295826 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2017-06-12 20:54
On Unix, you can simply check the errno value:

>>> fn = "x" * 9999999
>>> try: open(fn, "r")
... except OSError as e: exc = e
... 
>>> exc.errno
36
>>> exc.errno == errno.ENAMETOOLONG
True

I don't know about Windows.
msg295827 - (view) Author: Max Staff (Max Staff) Date: 2017-06-12 21:37
Yes I know about the errno. There would be two ways to resolve this:

One way would be by introducing a new exception class which would be nice because it's almost impossible to reliably check the allowed filename length (except for trial and error) and I have quite a few functions where I would want the error to propagate further as long as it's not an ENAMETOOLONG.

The other way would be by introducing a new syntax feature ("except OSError as e if e.errno == errno.ENAMETOOLONG:") but I don't think that that approach is reasonable.
msg295828 - (view) Author: Max Staff (Max Staff) Date: 2017-06-12 21:38
...at least those are the only two ways that I can think of.
msg295831 - (view) Author: Steven D'Aprano (steven.daprano) * (Python committer) Date: 2017-06-13 00:42
I don't understand what you actually are requesting here.

Are you requesting a way to tell whether or not the filename is too long? You've already been told that the way to do that is to check errno, and you say that you already knew that.

exc.errno == errno.ENAMETOOLONG

Or are you asking for a way to find out ahead of time what the maximum filename length will be? You say:

> it's almost impossible to reliably check the allowed filename length

I think that's right: it *is* almost impossible to reliably check the allowed filename length, except by trying it and seeing whether or not you can create the file.

The difficulty here is that there's no one maximum name length, it depends on the file system of the particular device you're accessing. So even if we had this `get_maximum_filename_length` function, and you wrote:

    if len(fname) < get_maximum_filename_length():
        with open(fname) as f: ...

the call to open might *still* fail with ENAMETOOLONG if you happen to be writing to a device or disk with a shorter than expected length.

E.g. FAT32 has a limit of either 8.3 bytes or 255 double-byte Unicode characters depending on the implementation; NTFS and HFS+ have a limit of 255 characters; ext4 has a limit of 255 bytes; Joliet has a limit of 64 characters; etc.

And then there's the question of the maximum allowed path.

So I think the first thing you should do is clarify exactly what it is that you're asking for:

- a way to check whether the exception is ENAMETOOLONG;

- specifically a new sub-exception for that case;

- a constant or function that returns the maximum file name length;

- or the maximum path name length;

- or something else.


But any of these (except the first, which already exists) is a new feature, not a bug fix, to it can only go into 3.7.
msg295851 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2017-06-13 06:09
An exception specifically for ENAMETOOLONG would be limited to Unix systems.

The Windows CRT defines ENAMETOOLONG but doesn't use it. Windows file systems do not return a specific status code for a filename that's too long. Per MS-FSA 2.1.5.1 [1], a request to open a file must fail with STATUS_OBJECT_NAME_INVALID if the name is invalid according to the spec in MS-FSCC 2.1.5 [2] (e.g. max component length cannot exceed 255 characters and may be less). This doesn't tell the caller why the filename is invalid. Anyway, for what it's worth, the Windows API translates this status code to ERROR_INVALID_NAME (0x007B), and the CRT in turn maps the latter to EINVAL.

Also, for versions prior to Windows 10, or Windows 10 without the LongPathsEnabled policy setting, the observed error is more commonly due to path preprocessing in user mode. In this case DOS paths are limited to MAX_PATH (260). The error depends on the called function -- e.g. CreateFileA vs SetCurrentDirectoryA, or calling the [A]NSI vs [W]ide-character version. It could be ERROR_PATH_NOT_FOUND (ENOENT), ERROR_FILENAME_EXCED_RANGE (ENOENT), or ERROR_INVALID_PARAMETER (EINVAL). 

[1]: https://msdn.microsoft.com/en-us/library/ff469536
[2]: https://msdn.microsoft.com/en-us/library/cc422524
msg295943 - (view) Author: R. David Murray (r.david.murray) * (Python committer) Date: 2017-06-13 17:28
Since according to Eryk there's no way to have a reliable cross-platform exception class catching file name to long, I'm rejecting this feature request.
History
Date User Action Args
2017-06-13 17:28:05r.david.murraysetstatus: open -> closed
resolution: rejected
messages: + msg295943

stage: resolved
2017-06-13 06:09:42eryksunsetnosy: + eryksun
messages: + msg295851
2017-06-13 00:42:42steven.dapranosetnosy: + steven.daprano
messages: + msg295831
2017-06-12 21:38:08Max Staffsetmessages: + msg295828
2017-06-12 21:37:26Max Staffsetmessages: + msg295827
2017-06-12 20:54:34pitrousetmessages: + msg295826
2017-06-12 19:25:55r.david.murraysetversions: - Python 2.7, Python 3.3, Python 3.4, Python 3.5, Python 3.6
nosy: + r.david.murray, pitrou

messages: + msg295814

components: + Library (Lib), - IO
type: behavior -> enhancement
2017-06-12 18:49:11Max Staffcreate