From f8c9ea7db42d9830f16318a4ceca0ac1c3688697 2020-06-13 03:35:59 From: Matthias Bussonnier Date: 2020-06-13 03:35:59 Subject: [PATCH] Merge pull request #12383 from cool-RR/2020-06-09-raise-from Fix exception causes all over the codebase --- diff --git a/IPython/core/display.py b/IPython/core/display.py index 18bfaa6..490435a 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -987,9 +987,9 @@ class Image(DisplayObject): """shortcut for returning metadata with shape information, if defined""" try: b64_data = b2a_base64(self.data).decode('ascii') - except TypeError: + except TypeError as e: raise FileNotFoundError( - "No such file or directory: '%s'" % (self.data)) + "No such file or directory: '%s'" % (self.data)) from e md = {} if self.metadata: md.update(self.metadata) diff --git a/IPython/core/page.py b/IPython/core/page.py index 8a8f14f..d039925 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -106,7 +106,7 @@ def _detect_screen_size(screen_lines_def): term_flags = termios.tcgetattr(sys.stdout) except termios.error as err: # can fail on Linux 2.6, pager_page will catch the TypeError - raise TypeError('termios error: {0}'.format(err)) + raise TypeError('termios error: {0}'.format(err)) from err try: scr = curses.initscr() diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index ef1539a..3af899e 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -200,8 +200,8 @@ def _reshow_nbagg_figure(fig): """reshow an nbagg figure""" try: reshow = fig.canvas.manager.reshow - except AttributeError: - raise NotImplementedError() + except AttributeError as e: + raise NotImplementedError() from e else: reshow() diff --git a/IPython/core/tests/test_pylabtools.py b/IPython/core/tests/test_pylabtools.py index 7b64aab..75b103f 100644 --- a/IPython/core/tests/test_pylabtools.py +++ b/IPython/core/tests/test_pylabtools.py @@ -51,7 +51,7 @@ def _check_pil_jpeg_bytes(): img.save(buf, 'jpeg') except Exception as e: ename = e.__class__.__name__ - raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) + raise SkipTest("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) from e @dec.skip_without("PIL.Image") def test_figure_to_jpeg(): diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index 2974da4..9634913 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -241,8 +241,8 @@ class TestMagicRunSimple(tt.TempFileMixin): if sys.platform == 'win32': try: import win32api - except ImportError: - raise SkipTest("Test requires pywin32") + except ImportError as e: + raise SkipTest("Test requires pywin32") from e src = ("class A(object):\n" " def __del__(self):\n" " print('object A deleted')\n" diff --git a/IPython/extensions/storemagic.py b/IPython/extensions/storemagic.py index 51b79ad..9102ea1 100644 --- a/IPython/extensions/storemagic.py +++ b/IPython/extensions/storemagic.py @@ -126,13 +126,13 @@ class StoreMagics(Magics): if 'd' in opts: try: todel = args[0] - except IndexError: - raise UsageError('You must provide the variable to forget') + except IndexError as e: + raise UsageError('You must provide the variable to forget') from e else: try: del db['autorestore/' + todel] - except: - raise UsageError("Can't delete variable '%s'" % todel) + except BaseException as e: + raise UsageError("Can't delete variable '%s'" % todel) from e # reset elif 'z' in opts: for k in db.keys('autorestore/*'): @@ -203,8 +203,8 @@ class StoreMagics(Magics): name = arg try: cmd = ip.alias_manager.retrieve_alias(name) - except ValueError: - raise UsageError("Unknown variable '%s'" % name) + except ValueError as e: + raise UsageError("Unknown variable '%s'" % name) from e staliases = db.get('stored_aliases',{}) staliases[name] = cmd diff --git a/IPython/lib/clipboard.py b/IPython/lib/clipboard.py index 316a8ab..95a6b0a 100644 --- a/IPython/lib/clipboard.py +++ b/IPython/lib/clipboard.py @@ -16,9 +16,9 @@ def win32_clipboard_get(): """ try: import win32clipboard - except ImportError: + except ImportError as e: raise TryNext("Getting text from the clipboard requires the pywin32 " - "extensions: http://sourceforge.net/projects/pywin32/") + "extensions: http://sourceforge.net/projects/pywin32/") from e win32clipboard.OpenClipboard() try: text = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT) @@ -26,8 +26,8 @@ def win32_clipboard_get(): try: text = win32clipboard.GetClipboardData(win32clipboard.CF_TEXT) text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING) - except (TypeError, win32clipboard.error): - raise ClipboardEmpty + except (TypeError, win32clipboard.error) as e: + raise ClipboardEmpty from e finally: win32clipboard.CloseClipboard() return text @@ -52,15 +52,15 @@ def tkinter_clipboard_get(): """ try: from tkinter import Tk, TclError - except ImportError: - raise TryNext("Getting text from the clipboard on this platform requires tkinter.") + except ImportError as e: + raise TryNext("Getting text from the clipboard on this platform requires tkinter.") from e root = Tk() root.withdraw() try: text = root.clipboard_get() - except TclError: - raise ClipboardEmpty + except TclError as e: + raise ClipboardEmpty from e finally: root.destroy() text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING) diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index bd8c01b..ddfa1bc 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -97,21 +97,21 @@ def get_parent(globals, level): for x in range(level, 1, -1): try: dot = name.rindex('.', 0, dot) - except ValueError: + except ValueError as e: raise ValueError("attempted relative import beyond top-level " - "package") + "package") from e name = name[:dot] try: parent = sys.modules[name] - except: + except BaseException as e: if orig_level < 1: warn("Parent module '%.200s' not found while handling absolute " "import" % name) parent = None else: raise SystemError("Parent module '%.200s' not loaded, cannot " - "perform relative import" % name) + "perform relative import" % name) from e # We expect, but can't guarantee, if parent != None, that: # - parent.__name__ == name @@ -292,9 +292,9 @@ def deep_reload_hook(m): else: try: parent = sys.modules[name[:dot]] - except KeyError: + except KeyError as e: modules_reloading.clear() - raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot]) + raise ImportError("reload(): parent %.200s not in sys.modules" % name[:dot]) from e subname = name[dot+1:] path = getattr(parent, "__path__", None) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index d24f455..4f28010 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -182,9 +182,9 @@ class Audio(DisplayObject): try: max_abs_value = float(max([abs(x) for x in data])) - except TypeError: + except TypeError as e: raise TypeError('Only lists of mono audio are ' - 'supported if numpy is not installed') + 'supported if numpy is not installed') from e normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) scaled = array.array('h', [int(x / normalization_factor * 32767) for x in data]) diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py index 62f840d..86077d0 100644 --- a/IPython/lib/inputhook.py +++ b/IPython/lib/inputhook.py @@ -281,9 +281,9 @@ class InputHookManager(object): try: gui_hook = self.guihooks[gui] - except KeyError: + except KeyError as e: e = "Invalid GUI request {!r}, valid ones are: {}" - raise ValueError(e.format(gui, ', '.join(self.guihooks))) + raise ValueError(e.format(gui, ', '.join(self.guihooks))) from e self._current_gui = gui app = gui_hook.enable(app) diff --git a/IPython/lib/inputhookglut.py b/IPython/lib/inputhookglut.py index 9fc29bd..e866ebd 100644 --- a/IPython/lib/inputhookglut.py +++ b/IPython/lib/inputhookglut.py @@ -61,10 +61,10 @@ if sys.platform == 'darwin': doc='glutCheckLoop( ) -> None', argNames=(), ) - except AttributeError: + except AttributeError as e: raise RuntimeError( '''Your glut implementation does not allow interactive sessions. ''' - '''Consider installing freeglut.''') + '''Consider installing freeglut.''') from e glutMainLoopEvent = glutCheckLoop elif glut.HAVE_FREEGLUT: glutMainLoopEvent = glut.glutMainLoopEvent diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index cbcc7d9..9561bd7 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -95,8 +95,8 @@ def latex_to_png(s, encode=False, backend=None, wrap=False, color='Black', try: color = "RGB {}".format(" ".join([str(int(x, 16)) for x in textwrap.wrap(color[1:], 2)])) - except ValueError: - raise ValueError('Invalid color specification {}.'.format(color)) + except ValueError as e: + raise ValueError('Invalid color specification {}.'.format(color)) from e else: raise ValueError('Invalid color specification {}.'.format(color)) else: diff --git a/IPython/paths.py b/IPython/paths.py index bbe3d5c..5334429 100644 --- a/IPython/paths.py +++ b/IPython/paths.py @@ -113,7 +113,7 @@ def locate_profile(profile='default'): from IPython.core.profiledir import ProfileDir, ProfileDirError try: pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile) - except ProfileDirError: + except ProfileDirError as e: # IOError makes more sense when people are expecting a path - raise IOError("Couldn't find profile %r" % profile) + raise IOError("Couldn't find profile %r" % profile) from e return pd.location diff --git a/IPython/sphinxext/custom_doctests.py b/IPython/sphinxext/custom_doctests.py index 7678fd6..75c2a25 100644 --- a/IPython/sphinxext/custom_doctests.py +++ b/IPython/sphinxext/custom_doctests.py @@ -107,10 +107,10 @@ def float_doctest(sphinx_shell, args, input_lines, found, submitted): try: rtol = float(args[2]) atol = float(args[3]) - except IndexError: + except IndexError as e: e = ("Both `rtol` and `atol` must be specified " "if either are specified: {0}".format(args)) - raise IndexError(e) + raise IndexError(e) from e try: submitted = str_to_array(submitted) diff --git a/IPython/terminal/magics.py b/IPython/terminal/magics.py index 3c7e82b..9e6f647 100644 --- a/IPython/terminal/magics.py +++ b/IPython/terminal/magics.py @@ -181,8 +181,8 @@ class TerminalMagics(Magics): else: error('Could not get text from the clipboard.') return - except ClipboardEmpty: - raise UsageError("The clipboard appears to be empty") + except ClipboardEmpty as e: + raise UsageError("The clipboard appears to be empty") from e # By default, echo back to terminal unless quiet mode is requested if 'q' not in opts: diff --git a/IPython/terminal/pt_inputhooks/glut.py b/IPython/terminal/pt_inputhooks/glut.py index d26f91c..835aadf 100644 --- a/IPython/terminal/pt_inputhooks/glut.py +++ b/IPython/terminal/pt_inputhooks/glut.py @@ -44,10 +44,10 @@ if sys.platform == 'darwin': doc='glutCheckLoop( ) -> None', argNames=(), ) - except AttributeError: + except AttributeError as e: raise RuntimeError( '''Your glut implementation does not allow interactive sessions. ''' - '''Consider installing freeglut.''') + '''Consider installing freeglut.''') from e glutMainLoopEvent = glutCheckLoop elif glut.HAVE_FREEGLUT: glutMainLoopEvent = glut.glutMainLoopEvent diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index 0db926a..75a9525 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -443,8 +443,8 @@ def fake_input(inputs): def mock_input(prompt=''): try: return next(it) - except StopIteration: - raise EOFError('No more inputs given') + except StopIteration as e: + raise EOFError('No more inputs given') from e return patch('builtins.input', mock_input) diff --git a/IPython/utils/_process_win32.py b/IPython/utils/_process_win32.py index 6d05bda..86d8100 100644 --- a/IPython/utils/_process_win32.py +++ b/IPython/utils/_process_win32.py @@ -75,8 +75,8 @@ def _find_cmd(cmd): """Find the full path to a .bat or .exe using the win32api module.""" try: from win32api import SearchPath - except ImportError: - raise ImportError('you need to have pywin32 installed for this to work') + except ImportError as e: + raise ImportError('you need to have pywin32 installed for this to work') from e else: PATH = os.environ['PATH'] extensions = ['.exe', '.com', '.bat', '.py'] diff --git a/IPython/utils/coloransi.py b/IPython/utils/coloransi.py index bc8e837..e331421 100644 --- a/IPython/utils/coloransi.py +++ b/IPython/utils/coloransi.py @@ -176,9 +176,9 @@ class ColorSchemeTable(dict): scheme_test = scheme.lower() try: scheme_idx = valid_schemes.index(scheme_test) - except ValueError: + except ValueError as e: raise ValueError('Unrecognized color scheme: ' + scheme + \ - '\nValid schemes: '+str(scheme_names).replace("'', ",'')) + '\nValid schemes: '+str(scheme_names).replace("'', ",'')) from e else: active = scheme_names[scheme_idx] self.active_scheme_name = active diff --git a/IPython/utils/importstring.py b/IPython/utils/importstring.py index c8e1840..c7a9cce 100644 --- a/IPython/utils/importstring.py +++ b/IPython/utils/importstring.py @@ -31,8 +31,8 @@ def import_item(name): module = __import__(package, fromlist=[obj]) try: pak = getattr(module, obj) - except AttributeError: - raise ImportError('No module named %s' % obj) + except AttributeError as e: + raise ImportError('No module named %s' % obj) from e return pak else: # called with un-dotted string diff --git a/IPython/utils/ipstruct.py b/IPython/utils/ipstruct.py index e2b3e8f..376fbbe 100644 --- a/IPython/utils/ipstruct.py +++ b/IPython/utils/ipstruct.py @@ -120,7 +120,7 @@ class Struct(dict): try: self.__setitem__(key, value) except KeyError as e: - raise AttributeError(e) + raise AttributeError(e) from e def __getattr__(self, key): """Get an attr by calling :meth:`dict.__getitem__`. @@ -145,8 +145,8 @@ class Struct(dict): """ try: result = self[key] - except KeyError: - raise AttributeError(key) + except KeyError as e: + raise AttributeError(key) from e else: return result diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 0fb6144..3f0e217 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -39,8 +39,8 @@ if sys.platform == 'win32': """ try: import ctypes - except ImportError: - raise ImportError('you need to have ctypes installed for this to work') + except ImportError as e: + raise ImportError('you need to have ctypes installed for this to work') from e _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint ] diff --git a/IPython/utils/shimmodule.py b/IPython/utils/shimmodule.py index b70ac13..cc05503 100644 --- a/IPython/utils/shimmodule.py +++ b/IPython/utils/shimmodule.py @@ -90,5 +90,5 @@ class ShimModule(types.ModuleType): name = "%s.%s" % (self._mirror, key) try: return import_item(name) - except ImportError: - raise AttributeError(key) + except ImportError as e: + raise AttributeError(key) from e diff --git a/docs/sphinxext/github.py b/docs/sphinxext/github.py index dcc0250..a24b5a6 100644 --- a/docs/sphinxext/github.py +++ b/docs/sphinxext/github.py @@ -40,7 +40,7 @@ def make_link_node(rawtext, app, type, slug, options): if not base.endswith('/'): base += '/' except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) + raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err ref = base + type + '/' + slug + '/' set_classes(options) @@ -137,7 +137,7 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if not base.endswith('/'): base += '/' except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) + raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) from err ref = base + text node = nodes.reference(rawtext, text[:6], refuri=ref, **options) diff --git a/tools/gh_api.py b/tools/gh_api.py index 094562d..d03495b 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -30,8 +30,8 @@ class Obj(dict): def __getattr__(self, name): try: return self[name] - except KeyError: - raise AttributeError(name) + except KeyError as e: + raise AttributeError(name) from e def __setattr__(self, name, val): self[name] = val