Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

help() not helpful with enum #62893

Closed
ethanfurman opened this issue Aug 9, 2013 · 24 comments
Closed

help() not helpful with enum #62893

ethanfurman opened this issue Aug 9, 2013 · 24 comments
Assignees

Comments

@ethanfurman
Copy link
Member

BPO 18693
Nosy @warsaw, @ronaldoussoren, @ned-deily, @ethanfurman
Files
  • issue18693.stoneleaf.01.patch
  • issue18693.stoneleaf.02.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/ethanfurman'
    closed_at = <Date 2013-09-16.00:00:20.916>
    created_at = <Date 2013-08-09.01:59:52.108>
    labels = []
    title = 'help() not helpful with enum'
    updated_at = <Date 2013-09-16.00:03:39.857>
    user = 'https://github.com/ethanfurman'

    bugs.python.org fields:

    activity = <Date 2013-09-16.00:03:39.857>
    actor = 'ethan.furman'
    assignee = 'ethan.furman'
    closed = True
    closed_date = <Date 2013-09-16.00:00:20.916>
    closer = 'python-dev'
    components = []
    creation = <Date 2013-08-09.01:59:52.108>
    creator = 'ethan.furman'
    dependencies = []
    files = ['31585', '31763']
    hgrepos = []
    issue_num = 18693
    keywords = ['patch']
    message_count = 24.0
    messages = ['194714', '194717', '194830', '194834', '194864', '194872', '194894', '194916', '194928', '194951', '194961', '196757', '196760', '196762', '196763', '196764', '196781', '196913', '196917', '196924', '197743', '197842', '197843', '197846']
    nosy_count = 6.0
    nosy_names = ['barry', 'ronaldoussoren', 'ned.deily', 'eli.bendersky', 'ethan.furman', 'python-dev']
    pr_nums = []
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue18693'
    versions = ['Python 3.4']

    @ethanfurman
    Copy link
    Member Author

    help(), when used on an enum member or class, returns almost nothing. I suspect the custom __dir__ is at fault, but whatever is causing the problem needs fixing.

    @ethanfurman ethanfurman self-assigned this Aug 9, 2013
    @ethanfurman
    Copy link
    Member Author

    With custom __dir__:

    Help on class Enum in module enum:

    Enum = <enum 'Enum'>

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

    Without custom __dir__:

    Help on class Enum in module enum:

    class Enum(builtins.object)
     |  Generic enumeration.
     |  
     |  Derive from this class to define new enumerations.
     |  
     |  Methods defined here:
     |  
     |  __eq__(self, other)
     |  
     |  __getnewargs__(self)
     |  
     |  __hash__(self)
     |  
     |  __repr__(self)
     |  
     |  __str__(self)
     |  
     |  

    | Static methods defined here:
    |
    | __new__(cls, value)
    |
    | ----------------------------------------------------------------------
    | Data descriptors defined here:
    |
    | __dict__
    | dictionary for instance variables (if defined)
    |
    | __weakref__
    | list of weak references to the object (if defined)
    |
    | name
    | Route attribute access on a class to __getattr__.
    |
    | This is a descriptor, used to define attributes that act differently when
    | accessed through an instance and through a class. Instance access remains
    | normal, but access to an attribute through a class will be routed to the
    | class's __getattr__ method; this is done by raising AttributeError.
    |
    | value
    | Route attribute access on a class to __getattr__.
    |
    | This is a descriptor, used to define attributes that act differently when
    | accessed through an instance and through a class. Instance access remains
    | normal, but access to an attribute through a class will be routed to the
    | class's __getattr__ method; this is done by raising AttributeError.

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

    I'm thinking we should drop the custom __dir__. help() is far more important than not seeing some things with dir().

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Aug 10, 2013

    New changeset 5d417257748e by Ethan Furman in branch 'default':
    Close bpo-18693: __dir__ removed from Enum; help() now helpful.
    http://hg.python.org/cpython/rev/5d417257748e

    @python-dev python-dev mannequin closed this as completed Aug 10, 2013
    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Aug 10, 2013

    Less than two days passed since this issue was opened. No waiting for feedback? No patch? No code review?

    Maybe there's another solution? Personally I find dir() often more useful than help(). Maybe help() can be adapted to behave nicely for classes with custom __dir__ and it could be useful elsewhere?

    Is this such a burning immediate need that we forego all the usual discussion channels?

    @ethanfurman
    Copy link
    Member Author

    Sorry, sorry.

    Long week, felt like more than two days, mild sense of unease and stress due to non-functioning Release Schedule on python.org, and wanting to get Enum used /somewhere/ in the stdlib before 3.4 is locked down.

    Making help() better would be a better solution, especially if we enhanced it to show docstrings on instances.

    I'll see what I can figure out. Feel free to beat me to it. :)

    @ethanfurman ethanfurman reopened this Aug 11, 2013
    @ned-deily
    Copy link
    Member

    Ethan, http://www.python.org/dev/peps/pep-0429/#release-schedule
    TL;DR - no new features after beta 1 (2013-11-24), no non-release-critical bug fixes after rc1 (2014-01-19)

    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Aug 11, 2013

    Ethan, as Ned said (and I think you got this answer in the list before), the real feature cutoff is Beta 1. So we have time until the end of November. Note that even new PEPs (like the statistics one) can go in before that. Even after beta, things that appear to be bugs (like this issue) can usually be fixed before the RCs come. So there is no time pressure whatsoever.

    @ethanfurman
    Copy link
    Member Author

    So what do we want Enum's __dir__ to report?

    Normally we see things like __eq__, __dict__, __getnewargs__, etc.

    For IntEnum there would be __abs__, __floor__, __div__, etc.

    Do we want to worry about those kinds of differences? I think we do.

    And if we do, then we are looking at removing items to make our custom __dir__, and with each release we would have to revisit the blacklist of items we don't want (the tests would catch that for us, but it would still be effort to update the code).

    What if we took what object.__dir__ gave us, then added the Enum members while removing the private, er, non-public data structures?

    In other words, this dir in EnumMeta:

        def __dir__(cls):
            items = set(super().__dir__())
            disgard = set([m for m in items if _is_sunder(m)])
            members = set(cls.__members__)
            return sorted((items | members) ^ disgard)
    
    with this Enum:
    >>> class Color(enum.Enum):
    ...  RED = 1
    ...  BLUE = 2
    ...  GREEN = 3
    ... 

    gives us this result:

    >>> dir(Color)
    ['BLUE', 'GREEN', 'RED', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'value']

    @ethanfurman
    Copy link
    Member Author

    Huh. I just checked help(Color) on my proposed dir and got the two-line, rather useless, response. Perhaps help() is broken with all custom __dir__s.

    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Aug 12, 2013

    Ethan, please revert your commit first. I liked the previous dir. The current one is useless.

    I think you may be right about help, but I didn't dig deep enough to be sure.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Aug 12, 2013

    New changeset 39697dcd97e3 by Ethan Furman in branch 'default':
    bpo-18693: Put custom dir back in place. Will instead look at fixing help().
    http://hg.python.org/cpython/rev/39697dcd97e3

    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Sep 1, 2013

    Do we have enough evidence to open a new bug vs. help() ?

    @ethanfurman
    Copy link
    Member Author

    I've done some more investigation today but I can't tell if the issue is solely in help or if it's some wierd
    interaction between help and _EnumMeta.

    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Sep 2, 2013

    On Sun, Sep 1, 2013 at 5:29 PM, Ethan Furman <report@bugs.python.org> wrote:

    Ethan Furman added the comment:

    I've done some more investigation today but I can't tell if the issue is
    solely in help or if it's some wierd
    interaction between help and _EnumMeta.

    So you can't reproduce it with other classes that have a custom __dir__ ?

    @ethanfurman
    Copy link
    Member Author

    Nope, not yet. And even a simple dummy metaclass with a custom __dir__ worked fine.

    @ethanfurman
    Copy link
    Member Author

    What I know for sure:

    1. if something is added to dir() that does not live in __dict__, help() breaks.

    2. if a certain something or some things are removed from dir(), help() breaks. I'm not yet certain which somethings
      apply here.

    @ronaldoussoren
    Copy link
    Contributor

    That help() is confused by __dir__ is documented in bpo-16938.

    AFAIK help is fairly fragile in its expectations of the attributes present on classes and the correspondence between dir(cls) and list(cls.__dict__), and that is something that could be fixed in pydoc and/or inspect.

    @ethanfurman
    Copy link
    Member Author

    Found it!

    It was a combination of __objclass__ not being defined on the enum mmebers, and the metatype not being searched in the __mro__ by inspect. Thanks, Ronald, for the necessary clues.

    Patch attached.

    I'm not sure if I have the method wowser showing up in the correct dir(). Thoughts?

    @elibendersky
    Copy link
    Mannequin

    elibendersky mannequin commented Sep 4, 2013

    Great, Ethan.

    I'd say the inspect fix has to be reviewed and committed separately. Maybe bpo-16938 is the right place to post the patch for it. Once that's in, we can review/commit the enum parts.

    @ethanfurman
    Copy link
    Member Author

    help() won't really be fixed with the inspect patch. If no objections within a few hours I'll open a new issue for it.

    @ethanfurman
    Copy link
    Member Author

    Okay, here's the patch after the inspect portion was committed in bpo-18929.

    Summary:

    • added __objclass__ to each enum member
    • added __module__ to the class dir
    • aded any extra methods defined to the instance dir
    • changed _RouteClassAttributeToGetattr to use the wrapped doc if it exists
    • added more useful __doc__s to value and name
    • added another test :)

    @ethanfurman
    Copy link
    Member Author

    Two issues still remain:

    • custom behavior, as well as value and name, don't show in help
    • value and name, if defined as enum members, show up as data
      descriptors in help

    =======================================================================================
    --> class Test(enum.Enum):
    ... this = 'that'
    ... these = 'those'
    ... whose = 'mine'
    ... name = 'Python'
    ... value = 'awesome'
    ... def what(self):
    ... return "%s is %s!" % (self.name, self.value)
    ...

    --> dir(Test)
    ['__class__', '__doc__', '__members__', '__module__', 'name', 'these', 'this', 'value', 'whose']

    --> dir(Test.this)
    ['__class__', '__doc__', '__module__', 'name', 'value', 'what']

    --> help(Test)
    Help on Test in module __main__ object:

    class Test(enum.Enum)
     |  Method resolution order:
     |      Test
     |      enum.Enum
     |      builtins.object
     |  
     |  Data and other attributes defined here:
     |  
     |  these = <Test.these: 'those'>
     |  
     |  this = <Test.this: 'that'>
     |  
     |  whose = <Test.whose: 'mine'>
     |  
     |  

    | Data descriptors inherited from enum.Enum:
    |
    | name
    | The name of the Enum member.
    |
    | value
    | The value of the Enum member.
    |
    | ----------------------------------------------------------------------
    | Data descriptors inherited from enum.EnumMeta:
    |
    | __members__
    | Returns a mapping of member name->value.
    |
    | This mapping lists all enum members, including aliases. Note that this
    | is a read-only view of the internal mapping.
    (END)
    =======================================================================================

    At this point, dir() on an Enum member shows what can be done with the member, and dir() on an Enum class shows what can be done with the class.

    I'll create new issues to track changes for inspect and help.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Sep 16, 2013

    New changeset 353ced6ae182 by Ethan Furman in branch 'default':
    Close bpo-18693: Enum is now more help() friendly.
    http://hg.python.org/cpython/rev/353ced6ae182

    @python-dev python-dev mannequin closed this as completed Sep 16, 2013
    @ethanfurman
    Copy link
    Member Author

    Tracking inspect in bpo-19030.

    Tracking help in bpo-19031.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    None yet
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants