All Projects → SylvainDe → Didyoumean Python

SylvainDe / Didyoumean Python

Licence: mit
Module to have suggestions in case of errors (NameError, AttributeError, etc).

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to Didyoumean Python

Bugsnag Node
[DEPRECATED] Please upgrade to our Universal JS notifier "@bugsnag/js" • https://github.com/bugsnag/bugsnag-js
Stars: ✭ 48 (-52.94%)
Mutual labels:  exceptions, error
Bugsnag Go
Automatic panic monitoring for Go and Go web frameworks, like negroni, gin, and revel
Stars: ✭ 155 (+51.96%)
Mutual labels:  exceptions, error
custom-exception-middleware
Middleware to catch custom or accidental exceptions
Stars: ✭ 30 (-70.59%)
Mutual labels:  error, exceptions
Wynullview
An easy way to use for view's empty state 一行代码显示空视图,高度自定义
Stars: ✭ 44 (-56.86%)
Mutual labels:  error
Oops
😥A library for android that help to show the layout of loading, error, empty etc.
Stars: ✭ 49 (-51.96%)
Mutual labels:  error
Backtrace
Makes Python tracebacks human friendly
Stars: ✭ 80 (-21.57%)
Mutual labels:  exceptions
Alloylever
1kb js library contains development debugging, error monitoring and reporting, user problem localization features - 1KB代码搞定开发调试发布,错误监控上报,用户问题定位
Stars: ✭ 1,348 (+1221.57%)
Mutual labels:  error
Rollbar Android
Rollbar for Android
Stars: ✭ 41 (-59.8%)
Mutual labels:  exceptions
Vue Raven
vue-raven automatically reports uncaught JavaScript exceptions triggered from vue component
Stars: ✭ 91 (-10.78%)
Mutual labels:  exceptions
React Native Exception Handler
A react native module that lets you to register a global error handler that can capture fatal/non fatal uncaught exceptions.
Stars: ✭ 1,170 (+1047.06%)
Mutual labels:  error
Bugsnag Python
Official bugsnag error monitoring and error reporting for django, flask, tornado and other python apps.
Stars: ✭ 69 (-32.35%)
Mutual labels:  exceptions
Noexception
Java library for handling exceptions in concise, unified, and architecturally clean way.
Stars: ✭ 56 (-45.1%)
Mutual labels:  exceptions
Larabug
Laravel error reporting tool
Stars: ✭ 84 (-17.65%)
Mutual labels:  exceptions
React Guard
🦄 React Guard automagically catches exceptions from React components, extracts useful debug information and prevents White Screen of Death 👻
Stars: ✭ 89 (-12.75%)
Mutual labels:  exceptions
Seriouscode
This header file enforces Clang warnings to bu turned-on for specific flags (almost everyone, at least each one I was able to find).
Stars: ✭ 68 (-33.33%)
Mutual labels:  error
Coderr.server
Replace logfiles with Coderr to correct bugs faster and more efficiently.
Stars: ✭ 92 (-9.8%)
Mutual labels:  exceptions
Bugsnag Android Ndk
DEPRECATED - this project now lives at bugsnag/bugsnag-android
Stars: ✭ 42 (-58.82%)
Mutual labels:  exceptions
Extensible Custom Error
JavaScript extensible custom error that can take a message and/or an Error object
Stars: ✭ 64 (-37.25%)
Mutual labels:  error
Vos backend
vangav open source - backend; a backend generator (generates more than 90% of the code needed for big scale backend services)
Stars: ✭ 71 (-30.39%)
Mutual labels:  exceptions
Exception Track
Tracking ⚠️ exceptions for Rails application and store them in database.
Stars: ✭ 102 (+0%)
Mutual labels:  exceptions

DidYouMean-Python (aka BetterErrorMessages)

BetterErrorMessages on PyPI

Build Status

Coverage Status codecov.io

Code Health Code Climate Scrutinizer Codacy Badge

Logic to have various kind of suggestions in case of errors (NameError, AttributeError, ImportError, TypeError, ValueError, SyntaxError, MemoryError, OverflowError, IOError, OSError).

Inspired by "Did you mean" for Ruby (Explanation, Github Page), this is a simple implementation for/in Python. I wanted to see if I could mess around and create something similar in Python and it seems to be possible.

Usage

Once the package is installed (see below), the logic adding suggestions can be invoked in different ways:

  • hook on sys.excepthook : just call didyoumean_enablehook() and you'll have the suggestions for any uncaught exception:
>>> abc = 3
>>> abcd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'abcd' is not defined
>>> didyoumean.didyoumean_api.didyoumean_enablehook()
>>> abcd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'abcd' is not defined. Did you mean 'abc' (local)?
  • post-mortem function didyoumean_postmortem() on the last uncaught exception during interactive sessions:
>>> abc = 3
>>> abcd
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'abcd' is not defined
>>> didyoumean.didyoumean_api.didyoumean_postmortem()
NameError("name 'abcd' is not defined. Did you mean 'abc' (local)?",)
  • context manager didyoumean_contextmanager():
>>> with didyoumean.didyoumean_api.didyoumean_contextmanager():
...     abcd
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: name 'abcd' is not defined. Did you mean 'abc' (local)
  • decorator : just add the @didyoumean decorator before any function (the main() could be a good choice) and you'll have the suggestions for any exception happening through a call to that method.
>>> @didyoumean.didyoumean_api.didyoumean_decorator
... def foo(): return abcd
...
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 2, in foo
NameError: global name 'abcd' is not defined. Did you mean 'abc' (global)?

The API does not look great and may be updated in the near future.

Example

More examples can be found from the test file didyoumean/didyoumean_sugg_tests.py.

NameError

Fuzzy matches on existing names (local, builtin, keywords, modules, etc)
def my_func(foo, bar):
	return foob
my_func(1, 2)
#>>> Before: NameError("global name 'foob' is not defined",)
#>>> After: NameError("global name 'foob' is not defined. Did you mean 'foo' (local)?",)
leng([0])
#>>> Before: NameError("name 'leng' is not defined",)
#>>> After: NameError("name 'leng' is not defined. Did you mean 'len' (builtin)?",)
import math
maths.pi
#>>> Before: NameError("name 'maths' is not defined",)
#>>> After: NameError("name 'maths' is not defined. Did you mean 'math' (local)?",)
passs
#>>> Before: NameError("name 'passs' is not defined",)
#>>> After: NameError("name 'passs' is not defined. Did you mean 'pass' (keyword)?",)
def my_func():
	foo = 1
	foob +=1
my_func()
#>>> Before: UnboundLocalError("local variable 'foob' referenced before assignment",)
#>>> After: UnboundLocalError("local variable 'foob' referenced before assignment. Did you mean 'foo' (local)?",)
Checking if name is the attribute of a defined object
class Duck():
	def __init__(self):
		quack()
	def quack(self):
		pass
d = Duck()
#>>> Before: NameError("global name 'quack' is not defined",)
#>>> After: NameError("global name 'quack' is not defined. Did you mean 'self.quack'?",)
import math
pi
#>>> Before: NameError("name 'pi' is not defined",)
#>>> After: NameError("name 'pi' is not defined. Did you mean 'math.pi'?",)
Looking for missing imports
string.ascii_lowercase
#>>> Before: NameError("name 'string' is not defined",)
#>>> After: NameError("name 'string' is not defined. Did you mean to import string first?",)
Looking in missing imports
choice
#>>> Before: NameError("name 'choice' is not defined",)
#>>> After: NameError("name 'choice' is not defined. Did you mean 'choice' from random (not imported)?",)
Special cases
assert j ** 2 == -1
#>>> Before: NameError("name 'j' is not defined",)
#>>> After: NameError("name 'j' is not defined. Did you mean '1j' (imaginary unit)?",)

AttributeError

Fuzzy matches on existing attributes
lst = [1, 2, 3]
lst.appendh(4)
#>>> Before: AttributeError("'list' object has no attribute 'appendh'",)
#>>> After: AttributeError("'list' object has no attribute 'appendh'. Did you mean 'append'?",)
import math
math.pie
#>>> Before: AttributeError("'module' object has no attribute 'pie'",)
#>>> After: AttributeError("'module' object has no attribute 'pie'. Did you mean 'pi'?",)
Trying to find method with similar meaning (hardcoded)
lst = [1, 2, 3]
lst.add(4)
#>>> Before: AttributeError("'list' object has no attribute 'add'",)
#>>> After: AttributeError("'list' object has no attribute 'add'. Did you mean 'append'?",)
lst = [1, 2, 3]
lst.get(5, None)
#>>> Before: AttributeError("'list' object has no attribute 'get'",)
#>>> After: AttributeError("'list' object has no attribute 'get'. Did you mean 'obj[key]' with a len() check or try: except: KeyError or IndexError?",)
Detection of mis-used builtins
lst = [1, 2, 3]
lst.max()
#>>> Before: AttributeError("'list' object has no attribute 'max'")
#>>> After: AttributeError("'list' object has no attribute 'max'. Did you mean 'max(list)'?")
Period used instead of comma
a, b = 1, 2
max(a. b)
#>>> Before: AttributeError("'int' object has no attribute 'b'")
#>>> After: AttributeError("'int' object has no attribute 'b'. Did you mean to use a comma instead of a period?")

ImportError

Fuzzy matches on existing modules
from maths import pi
#>>> Before: ImportError('No module named maths',)
#>>> After: ImportError("No module named maths. Did you mean 'math'?",)
Fuzzy matches on elements of the module
from math import pie
#>>> Before: ImportError('cannot import name pie',)
#>>> After: ImportError("cannot import name pie. Did you mean 'pi'?",)
Looking for import from wrong module
from itertools import pi
#>>> Before: ImportError('cannot import name pi',)
#>>> After: ImportError("cannot import name pi. Did you mean 'from math import pi'?",)

TypeError

Fuzzy matches on keyword arguments
def my_func(abcde):
	pass
my_func(abcdf=1)
#>>> Before: TypeError("my_func() got an unexpected keyword argument 'abcdf'",)
#>>> After: TypeError("my_func() got an unexpected keyword argument 'abcdf'. Did you mean 'abcde'?",)
Confusion between brackets and parenthesis
lst = [1, 2, 3]
lst(0)
#>>> Before: TypeError("'list' object is not callable",)
#>>> After: TypeError("'list' object is not callable. Did you mean 'list[value]'?",)
def my_func(a):
    pass
my_func[1]
#>>> Before: TypeError("'function' object has no attribute '__getitem__'",)
#>>> After: TypeError("'function' object has no attribute '__getitem__'. Did you mean 'function(value)'?",)

ValueError

Special cases
'Foo{}'.format('bar')
#>>> Before: ValueError('zero length field name in format',)
#>>> After: ValueError('zero length field name in format. Did you mean {0}?',)
import datetime
datetime.datetime.strptime("%d %b %y", "30 Nov 00")
#> Before: ValueError("time data '%d %b %y' does not match format '30 Nov 00'",)
#> After: ValueError("time data '%d %b %y' does not match format '30 Nov 00'. Did you mean to swap value and format parameters?",)

SyntaxError

Fuzzy matches when importing from future
from __future__ import divisio
#>>> Before: SyntaxError('future feature divisio is not defined',)
#>>> After: SyntaxError("future feature divisio is not defined. Did you mean 'division'?",)
Various
return
#>>> Before: SyntaxError("'return' outside function", ('<string>', 1, 0, None))
#>>> After: SyntaxError("'return' outside function. Did you mean to indent it, 'sys.exit([arg])'?", ('<string>', 1, 0, None))

MemoryError

Search for a memory-efficient equivalent
range(99999999999)
#>>> Before: MemoryError()
#>>> After: MemoryError(". Did you mean 'xrange'?",)

OverflowError

Search for a memory-efficient equivalent
range(999999999999999)
#>>> Before: OverflowError('range() result has too many items',)
#>>> After: OverflowError("range() result has too many items. Did you mean 'xrange'?",)

OSError/IOError

Suggestion for tilde/variable expansions
os.listdir('~')
#>>> Before: OSError(2, 'No such file or directory')
#>>> After: OSError(2, "No such file or directory. Did you mean '/home/user' (calling os.path.expanduser)?")

RuntimeError

Suggestion to avoid reaching maximum recursion depth
global rec
def rec(n): return rec(n-1)
rec(0)
#>>> Before: RuntimeError('maximum recursion depth exceeded',)
#>>> After: RuntimeError('maximum recursion depth exceeded. Did you mean to avoid recursion (cf http://neopythonic.blogspot.fr/2009/04/tail-recursion-elimination.html), increase the limit with `sys.setrecursionlimit(limit)` (current value is 1000)?',)

Installation

The package is available on Pypi as BetterErrorMessages.

Installation can be done from the package index with pip install BetterErrorMessages.

Installation from sources can be done just as easily:

git clone https://github.com/SylvainDe/DidYouMean-Python.git
cd DidYouMean-Python
git install .

Making things automatic in your interactive sessions

You can have the suggestions automatically in your interactive sessions by adding the following code in your ${PYTHONSTARTUP} file:

try:
    import didyoumean
except ImportError:
    print("Did you mean to install BetterErrorMessages first (`pip install BetterErrorMessages`)")
else:
    didyoumean.didyoumean_api.didyoumean_enablehook()

Implementation

All external APIs (decorator, hook, etc) use the same logic behind the scene. It works in a pretty simple way : when an exception happens, we try to get the relevant information out of the error message and of the backtrace to find the most relevant suggestions. To filter the best suggestions out of everything in case of fuzzy match, I am currently using difflib.

See also (similar projects/ideas)

Projects:

Discussions:

Contributing

Feedback is welcome, feel free to :

  • send me an email for any question/advice/comment/criticism
  • open issues if something goes wrong (please provide at least the version of Python you are using).

Also, pull-requests are welcome to :

  • fix issues
  • enhance the documentation
  • improve the code
  • bring awesomeness

As for the technical details :

  • this is under MIT License : you can do anything you want as long as you provide attribution back to this project.
  • I try to follow PEP 8 and PEP 257 as much as possible. Compliancy is checked during continuous integration using the pep8 and pep257 checkers.
  • I try to have most of the code covered by unit tests.
  • I try to write the code in such a way that it works on all Python versions from 2.6 (included).
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].