
Part of the fix for issue #18693 is to fix inspect to look in the metaclass for class attributes (http://bugs.python.org/issue18929). In inspect.py in function get_mro() we can either add the metaclass unconditionally, or only if it is not 'type'. If we add unconditionally, then help() adds the following: class A(builtins.object) | Hello and goodbye + | + | Method resolution order: + | A + | builtins.object + | builtins.type | | Methods defined here: Do we want that, or should we just add the metaclass if it is not 'type'? -- ~Ethan~

Hi Ethan, Are you suggesting that inspect.get_mro(A) would return (A, object, type)? That seems very wrong to me. If the goal is to fix `inspect.classify_class_attrs()`, then this function only needs a specific fix, along the lines of looking in `get_mro(A) + get_mro(type(A))`. (A more minor issue is that the bug report suggests `... + (type(A),)` only, but that's wrong: Python will also look in all the base classes of type(A).) "Fixing" inspect.get_mro() as suggested would break a lot of other usages of it. A bientôt, Armin.

On 09/06/2013 07:47 AM, Armin Rigo wrote:
Are you suggesting that inspect.getmro(A) would return (A, object, type)? That seems very wrong to me.
Currently, `inspect.getmro(A)` returns `(A, object)`. Considering that Python actually will look in A's metaclass to find a class attribute, I think returning `(A, object, type(A)` is appropriate: ================================================================================= Python 3.4.0a1+ (default:61ca4732399b+, Sep 4 2013, 22:28:04) [GCC 4.7.3] on linux Type "help", "copyright", "credits" or "license" for more information. --> class Meta(type): ... meta_attr = 42 ... --> class Class(metaclass=Meta): ... cls_attr = 'Vitamin-soaked towel' ... def __init__(self): ... self.inst_attr = 'dolphins' ... --> test = Class() --> test.inst_attr 'dolphins' --> test.cls_attr 'Vitamin-soaked towel' --> test.meta_attr Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Class' object has no attribute 'meta_attr' --> Class.cls_attr 'Vitamin-soaked towel' --> Class.meta_attr 42 --> import inspect --> inspect.getmro(Class) # with patch in place (<class '__main__.Class'>, <class 'object'>, <class '__main__.Meta'>) =================================================================================
If the goal is to fix `inspect.classify_class_attrs()`, then this function only needs a specific fix, along the lines of looking in `getmro(A) + getmro(type(A))`. (A more minor issue is that the bug report suggests `... + (type(A),)` only, but that's wrong: Python will also look in all the base classes of type(A).)
Good point. Will incorporate that into the final fix, whichever way it ends up.
"Fixing" inspect.getmro() as suggested would break a lot of other usages of it.
Any examples? -- ~Ethan~

On Fri, 06 Sep 2013 08:14:09 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 07:47 AM, Armin Rigo wrote:
Are you suggesting that inspect.getmro(A) would return (A, object, type)? That seems very wrong to me.
Currently, `inspect.getmro(A)` returns `(A, object)`.
Which matches A.__mro__. EOD, I think. --David

On 09/06/2013 08:44 AM, R. David Murray wrote:
On Fri, 06 Sep 2013 08:14:09 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 07:47 AM, Armin Rigo wrote:
Are you suggesting that inspect.getmro(A) would return (A, object, type)? That seems very wrong to me.
Currently, `inspect.getmro(A)` returns `(A, object)`.
Which matches A.__mro__. EOD, I think.
I hope not, because currently this leaves a hole in the introspection of class attributes. Is __mro__ aimed primarily at instances and not classes? That seems to be how it works. In which case, do we need another __mmro__ (or __cmro__ or ...) to handle the mro of classes themselves? For the short term I can restrict the change to inspect.classify_class_attrs(). -- ~Ethan~

On Fri, 06 Sep 2013 08:59:02 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 08:44 AM, R. David Murray wrote:
On Fri, 06 Sep 2013 08:14:09 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 07:47 AM, Armin Rigo wrote:
Are you suggesting that inspect.getmro(A) would return (A, object, type)? That seems very wrong to me.
Currently, `inspect.getmro(A)` returns `(A, object)`.
Which matches A.__mro__. EOD, I think.
I hope not, because currently this leaves a hole in the introspection of class attributes.
Is __mro__ aimed primarily at instances and not classes? That seems to be how it works. In which case, do we need another __mmro__ (or __cmro__ or ...) to handle the mro of classes themselves?
Or maybe just a new inspect function?
For the short term I can restrict the change to inspect.classify_class_attrs().
Sounds like the best course. --David

On 09/06/2013 09:37 AM, R. David Murray wrote:
On Fri, 06 Sep 2013 08:59:02 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
For the short term I can restrict the change to inspect.classify_class_attrs().
Sounds like the best course.
There is one other function in inspect that calls getmro(): def getmembers(object, predicate=None): """Return all members of an object as (name, value) pairs sorted by name. Optionally, only return members that satisfy a given predicate.""" if isclass(object): mro = (object,) + getmro(object) Should I add `+ getmro(type(object))` here as well? -- ~Ethan~

On Fri, 06 Sep 2013 10:01:32 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 09:37 AM, R. David Murray wrote:
On Fri, 06 Sep 2013 08:59:02 -0700, Ethan Furman <ethan@stoneleaf.us> wrote:
For the short term I can restrict the change to inspect.classify_class_attrs().
Sounds like the best course.
There is one other function in inspect that calls getmro():
def getmembers(object, predicate=None): """Return all members of an object as (name, value) pairs sorted by name. Optionally, only return members that satisfy a given predicate.""" if isclass(object): mro = (object,) + getmro(object)
Should I add `+ getmro(type(object))` here as well?
Not unless you want to void the warranty on the docs :) Note getmembers() does not return metaclass attributes when the argument is a class (this behavior is inherited from the dir() function). --David

On Fri, 06 Sep 2013 08:14:09 -0700 Ethan Furman <ethan@stoneleaf.us> wrote:
On 09/06/2013 07:47 AM, Armin Rigo wrote:
Are you suggesting that inspect.getmro(A) would return (A, object, type)? That seems very wrong to me.
Currently, `inspect.getmro(A)` returns `(A, object)`.
Considering that Python actually will look in A's metaclass to find a class attribute, I think returning `(A, object, type(A)` is appropriate:
No, I don't think it's appropriate at all. You are conflating two things: - the instance lookup of an attribute (on A, here) - the class lookup when the instance lookup fails (on type, here) Both lookups obey the same MRO rules, it just happens that the second lookup uses a trivial MRO:
type.__mro__ (<class 'type'>, <class 'object'>)
Regards Antoine.
participants (4)
-
Antoine Pitrou
-
Armin Rigo
-
Ethan Furman
-
R. David Murray