I'm trying to write a class. Objects of that class can take a label/value pair and store it in such a way that label
can be accessed as an attribute, returning value
: obj.label -> value
The main goal here is to get autocompletion in jupyter notebooks, so obj.<tab>
should produce the list of labels as autocompletion suggestion. The below class accomplishes this:
class Autocompleter:
def __init__(self, ):
self._funcs = {}
def add(self, label):
self._funcs[label] = 1.
def __dir__(self):
return list(self._funcs.keys())
def __getattr__(self, name):
if name in dir(self):
return self._funcs[name]
The problem: When accessing an invalid attribute, the __getattr__
simply returns None
. I'd rather have it throw an exception. I can think of 2 ways to achieve this, but unfortunately both break the autocompletion:
Changing __getattr__
to:
def __getattr__(self, name):
return self._funcs[name]
or
def __getattr__(self, name):
if name in dir(self):
return self._funcs[name]
else:
raise Exception('invalid name')
produces the desired exception, but breaks the autocompletion:
a = Autocompleter()
a.add('foo')
Now a.<tab>
does not suggest foo
for autocompletion, it simply does nothing. As far as I can tell, jedi is used by default for autompletion in jupyterlab.
Question: Is there a way to get both the exception on invalid names and the autocomplete feature working?
I figured it out myself. The correct way to handle an invalid attribute name is to raise an AttributeError. This can then be understood by jedi.
def __getattr__(self, name):
if name in dir(self):
return self._funcs[name]
raise AttributeError(name)
Note that the __dir__
method is still needed.