Class introspection by pydoc vs. attributes on meta classes

Hi, Pydoc (and AFAIK loads of other introspection tools as well) currently ignores attributes on metaclasses. I wonder if it would be better to teach pydoc (and possibly inspect as well) about those, and thought it would be better to ask here before starting on a patch. That is, given the following definitions: class Meta (type): def hidden_class(cls): print('H', cls.__name__) class MyObject (metaclass=Meta): @classmethod def public_class(cls): print('P', cls.__name__) Pydoc will show “public_class” as a class method of “MyObject” when you use “help(MyObject)”, but it will not show that there is a method named “hidden_class” that can be called on “MyObject” (but not on instances of that class). That is a problem when “hidden_class” is part of the public interface of the class itself. The issue was found in the context of PyObjC (obviously…): Objective-C classes can and do have instance and class methods of the same name. Those cannot both be a descriptor in the Python proxy class, and that’s why PyObjC uses an metaclass to expose Objective-C class methods to Python code. This works very well, except for some problems with introspection such as the pydoc issue I refer to above. Ronald

On 25 July 2015 at 21:47, Ronald Oussoren <ronaldoussoren@mac.com> wrote:
The main problem with doing that by default is the number of methods and attributes that exist on type:
We *don't* want all of those turning up in the API reported for every class object, so we don't go to the metaclass by default in dir(), and hence not in help() output either. However, if you override __dir__ on the metaclass, you also affect pydoc output on instances of that metaclass:
class C(builtins.object) | Methods inherited from M: | | meta_method() from __main__.M | Metaclass method It actually slightly confuses pydoc (it's assuming any method not defined locally is "inherited", which isn't really the right word for metaclass methods), but it's good enough to get people going in the right direction. And dynamically reverting C back to the default help output to demonstrate that it really is the __dir__ that makes the difference:
class C(builtins.object) | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On 25 July 2015 at 21:47, Ronald Oussoren <ronaldoussoren@mac.com> wrote:
The main problem with doing that by default is the number of methods and attributes that exist on type:
We *don't* want all of those turning up in the API reported for every class object, so we don't go to the metaclass by default in dir(), and hence not in help() output either. However, if you override __dir__ on the metaclass, you also affect pydoc output on instances of that metaclass:
class C(builtins.object) | Methods inherited from M: | | meta_method() from __main__.M | Metaclass method It actually slightly confuses pydoc (it's assuming any method not defined locally is "inherited", which isn't really the right word for metaclass methods), but it's good enough to get people going in the right direction. And dynamically reverting C back to the default help output to demonstrate that it really is the __dir__ that makes the difference:
class C(builtins.object) | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia
participants (2)
-
Nick Coghlan
-
Ronald Oussoren