This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author andymaier
Recipients andymaier, ethan.furman, terry.reedy
Date 2014-06-06.17:58:05
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1402077496.18.0.0805410075316.issue21561@psf.upfronthosting.co.za>
In-reply-to
Content
Using Ethan's sample code (Thanks!!), I was pointed in the right direction and was able to produce a simple piece of code that reproduces the behavior without depending on enum34, as well as a proposal for a fix in pydoc.py.

The problem can be reproduced with a class that specifies a metaclass that has class attributes and includes these class attributes in its __dir__() result, which causes them to "propagate" as class attributes to the class using that metaclass, at least for the purposes of pydoc.

In the course of the processing within pydoc.py, the tuple returned by inspect.classify_class_attrs() for such class attributes then has None for its class item, which triggers the issue I originally reported (pydoc traps and produces just a dummy help description).

In my original problem with the enum34 module, the same thing happens, just here the "propagated" class attributes include the __members__ list, which is defined as a property. So I do believe that my simple code represents the same error situation as the original enum34 issue.

Because pydoc.py already has its own classify_class_attrs() function that wrappers inspect.classify_class_attrs() for the purpose of treating data descriptors correctly, I think it would be acceptable to continue down the path of fixing it up, just this case for class attributes propagated by the metaclass. That's what my proposed fix does.

Unfortunately, it seems one can attach only one file, so I paste the reproduction code in here, and attach the fixed pydoc.py.

Here is the code that reproduces the issue:
---------------- bug2.py
# Boolean test switches that control whether a class variable of the metaclass
# is added to the dir() result.
# If the fix is not present, then enabling each one triggers the error
# behavior; If none of them is enabled, the error behavior is not triggered.
with_food = True      # Add the 'normal' class attribute 'food'
with_drink = True     # Add the property-based class attribute 'drink'

class FoodMeta(type):
    """Metaclass that adds its class attributes to dir() of classes using it."""

    food = 'ham'      # 'normal' class attribute
    
    @property
    def drink(cls):   # property-based class attribute
        return 'beer'

    def __dir__(cls):
        ret = [name for name in cls.__dict__] # the normal list
        if with_food:
            ret += ['food']
        if with_drink:
            ret += ['drink']
        print "bug2.FoodMeta.__dir__(): return=%s" % (repr(ret),)
        return ret

class Food(object):
    """docstring for Food class"""
    __metaclass__ = FoodMeta

    def diet(self):
        return "no!"

if __name__ == '__main__':
    print "bug2: Calling help(Food):"
    help(Food)

----------------

-> Please review the reproduction code and the fix and let me know how to proceed.

Andy
History
Date User Action Args
2014-06-06 17:58:16andymaiersetrecipients: + andymaier, terry.reedy, ethan.furman
2014-06-06 17:58:16andymaiersetmessageid: <1402077496.18.0.0805410075316.issue21561@psf.upfronthosting.co.za>
2014-06-06 17:58:16andymaierlinkissue21561 messages
2014-06-06 17:58:11andymaiercreate