New submission from Charles Ferguson:

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.

----------
components: Library (Lib)
messages: 299669
nosy: gerph
priority: normal
severity: normal
status: open
title: Python 3.6 has an inaccessible attribute on FileNotFoundError
type: behavior
versions: Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue31111>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to