Re: [Python-Dev] [Python-checkins] r86566 - in python/branches/py3k: Doc/glossary.rst Doc/library/inspect.rst Lib/inspect.py Lib/test/test_inspect.py Misc/NEWS Misc/python-wing4.wpr

On Sun, Nov 21, 2010 at 1:07 AM, michael.foord <python-checkins@python.org> wrote:
+Fetching attributes statically +------------------------------ + +Both :func:`getattr` and :func:`hasattr` can trigger code execution when +fetching or checking for the existence of attributes. Descriptors, like +properties, will be invoked and :meth:`__getattr__` and :meth:`__getattribute__` +may be called. + +For cases where you want passive introspection, like documentation tools, this +can be inconvenient. `getattr_static` has the same signature as :func:`getattr` +but avoids executing code when it fetches attributes.
This description feels a little strong to me - getattr_static still executes all those things on the metaclass as it retrieves the information it needs to do the "static" lookup. Leaving this original description (which assumes metaclass=type) alone and adding a note near the end of the section to say that metaclass code is still executed might be an improvement. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 20/11/2010 15:21, Nick Coghlan wrote:
On Sun, Nov 21, 2010 at 1:07 AM, michael.foord <python-checkins@python.org> wrote:
+Fetching attributes statically +------------------------------ + +Both :func:`getattr` and :func:`hasattr` can trigger code execution when +fetching or checking for the existence of attributes. Descriptors, like +properties, will be invoked and :meth:`__getattr__` and :meth:`__getattribute__` +may be called. + +For cases where you want passive introspection, like documentation tools, this +can be inconvenient. `getattr_static` has the same signature as :func:`getattr` +but avoids executing code when it fetches attributes. This description feels a little strong to me - getattr_static still executes all those things on the metaclass as it retrieves the information it needs to do the "static" lookup. Leaving this original description (which assumes metaclass=type) alone and adding a note near the end of the section to say that metaclass code is still executed might be an improvement. Can you give an example of code in a metaclass that may be executed by getattr_static? It's not that I don't believe you I just can't think of an example. Looking up the class and the mro are the only two examples I can think of (klass.__mro__ and instance.__class__ - and they are noted in the docs?) but aren't metaclass specific.
Michael
Cheers, Nick.
-- http://www.voidspace.org.uk/ READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies (”BOGUS AGREEMENTS”) that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

On Sun, Nov 21, 2010 at 1:29 AM, Michael Foord <fuzzyman@voidspace.org.uk> wrote:
Can you give an example of code in a metaclass that may be executed by getattr_static? It's not that I don't believe you I just can't think of an example. Looking up the class and the mro are the only two examples I can think of (klass.__mro__ and instance.__class__ - and they are noted in the docs?) but aren't metaclass specific.
The description heavily implies that arbitrary Python code won't be executed by calling getattr_static, and that isn't necessarily true. It's almost certain to be true in the case when the metaclass is type, but can't be guaranteed otherwise. The retrieval of __class__ is a normal lookup on the object, so it can trigger all of the things getattr_static is trying to avoid (unavoidable if you want to support proxy classes at all), and the lookup of __mro__ invokes all of those things on the metaclass. I'll see if I'm still of the same opinion after I sleep on it, but my first impression of the docs was that they slightly oversold the strength of the "doesn't execute arbitrary code" aspect of the new function. The existing caveats were all relating to when getattr() and getattr_static() might give different answers, while the additional caveats I was suggesting related to cases where arbitrary code may still be executed. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 20/11/2010 16:01, Nick Coghlan wrote:
On Sun, Nov 21, 2010 at 1:29 AM, Michael Foord <fuzzyman@voidspace.org.uk> wrote:
Can you give an example of code in a metaclass that may be executed by getattr_static? It's not that I don't believe you I just can't think of an example. Looking up the class and the mro are the only two examples I can think of (klass.__mro__ and instance.__class__ - and they are noted in the docs?) but aren't metaclass specific. The description heavily implies that arbitrary Python code won't be executed by calling getattr_static, and that isn't necessarily true. It's almost certain to be true in the case when the metaclass is type, but can't be guaranteed otherwise.
Given the way that member lookups are done by getattr_static I don't think any assumptions about the metaclass are made. I'm happy to be proven wrong (but would rather fix it than document it as an exception). (Actually we assume the metaclass doesn't use __slots__, but only because it isn't *possible* for a metaclass to use __slots__.)
The retrieval of __class__ is a normal lookup on the object, so it can trigger all of the things getattr_static is trying to avoid (unavoidable if you want to support proxy classes at all), and the lookup of __mro__ invokes all of those things on the metaclass.
__class__ and mro lookup are noted in the docs as being exceptions. We could actually remove the __class__ lookup from the list of exceptions by using type(...) instead of obj.__class__.
I'll see if I'm still of the same opinion after I sleep on it, but my first impression of the docs was that they slightly oversold the strength of the "doesn't execute arbitrary code" aspect of the new function. The existing caveats were all relating to when getattr() and getattr_static() might give different answers, while the additional caveats I was suggesting related to cases where arbitrary code may still be executed. I'm happy to change the wording to make the promise less strong.
All the best, Michael
Cheers, Nick.
-- http://www.voidspace.org.uk/ READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies (”BOGUS AGREEMENTS”) that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

On 20/11/2010 16:06, Michael Foord wrote:
On 20/11/2010 16:01, Nick Coghlan wrote: [snip...]
The retrieval of __class__ is a normal lookup on the object, so it can trigger all of the things getattr_static is trying to avoid (unavoidable if you want to support proxy classes at all), and the lookup of __mro__ invokes all of those things on the metaclass.
__class__ and mro lookup are noted in the docs as being exceptions. We could actually remove the __class__ lookup from the list of exceptions by using type(...) instead of obj.__class__.
Done.
I'll see if I'm still of the same opinion after I sleep on it, but my first impression of the docs was that they slightly oversold the strength of the "doesn't execute arbitrary code" aspect of the new function. The existing caveats were all relating to when getattr() and getattr_static() might give different answers, while the additional caveats I was suggesting related to cases where arbitrary code may still be executed. I'm happy to change the wording to make the promise less strong.
I've also removed the __mro__ exception. This is done with: type.__dict__['__mro__'].__get__(klass) If you can think of any other exceptions then please let me know. Michael
All the best,
Michael
Cheers, Nick.
-- http://www.voidspace.org.uk/ READ CAREFULLY. By accepting and reading this email you agree, on behalf of your employer, to release me from all obligations and waivers arising from any and all NON-NEGOTIATED agreements, licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap, confidentiality, non-disclosure, non-compete and acceptable use policies (”BOGUS AGREEMENTS”) that I have entered into with your employer, its partners, licensors, agents and assigns, in perpetuity, without prejudice to my ongoing rights and privileges. You further represent that you have the authority to release me from any BOGUS AGREEMENTS on behalf of your employer.

On Sun, Nov 21, 2010 at 2:06 AM, Michael Foord <fuzzyman@voidspace.org.uk> wrote:
I'll see if I'm still of the same opinion after I sleep on it, but my first impression of the docs was that they slightly oversold the strength of the "doesn't execute arbitrary code" aspect of the new function. The existing caveats were all relating to when getattr() and getattr_static() might give different answers, while the additional caveats I was suggesting related to cases where arbitrary code may still be executed.
I'm happy to change the wording to make the promise less strong.
Your latest changes may have actually made the stronger wording accurate (I certainly can't think of any loopholes off the top of my head). If you did still want to soften the wording, I'd be inclined to replace the word "avoids" with "minimises" in the appropriate places. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (2)
-
Michael Foord
-
Nick Coghlan