This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author gerph
Recipients gerph
Date 2017-08-02.19:57:43
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1501703863.51.0.936615948464.issue31111@psf.upfronthosting.co.za>
In-reply-to
Content
Whilst debugging a problem in some of my code (which turned out to be a misspelt filename), I found that I could not access one of the properties of the FileNotFoundError object.

Essentially, if you get a 'FileNotFoundError' for opening a file that does not exist, you expect to be able to enumerate the attributes on that object. And if you try to access them, that they be accessible.
However, there is an attribute - 'characters_written' - which claims to be present according to 'dir()' but not according to 'hasattr()' and trying to access it with 'getattr()' confirms that it's not really there.

Looking at the documentation at https://docs.python.org/3/library/exceptions.html#OSError I see that it is a subclass of OSError(), and that the BlockingIOError can have this attribute. But none of the other OSError subclasses are documented as having the attribute.

It is still reasonable that any attribute access could generate another exception (including an AttributeError), as their implementation may have other issues, but I do not feel that this applies here, as this is an internal exception object that probably ought not to have an issue.

Since 'characters_written' doesn't seem to have any meaning in the context of 'FileNotFound', it seems like it's an oversight from the other exception subclass.

What I conclude from this is that the documentation, hasattr() and getattr() are correct, but dir() is acting wrongly. Principle of least surprise also suggests that having inconsistent returns from these functions probably isn't correct. I guess it could be the other way around, and the documentation, hasattr and getattr could be returning incorrectly, but that feels like something of a stretch.

I would wonder if the other OSError subclasses also suffer from this extraneous attribute name, and that it's been implemented at the wrong level, but I have no evidence to suggest that's the case (just that that's something I'd probably look at if I had the time).

Reproduction code:

----
#!/usr/bin/python3.6
##
# Demonstrate oddity of FileNotFoundError.
#

try:
    fh = open('/nothing/at/all', 'r')
except Exception as ex:
    print("Exception: {}".format(ex))
    for attrname in dir(ex):
        if attrname.startswith('__'):
            # Ignore dunders for the sake of brevity
            continue

        print("  Attribute name: {}".format(attrname))
        if not hasattr(ex, attrname):
            print("         hasattr: False - surprising!")
        print("           value: {}".format(getattr(ex, attrname)))
----

On 3.6 this generates:

----
Charles@charlesmbp:~/Coding/terraspock-develop (develop)$ python python3.6.2-filenotfound.py 
Exception: [Errno 2] No such file or directory: '/nothing/at/all'
  Attribute name: args
           value: (2, 'No such file or directory')
  Attribute name: characters_written
         hasattr: False - surprising!
Traceback (most recent call last):
  File "python3.6.2-filenotfound.py", line 7, in <module>
    fh = open('/nothing/at/all', 'r')
FileNotFoundError: [Errno 2] No such file or directory: '/nothing/at/all'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "python3.6.2-filenotfound.py", line 18, in <module>
    print("           value: {}".format(getattr(ex, attrname)))
AttributeError: characters_written
----

On 2.7 this works fine, but I've not tested the other 3.x series versions as I don't have them to hand.

Testing performed on macOS using Python 3.6.2.

I find it hard to think that this is intended behaviour, but whether it's something that debugging tools (and users) would expect or find useful I don't know.
History
Date User Action Args
2017-08-02 19:57:43gerphsetrecipients: + gerph
2017-08-02 19:57:43gerphsetmessageid: <1501703863.51.0.936615948464.issue31111@psf.upfronthosting.co.za>
2017-08-02 19:57:43gerphlinkissue31111 messages
2017-08-02 19:57:43gerphcreate