Strange tab completion oddity with enums?
Peter Otten
__peter__ at web.de
Mon Oct 7 02:58:20 EDT 2019
Chris Angelico wrote:
> 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?
With Python 3.7:
>>> from enum import Flag
>>> import inspect
>>> print(inspect.getsource(Flag.__dir__))
def __dir__(self):
added_behavior = [
m
for cls in self.__class__.mro()
for m in cls.__dict__
if m[0] != '_' and m not in self._member_map_
]
return (['__class__', '__doc__', '__module__'] + added_behavior)
Looks like everything starting with an underscore (except class, doc, and
module) is suppressed, probably to suppress some noise...
More information about the Python-list
mailing list