[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Strange tab completion oddity with enums?

I'm not sure what's going on here, and it's probably not actually
enum-specific, but that's where I saw it.

If you create a plain class and have an attribute with an annotation,
you can see that:

>>> class Foo:
...     spam: "ham" = 1
>>> Foo.__a
Foo.__abstractmethods__  Foo.__annotations__
>>> Foo.__annotations__
{'spam': 'ham'}

Note that __annotations__ shows up when tab-completing "__a".

Now consider an enumeration:

>>> from enum import Flag, auto
>>> class Bar(Flag):
...     quux: "asdf" = auto()
>>> Bar.__
Bar.__abstractmethods__  Bar.__getattr__(         Bar.__ne__(
Bar.__base__(            Bar.__getattribute__(    Bar.__new__(
Bar.__bases__            Bar.__getitem__(         Bar.__prepare__(
Bar.__basicsize__        Bar.__gt__(              Bar.__qualname__
Bar.__bool__(            Bar.__hash__(            Bar.__reduce__(
Bar.__call__(            Bar.__init__(            Bar.__reduce_ex__(
Bar.__class__(           Bar.__init_subclass__(   Bar.__repr__(
Bar.__contains__(        Bar.__instancecheck__(   Bar.__reversed__(
Bar.__delattr__(         Bar.__itemsize__         Bar.__setattr__(
Bar.__dict__             Bar.__iter__(            Bar.__sizeof__(
Bar.__dictoffset__       Bar.__le__(              Bar.__str__(
Bar.__dir__(             Bar.__len__(             Bar.__subclasscheck__(
Bar.__doc__              Bar.__lt__(              Bar.__subclasses__(
Bar.__eq__(              Bar.__members__          Bar.__subclasshook__(
Bar.__flags__            Bar.__module__           Bar.__text_signature__
Bar.__format__(          Bar.__mro__              Bar.__weakrefoffset__
Bar.__ge__(              Bar.__name__
>>> Bar.__annotations__
{'quux': 'asdf'}

Double-tabbing "__" shows everything but, and double-tabbing "__ann"
has nothing... but the attribute is most definitely there.

Perhaps notable is dir():

>>> dir(Foo)
['__annotations__', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__gt__', '__hash__', '__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', 'spam']
>>> dir(Bar)
['__class__', '__doc__', '__members__', '__module__', 'quux']

But that's not the whole story, since tab completing "Bar.__" will
still show "__class__" and "__init__" that aren't in dir().

Tested with the default REPL CPython 3.6, 3.7, 3.8, and 3.9. Tested
also in IDLE on 3.9 but tab completion of dunders behaves differently
there (it ONLY seems to want to tab complete __class__, for some
reason) so it's not comparable.

What's actually going on here?