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

Rlcompleter.Completer does not use __dir__ magic method #49312

Closed
carlj mannequin opened this issue Jan 26, 2009 · 10 comments
Closed

Rlcompleter.Completer does not use __dir__ magic method #49312

carlj mannequin opened this issue Jan 26, 2009 · 10 comments
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@carlj
Copy link
Mannequin

carlj mannequin commented Jan 26, 2009

BPO 5062
Nosy @birkenfeld, @merwok, @vadmium
Superseder
  • bpo-25590: tab-completition on instances repeatedly accesses attribute/descriptors values
  • Files
  • rlcompleter.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 = None
    closed_at = <Date 2016-05-13.13:20:23.820>
    created_at = <Date 2009-01-26.01:28:57.402>
    labels = ['type-bug', 'library']
    title = 'Rlcompleter.Completer does not use __dir__ magic method'
    updated_at = <Date 2016-05-13.13:20:46.856>
    user = 'https://bugs.python.org/carlj'

    bugs.python.org fields:

    activity = <Date 2016-05-13.13:20:46.856>
    actor = 'martin.panter'
    assignee = 'docs@python'
    closed = True
    closed_date = <Date 2016-05-13.13:20:23.820>
    closer = 'martin.panter'
    components = ['Library (Lib)']
    creation = <Date 2009-01-26.01:28:57.402>
    creator = 'carlj'
    dependencies = []
    files = ['12872']
    hgrepos = []
    issue_num = 5062
    keywords = ['patch']
    message_count = 10.0
    messages = ['80556', '80615', '80619', '80623', '80625', '80626', '80627', '80630', '221649', '265474']
    nosy_count = 6.0
    nosy_names = ['georg.brandl', 'ggenellina', 'eric.araujo', 'carlj', 'BreamoreBoy', 'martin.panter']
    pr_nums = []
    priority = 'normal'
    resolution = 'duplicate'
    stage = 'resolved'
    status = 'closed'
    superseder = '25590'
    type = 'behavior'
    url = 'https://bugs.python.org/issue5062'
    versions = ['Python 3.6']

    @carlj
    Copy link
    Mannequin Author

    carlj mannequin commented Jan 26, 2009

    The documentation at http://docs.python.org/library/rlcompleter.html
    claims that

    Completer.complete(text, state)¶

    Return the state*th completion for *text.

    If called for text that doesn’t include a period character ('.'), it
    will complete from names currently defined in __main__, __builtin__ and
    keywords (as defined by the keyword module).

    If called for a dotted name, it will try to evaluate anything without
    obvious side-effects (functions will not be evaluated, but it can
    generate calls to __getattr__()) up to the last part, and find matches
    for the rest via the dir() function. Any exception raised during the
    evaluation of the expression is caught, silenced and None is returned.

    In other words, it claims to use dir(obj) as part of the tab completion
    process. This is not true (using Python 2.6.1 on OS X):

    >>> class B(object):
    ...  def __dir__(self): return dir(u"") #Makes B objects look like strings
    ...
    >>> b = B()
    >>> dir(b)
    ['__add__', '__class__', '__contains__', '__delattr__', '__doc__',
    '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__',
    '__getnewargs__', '__getslice__', '__gt__', '__hash__', '__init__',
    '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__',
    '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__',
    '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
    '_formatter_field_name_split', '_formatter_parser', 'capitalize',
    'center', 'count', 'decode', 'encode', 'endswith', 'expandtabs', 'find',
    'format', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit',
    'islower', 'isnumeric', 'isspace', 'istitle', 'isupper', 'join',
    'ljust', 'lower', 'lstrip', 'partition', 'replace', 'rfind', 'rindex',
    'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines',
    'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
    >>> c = rlcompleter.Completer()
    >>> c.complete("b.", 0) #Notice that it does NOT return __add__
    u'b.__class__('
    >>> c.matches #Notice that this list is completely different from the
    list given by dir(b)
    [u'b.__class__(', u'b.__delattr__(', u'b.__doc__', u'b.__format__(',
    u'b.__getattribute__(', u'b.__hash__(', u'b.__init__(', u'b.__new__(',
    u'b.__reduce__(', u'b.__reduce_ex__(', u'b.__repr__(',
    u'b.__setattr__(', u'b.__sizeof__(', u'b.__str__(',
    u'b.__subclasshook__(', u'b.__class__(', u'b.__class__(',
    u'b.__delattr__(', u'b.__dict__', u'b.__dir__(', u'b.__doc__',
    u'b.__format__(', u'b.__getattribute__(', u'b.__hash__(',
    u'b.__init__(', u'b.__module__', u'b.__new__(', u'b.__reduce__(',
    u'b.__reduce_ex__(', u'b.__repr__(', u'b.__setattr__(',
    u'b.__sizeof__(', u'b.__str__(', u'b.__subclasshook__(',
    u'b.__weakref__', u'b.__class__(', u'b.__delattr__(', u'b.__doc__',
    u'b.__format__(', u'b.__getattribute__(', u'b.__hash__(',
    u'b.__init__(', u'b.__new__(', u'b.__reduce__(', u'b.__reduce_ex__(',
    u'b.__repr__(', u'b.__setattr__(', u'b.__sizeof__(', u'b.__str__(',
    u'b.__subclasshook__(']

    Suggested course of action:

    • Change the documentation for Python 2.6/3.0.
    • Update Completer to use __dir__ in Pythons 2.7/3.1 and revert the
      documentation.

    See
    http://mail.python.org/pipermail/python-dev/2009-January/thread.html#85471

    @carlj carlj mannequin assigned birkenfeld Jan 26, 2009
    @carlj carlj mannequin added docs Documentation in the Doc dir extension-modules C modules in the Modules dir type-bug An unexpected behavior, bug, or error labels Jan 26, 2009
    @ggenellina
    Copy link
    Mannequin

    ggenellina mannequin commented Jan 27, 2009

    This is not a bug in rlcompleter; __dir__ is returning bogus items, and
    rlcompleter checks whether there exist actually an attribute with such
    name.

    Defining __getattr__ (or __getattribute__) and a matching __dir__ works
    fine:

    >>> class B(object):
    ...   def __dir__(self):
    ...     return dir(object) + ["xa","xb","xc"]
    ...   def __getattr__(self, name):
    ...     if name in ["xa","xb","xc"]:
    ...       return None
    ...     raise AttributeError, name
    ...
    >>> b = B()
    >>> import rlcompleter
    >>> c = rlcompleter.Completer()
    >>> c.complete("b.", 0)
    'b.__class__('
    >>> c.matches
    ['b.__class__(', 'b.__delattr__(', 'b.__doc__', 'b.__format__(', 
    'b.__getattribute__(', 
    ...
    'b.xa', 'b.xb', 'b.xc', 'b.__class__(', 'b.__class__(', 
    ...]
    >>> c.complete("b.x", 0)
    'b.xa'
    >>> c.matches
    ['b.xa', 'b.xb', 'b.xc']

    Now, looking at this I saw there *is* a bug in rlcompleter, as it may
    return many duplicate items:

    >>> c.complete("b.__c", 0)
    'b.__class__('
    >>> c.matches
    ['b.__class__(', 'b.__class__(', 'b.__class__(', 'b.__class__(']

    The attached patch fixes that.

    @carlj
    Copy link
    Mannequin Author

    carlj mannequin commented Jan 27, 2009

    It seems to me that it isn't tab completion's place to out think the
    __dir__ method. A) Because the documentation doesn't tell you that it
    does (although you are warned that it may call some stuff) and B)
    because if someone set up a __dir__ method, they probably are listing
    the things that they want listed for a particular reason. I think that
    it would be less confusing for rlcompleter to follow the __dir__ method
    when it exists and only do its own poking and prodding when it does not.

    @ggenellina
    Copy link
    Mannequin

    ggenellina mannequin commented Jan 27, 2009

    This is what rlcompleter does; it uses dir() to find out what names to
    return.
    Or do you mean that it should not iterate along __bases__ because this
    has already been done by dir()?

    @carlj
    Copy link
    Mannequin Author

    carlj mannequin commented Jan 27, 2009

    I think that checking to see which things really exist with
    getattr/hasattr made sense back in the days before the __dir__, since in
    those days the real API for an object could diverge wildly from what was
    reported by dir(object), but nowadays, if someone goes to the trouble of
    defining the __dir__ method, then we should just trust that as being
    "the API" and not do any other checking.

    @ggenellina
    Copy link
    Mannequin

    ggenellina mannequin commented Jan 27, 2009

    The check is made to decide whether the attribute is a method or not
    (because methods get a "(" appended) -- for names that fail to exist,
    one could just omit the "(" and include the name anyway.

    rlcompleter does nothing special with __dir__, it always uses dir()
    only.

    @carlj
    Copy link
    Mannequin Author

    carlj mannequin commented Jan 27, 2009

    Ah, I see. It does a dir(obj) then tests things to see which are
    callable and while it is at that, it removes the names that don't really
    exist according to getattr.

    Actually, can we go back to the Python 2.5 behavior? I really hate those
    auto-added parentheses. For one thing, it screws it up when you do
    "help(name<TAB>". Am I missing some really obvious switch that would
    turn the behavior back to the old style of ignoring the
    callable/non-callable thing?

    @ggenellina
    Copy link
    Mannequin

    ggenellina mannequin commented Jan 27, 2009

    The current behaviour is actually a requested feature: see bpo-449227

    I see your point, it may be annoying sometimes -- but calling a method
    is far more common than just getting a reference to it, so I think the
    current behaviour is fine (I'm talking about the added "(", not the
    repeated entries, nor the unneeded __bases__ recursion, nor the deleted
    entries)

    @admin admin mannequin assigned docspython and unassigned birkenfeld Oct 29, 2010
    @BreamoreBoy
    Copy link
    Mannequin

    BreamoreBoy mannequin commented Jun 26, 2014

    Patched code produces identical output to unpatched code. This doesn't really surprise me as word is reused within the for loop.

    @vadmium
    Copy link
    Member

    vadmium commented May 13, 2016

    bpo-14782 is open for complaints about the opening brackets.

    I think this report was mainly about attributes that fail the hasattr() test. In bpo-25590 we were conservative and only fixed it in 3.6+.

    @vadmium vadmium closed this as completed May 13, 2016
    @vadmium vadmium added stdlib Python modules in the Lib dir and removed docs Documentation in the Doc dir extension-modules C modules in the Modules dir labels May 13, 2016
    @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
    stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
    Projects
    None yet
    Development

    No branches or pull requests

    2 participants