didyoumean_contextmanager.__exit__()   B
last analyzed

Complexity

Conditions 5

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 23
rs 8.2508
c 0
b 0
f 0
cc 5
1
# -*- coding: utf-8
2
"""APIs to add suggestions to exceptions."""
3
from didyoumean_internal import add_suggestions_to_exception
4
import functools
5
import sys
6
7
8
def didyoumean_decorator(func):
9
    """Decorator to add suggestions to exceptions.
10
11
    To use it, decorate one of the functions called, for instance 'main()':
12
    @didyoumean_decorator
13
    def main():
14
        some_code
15
    """
16
    @functools.wraps(func)
17
    def decorated(*args, **kwargs):
18
        """Function returned by the decorator."""
19
        try:
20
            return func(*args, **kwargs)
21
        except:
22
            type_, value, traceback = sys.exc_info()
23
            add_suggestions_to_exception(type_, value, traceback)
24
            raise
25
    return decorated
26
27
28
def didyoumean_postmortem():
29
    """Post postem function to add suggestions to last exception thrown.
30
31
    Add suggestions to last exception thrown (in interactive mode) and
32
    return it (which should print it).
33
    """
34
    if hasattr(sys, 'last_type'):
35
        typ, val, trace = sys.last_type, sys.last_value, sys.last_traceback
36
        add_suggestions_to_exception(typ, val, trace)
37
        return val
38
    return None
39
40
41
class didyoumean_contextmanager(object):
42
    """Context manager to add suggestions to exceptions.
43
44
    To use it, create a context:
45
    with didyoumean_contextmanager():
46
        some_code.
47
    """
48
49
    def __enter__(self):
50
        """Method called when entering the context manager.
51
52
        Not relevant here (does not do anything).
53
        """
54
        pass
55
56
    def __exit__(self, type_, value, traceback):
57
        """Method called when exiting the context manager.
58
59
        Add suggestions to the exception (if any).
60
        """
61
        assert (type_ is None) == (value is None)
62
        if value is not None:
63
            if isinstance(value, type_):
64
                # Error is not re-raised as it is the caller's responsability
65
                # but the error is enhanced nonetheless
66
                add_suggestions_to_exception(type_, value, traceback)
67
            else:
68
                # Python 2.6 bug : http://bugs.python.org/issue7853
69
                # Instead of having the exception, we have its representation
70
                # We can try to rebuild the exception, add suggestions to it
71
                # and re-raise it (re-raise shouldn't be done normally but it
72
                # is a dirty work-around for a dirty issue).
73
                if isinstance(value, str):
74
                    value = type_(value)
75
                else:
76
                    value = type_(*value)
77
                add_suggestions_to_exception(type_, value, traceback)
78
                raise value
79
80
81
def didyoumean_hook(type_, value, traceback, prev_hook=sys.excepthook):
82
    """Hook to be substituted to sys.excepthook to enhance exceptions."""
83
    add_suggestions_to_exception(type_, value, traceback)
84
    return prev_hook(type_, value, traceback)
85
86
87
def didyoumean_custom_exc(shell, etype, evalue, tb, tb_offset=None):
88
    """Custom exception handler to replace the iPython one."""
89
    add_suggestions_to_exception(etype, evalue, tb)
90
    return shell.showtraceback((etype, evalue, tb), tb_offset=tb_offset)
91
92
93
def set_ipython_custom_exc(func):
94
    """Try to set the custom exception handler for iPython."""
95
    # https://mail.scipy.org/pipermail/ipython-dev/2012-April/008945.html
96
    # http://stackoverflow.com/questions/1261668/cannot-override-sys-excepthook
97
    try:
98
        get_ipython().set_custom_exc((Exception,), func)
99
    except NameError:
100
        pass  # get_ipython does not exist - ignore
101
102
103
def didyoumean_enablehook():
104
    """Function to set hooks to their custom value."""
105
    sys.excepthook = didyoumean_hook
106
    set_ipython_custom_exc(didyoumean_custom_exc)
107
108
109
def didyoumean_disablehook():
110
    """Function to set hooks to their normal value."""
111
    sys.excepthook = sys.__excepthook__
112
    set_ipython_custom_exc(None)
113
114
# NOTE: It could be funny to have a magic command in Python
115
# https://ipython.org/ipython-doc/dev/config/custommagics.html
116