STR:
-
Open the NVDA Python console.
-
Type the following:
class C(object):
@property
def p(self):
log.info("p", stack_info=True)
C().p
-
Look at the log.
You get something like this:
File "<console>", line 4, in p
File "C:\Python27\lib\logging\__init__.py", line 1159, in info
self._log(INFO, msg, args, **kwargs)
File "logHandler.py", line 91, in _log
codepath=getCodePath(f)
File "logHandler.py", line 55, in getCodePath
attr=getattr(arg0,funcName)
File "<console>", line 4, in p
File "C:\Python27\lib\logging\__init__.py", line 1159, in info
self._log(INFO, msg, args, **kwargs)
File "logHandler.py", line 91, in _log
codepath=getCodePath(f)
File "logHandler.py", line 55, in getCodePath
attr=getattr(arg0,funcName)
File "<console>", line 4, in p
File "C:\Python27\lib\logging\__init__.py", line 1159, in info
self._log(INFO, msg, args, **kwargs)
File "logHandler.py", line 91, in _log
codepath=getCodePath(f)
File "logHandler.py", line 55, in getCodePath
attr=getattr(arg0,funcName)
...
And so the recursion continues. The reason is that logHandler.getCodePath retrieves the p attribute from the class, but in this case, the attribute is a property. Retrieving the property runs the logging code again... and thus begins the infinite recursion. I'm pretty sure we exceed maximum recursion depth, but getCodePath catches that exception.
As to why we aren't hitting this all the time, I think this only applies to properties which use decorators. In contrast, most of our properties use the _get_foo magic methods, and in that case, the function name from the code attribute will point at the _get_foo method, not the foo property itself. So, we've just been lucky enough not to log within a decorated property.
We should be able to solve this by trying to retrieve the attribute from the class first. If that attribute has a __get__ attribute, we know it's a descriptor (usually a property). If so, we shouldn't try to retrieve the attribute from the instance.
STR:
Open the NVDA Python console.
Type the following:
Look at the log.
You get something like this:
And so the recursion continues. The reason is that
logHandler.getCodePathretrieves thepattribute from the class, but in this case, the attribute is a property. Retrieving the property runs the logging code again... and thus begins the infinite recursion. I'm pretty sure we exceed maximum recursion depth, butgetCodePathcatches that exception.As to why we aren't hitting this all the time, I think this only applies to properties which use decorators. In contrast, most of our properties use the
_get_foomagic methods, and in that case, the function name from the code attribute will point at the_get_foomethod, not thefooproperty itself. So, we've just been lucky enough not to log within a decorated property.We should be able to solve this by trying to retrieve the attribute from the class first. If that attribute has a
__get__attribute, we know it's a descriptor (usually a property). If so, we shouldn't try to retrieve the attribute from the instance.