10

When handling the errors that occur when trying to create an existing file or trying to use a file that doesn't exist the OSErrors that get thrown have a subclass (FileExistsError, FileNotFoundError). I couldn't find that subclass for the special case when the filename is too long.

The exact error message is:

OSError: [Errno 36] File name too long: 'filename'

I would like to catch the OSError that occurs when the filename is too long, but only when the filename is too long. I do not want to catch other OSErrors that might occur. Is there a way to achieve this?

Edit: I know that I could check the filename against a length but the maximum filename length varies too much depending on the OS and the filesystem and I don't see a "clean" solution that way.

Max Matti
  • 352
  • 1
  • 4
  • 17
  • Possible duplicate of [Python IOError exception when creating a long file](https://stackoverflow.com/questions/4677234/python-ioerror-exception-when-creating-a-long-file) – NuclearPeon Jun 12 '17 at 18:25
  • @NuclearPeon: No. That's windows specific and the answers there do not answer this question. I specified that in the question. – Max Matti Jun 12 '17 at 18:27
  • You can try to get the max filename path, although there is no sure way to do this. Check this link out: https://code.activestate.com/lists/python-list/210662/ - check the length of the filename and notify the user if it's too long. Otherwise a try/except is your best bet as already listed. – NuclearPeon Jun 12 '17 at 18:29
  • I specifically asked how to catch the exact error. I don't want to check the length beforehand because of race conditions and because of inconsistencies of maximum filename lengths (as stated in the question). – Max Matti Jun 12 '17 at 18:34
  • The only other way to narrow down OSError I've seen is to check the 3rd parameter when the exception is thrown. See doc here: https://docs.python.org/2/library/exceptions.html#exceptions.OSError - relevant information: `For exceptions that involve a file system path (such as chdir() or unlink()), the exception instance will contain a third attribute, filename, which is the file name passed to the function.` You might have to come to the conclusion that Python doesn't have a sure way of doing what you want. File a bug. – NuclearPeon Jun 12 '17 at 18:35
  • Found another SO question that might help you out; https://stackoverflow.com/questions/32807560/how-do-i-get-in-python-the-maximum-filesystem-path-length-in-unix - Step 1: Get max length from this question. Step 2: In your OSError `except` block, check the path and filename length. Step 3: If it's above the determined lengths, you have your condition where filesize is too long. Hope this helps. – NuclearPeon Jun 12 '17 at 18:41

2 Answers2

16

Simply check errno attribute of caught exception.

try:
    do_something()
except OSError as exc:
    if exc.errno == 36:
        handle_filename_too_long()
    else:
        raise  # re-raise previously caught exception

For readability you may consider using appropriate constant from errno built-in module instead of hardcoded constant.

Łukasz Rogalski
  • 22,092
  • 8
  • 59
  • 93
8

You can specify just how you want to catch a specific error such as errno.ENAMETOOLONG:

Specific to your question...

try:
    # try stuff
except OSError as oserr:
    if oserr.errno != errno.ENAMETOOLONG:
        # ignore
    else:
        # caught...now what?

Specific to your comments...

try:
    # try stuff
except Exception as err:
    # get the name attribute from the exception class
    errname = type(err).__name__
    # get the errno attribute from the exception class
    errnum = err.errno
    if (errname == 'OSError') and (errnum == errno.ENAMETOOLONG):
        # handle specific to OSError [Errno 36]
    else if (errname == 'ExceptionNameHere' and ...:
        # handle specific to blah blah blah
    .
    .
    .
    else:
        raise # if you want to re-raise; otherwise code your ignore

This will grab all exceptions caused by errors in the try. Then it checks if the __name__ matches any specific exception and any additional conditions you want to specify.

You should know there is no getting around the except if an error is encountered unless you specific a concrete exception.

pstatix
  • 3,611
  • 4
  • 18
  • 40
  • But then I also catch the other `OSError`s that I _specifically_ don't want to catch! – Max Matti Jun 12 '17 at 18:28
  • @MaxMatti To "catch" and error you must "handle" it. The `if/else` sets the conditional that `if` the exceptions `errno` attribute is not equal to (`!=`), you write code to ignore it (however you choose to do so); `else` you've "caught" the right exception...now "handle" it. – pstatix Jun 12 '17 at 18:34
  • I do not want to ignore it! I want to _not_ catch it. I stated that in my question: "I do _not_ want to catch other `OSError`s that might occur. Is there a way to achieve this?" If there's a way to let the previous error propagate further if `errno` is not equal to `errno.ENAMETOOLONG` please add that to your answer. But currently I don't see how you plan to achieve that. – Max Matti Jun 12 '17 at 18:39
  • @MaxMatti Lets say you have two errors: E1 & E2. In your `try/except` you only want to catch is E2 which is the error you are currently focused with. You know the type (`OSError`) but that is not how the `except` statement works. It is a [built-in](https://docs.python.org/2/library/exceptions.html#exceptions.OSError) and as such you have to refer to the `errno` module for its mapped error code. But what if the first error you got was E1? Because `OSError` is a built in, there is no `OSError.ENAMETOOLONG` to specify in the `except`. In both the answers posted, you can move along if not E2. – pstatix Jun 12 '17 at 18:53
  • @MaxMatti Just because you check if the `OSError` is the one you specifically want to deal with doesn't harm the code. Whatever is being executed in the `try` statement is subject to `except` if there is an error encountered. There is no `except OSError as oserr if oserr.errno == errno.ENAMETOOLONG`. – pstatix Jun 12 '17 at 18:57
  • I get the feeling that we're not speaking the same language. If I understand correctly you are catching _any_ `OSError`. I do not want to catch the other errors! Suppose I need to catch `FileExistsError` in the calling function: I can't catch `FileExistsError` in the calling function when I already catch `OSError` like you're suggesting. – Max Matti Jun 12 '17 at 18:59
  • @MaxMatti Check edit, is that more inline with what you were thinking? – pstatix Jun 12 '17 at 19:18
  • Yes, you are catching all Errors, but you are re-raising the ones you aren't interested in handling. In effect, this is the same as not catching the errors you do not want. – Rodney P. Barbati Feb 12 '20 at 18:57