Below is a class decorator did_you_mean
that will, when applied to a class, catch undefined methods on that class and return y
ou a recommendation of methods to call instead.
from fuzzywuzzy.process import extractOne
def get_class_methods(cls_instance):
return [name for name in dir(cls_instance) if not name.startswith('__')]
def get_recommendation(query, search_space, confidence_cutoff):
match = extractOne(query, search_space)
if match:
recommendation, calculated_confidence = match
return (
recommendation
if calculated_confidence >= confidence_cutoff
else None
)
def did_you_mean(confidence):
def _did_you_mean(self, name):
def wrapper(*args, **kwargs):
msg = 'The method "{}" does not exist...'.format(name)
cls_methods = get_class_methods(self)
recommendation = get_recommendation(name, cls_methods, confidence)
if recommendation:
msg += 'Did you mean to call: **{}()**?'.format(recommendation)
else:
msg += 'Instead try one of these: {}()'.format('(), '.join(cls_methods))
print(msg)
return self
return wrapper
def class_wrapper(cls):
setattr(cls, '__getattr__', _did_you_mean)
return cls
return class_wrapper
@did_you_mean(confidence=50)
class Pipette(object):
def foo(self):
print('foo was called')
return self
def bar(self):
print('bar was called')
return self
def baz(self):
print('baz was called')
return self
if __name__ == '__main__':
p200 = Pipette()
# This should recommend that you call 'bar' instead of 'bat'
p200.foo().bar().baz().bat()
# This should recommend all the methods in the calss since 'zzzz' is not
# close to any of the methods in the Pipette class withing the desired ratio
# but then continues to call other methods...
p200.zzzz().foo().bar()
If you run the above script in __main__
without applying did_you_mean
you get the standard python AttributeError
:
$ python did_you_mean.py
foo was called
bar was called
baz was called
Traceback (most recent call last):
File "did_you_mean.py", line 38, in <module>
p200.foo().bar().baz().bat()
AttributeError: 'Pipette' object has no attribute 'bat'
After applying did_you_mean
:
python did_you_mean.py
foo was called
bar was called
baz was called
The method "bat" does not exist...Did you mean to call: **bar()**?
The method "zzzz" does not exist...Instead try one of these: bar(), baz(), foo()
foo was called
bar was called
To replicate use a python env with python 3.3.2
with fuzzywuzzy
and python-Levenshtein
packages installed...