| 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 |  |  |  |