[issue8722] Documentation for __getattr__
New submission from Paul Davis <paul.joseph.davis@gmail.com>: The docs for __getattr__ in the object model section could be more specific on the behavior when a @property raises an AttributeError and there is a custom __getattr__ defined. Specifically, it wasn't exactly clear that __getattr__ would be invoked after a @property was found and evaluated. The attached script demonstrates the issue on OS X 10.6, Python 2.6.1 I'm thinking something along the lines of: If the attribute search encounters an AttributeError (perhaps due to a @property raising the error) the search is considered a failure and __getattr__ is invoked. ---------- assignee: docs@python components: Documentation files: example.py messages: 105790 nosy: Paul.Davis, docs@python priority: normal severity: normal status: open title: Documentation for __getattr__ type: feature request versions: Python 2.6 Added file: http://bugs.python.org/file17349/example.py _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Paul Davis <paul.joseph.davis@gmail.com> added the comment: I should mention, in example.py, it wasn't immediately clear that "print f.bing" would actually print instead of raising the AttributeError. As in, I had a property raising an unexpected error that happend to be an AttributeError. If its not an attribute error, the error is not swallowed. I can see the obvious argument for "AttributeError means not found", it just wasn't immediately obvious what was going on. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Changes by Terry J. Reedy <tjreedy@udel.edu>: ---------- versions: +Python 2.7, Python 3.1, Python 3.2 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: The problem with changing 2.7 docs is that object access is different for old- and new-style properties. Does your example work if you remove 'object'? (IE, can old style classes have properties?) For new-style classes, the example behavior is clear if you 1. know that object has a .__getattribute__ method inherited by everything when not overriden and 2. read the doc for that which says that __getattr__ is called whenever a __getattribute__ call raises AttributeError, which it does here by passing through the .get error. For 3.x, I think in 3.3.2. Customizing attribute access, object.__getattr__(self, name) "Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. " might be replaced by "Called when self.__getattribute__(name) raise AttributeError because name is not an instance attribute, not found in the class tree for self, or is a property attribute whose .get() method raises AttributeError." But this does not work for 2.7. ---------- keywords: +patch nosy: +terry.reedy stage: -> needs patch versions: -Python 2.6 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: /raise/raises/ I am pretty sure that when __getattribute__ is bypassed, so is __getattr__. ---------- _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Éric Araujo <merwok@netwok.org> added the comment: Old-style classes can’t have descriptors, hence no properties, static methods, class methods or super. ---------- nosy: +merwok _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Changes by David Stanek <dstanek@dstanek.com>: ---------- nosy: +dstanek _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Changes by Terry J. Reedy <tjreedy@udel.edu>: ---------- versions: +Python 3.3 _______________________________________ Python tracker <report@bugs.python.org> <http://bugs.python.org/issue8722> _______________________________________
Change by Cheryl Sabella <chekat2@gmail.com>: ---------- pull_requests: +4657 stage: needs patch -> patch review _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Change by Cheryl Sabella <chekat2@gmail.com>: ---------- keywords: +needs review -patch versions: +Python 3.6, Python 3.7 -Python 2.7, Python 3.1, Python 3.2, Python 3.3 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: Cheryl, thank you for reviving this, as it is still needed. A slightly revised example better illustrates the claim in the doc revision about when __getattr__ is called. class Foo(object): def __init__(self): self.foo = 1 self.data = {"bing": 4} def __getattr__(self, name): print(f'Getting {name}') return self.data.get(name) @property def bar(self): return 3 @property def bing(self): raise AttributeError("blarg") f = Foo() print('foo', f.foo) print('__str__', f.__str__) print('bar', f.bar) print('bing', f.bing) f.__getattribute__('bing') # prints foo 1 __str__ <method-wrapper '__str__' of Foo object at 0x0000016712378128> bar 3 Getting bing bing 4 Traceback (most recent call last): File "F:\Python\a\tem2.py", line 24, in <module> f.__getattribute__('bing') File "F:\Python\a\tem2.py", line 17, in bing raise AttributeError("blarg") AttributeError: blarg ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Cheryl Sabella <chekat2@gmail.com> added the comment: Terry, Thanks for clarifying with this example. I hadn't tried this when I was playing with the other example. I guess __getattribute__ might be defined by a class, but generally wouldn't be called directly, so the use of __getattr__ and __getattribute__ and the raising of AttributeError is more for an `attributeref` (https://docs.python.org/3/reference/expressions.html#attribute-references) usage? ---------- nosy: +csabella _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: Before testing, let alone documenting, the status quo, I would like to be sure that suppressing the exception is truly the intended behavior. Is there a way to get an annotated listing from git (given which patch, and therefore which person, is responsible for each line)? I will try asking on pydev. Calling __getattr__ on property failure is a behavior of __getattribute__, not of the property, and I would expect object.__getattribute__ to be tested wherever object is, but I have not found such tests. If we do add a test, the best model in test_desc.py looks like `def test_module_subclasses(self):`. The test class would only need __getattr__ and the faulty property. class Foo(object): def __getattr__(self, name): print(f'Getattr {name}') return True @property def bing(self): print('Property bing') raise AttributeError("blarg") f = Foo() print(f.bing) #prints (which would be the log list in a test) Property bing Getattr bing True ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: The behavior and doc for __setattr__ and __delattr__ should also be checked. ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Change by Berker Peksag <berker.peksag@gmail.com>: ---------- keywords: +patch _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Cheryl Sabella <chekat2@gmail.com> added the comment:
Is there a way to get an annotated listing from git (given which patch, and therefore which person, is responsible for each line)?
Which source did you want to look at? In github, if you go into any source, you can click on a line and it gives an option for 'git blame'. That shows the last commit change for each line. You can then click an icon to see a previous commit, etc. For the .rst sources, it's a little different and there is a Blame button at the top of the source that will bring up the same view (commit annotations to the left of the source) as right-clicking. I had posted about git blame a few months ago on core mentorship and Carol Willing mentioned another tool to get all the changes by line. Here was her post: Thanks for passing along the tip for others. You may also find the npm package `git-guilt` useful as it will display all the contributors to a particular line's history. https://www.npmjs.com/package/git-guilt <https://www.npmjs.com/package/git-guilt> ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: Thanks. I normally look at source in my local clone with an editor. I found 'view blame' and 'view blame prior' on github. ---------- keywords: -patch _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Terry J. Reedy <tjreedy@udel.edu> added the comment: Nick, this is about better documenting the behavior of __get(set/del)attr__ in 3.x it relations to AttributeError in a property. I think I understand what it does and think the patch is correct. Could you either review or suggest someone else who better understands core behavior like this? ---------- components: +Interpreter Core nosy: +ncoghlan versions: +Python 3.8 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Nick Coghlan <ncoghlan@gmail.com> added the comment: New changeset d1f318105b8781b01f3507d5cb0fd841b977d5f2 by Nick Coghlan (Cheryl Sabella) in branch 'master': bpo-8722: Document __getattr__ behavior with AttributeError in property (GH-4754) https://github.com/python/cpython/commit/d1f318105b8781b01f3507d5cb0fd841b97... ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>: ---------- keywords: +patch pull_requests: +5368 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Change by miss-islington <mariatta.wijaya+miss-islington@gmail.com>: ---------- pull_requests: +5369 _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Nick Coghlan <ncoghlan@gmail.com> added the comment: New changeset a8c25d1c7f0d395861cc3e10dd01989150891c95 by Nick Coghlan (Miss Islington (bot)) in branch '3.6': [3.6] bpo-8722: Document __getattr__ behavior with AttributeError in property (GH-5542) https://github.com/python/cpython/commit/a8c25d1c7f0d395861cc3e10dd019891508... ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Nick Coghlan <ncoghlan@gmail.com> added the comment: New changeset fea0a12f6bee4a36b2c9533003e33a12c58d2d91 by Nick Coghlan (Miss Islington (bot)) in branch '3.7': [3.7] bpo-8722: Document __getattr__ behavior with AttributeError in property (GH-5543) https://github.com/python/cpython/commit/fea0a12f6bee4a36b2c9533003e33a12c58... ---------- _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
Nick Coghlan <ncoghlan@gmail.com> added the comment: Thanks for the patch Cheryl, and for the reviews Terry! ---------- resolution: -> fixed stage: patch review -> resolved status: open -> closed _______________________________________ Python tracker <report@bugs.python.org> <https://bugs.python.org/issue8722> _______________________________________
participants (8)
-
Berker Peksag
-
Cheryl Sabella
-
David Stanek
-
miss-islington
-
Nick Coghlan
-
Paul Davis
-
Terry J. Reedy
-
Éric Araujo