0

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?

LcdDrm
  • 1,009
  • 7
  • 14

1 Answers1

0

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.

LcdDrm
  • 1,009
  • 7
  • 14