From 4335860f8de8f9abdc0b418a932e0c3c4cd47d5f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 30 Sep 2016 10:24:52 -0700 Subject: [PATCH 0001/4199] Start refactoring handling of color. This is one more step into getting rid of the old way of handling colors in IPython, in particular here we move the scheme/style as a configuration option of the parser instead of passing it around into the formats functions. Also remove our own usage of deprecated arguments. --- IPython/core/debugger.py | 13 ++-- IPython/core/interactiveshell.py | 13 ++-- IPython/core/tests/test_completer.py | 1 - IPython/core/tests/test_oinspect.py | 18 +++--- IPython/core/ultratb.py | 17 +----- IPython/utils/PyColorize.py | 84 ++++++-------------------- IPython/utils/colorable.py | 2 +- IPython/utils/tests/test_pycolorize.py | 18 +++--- 8 files changed, 54 insertions(+), 112 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 11f4b44a901..3e20170d0a9 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -239,7 +239,7 @@ def __init__(self, color_scheme=None, completekey=None, if color_scheme is not None: warnings.warn( "The `color_scheme` argument is deprecated since version 5.1", - DeprecationWarning) + DeprecationWarning, stacklevel=2) else: color_scheme = self.shell.colors @@ -269,11 +269,11 @@ def __init__(self, color_scheme=None, completekey=None, cst['Neutral'].colors.breakpoint_enabled = C.LightRed cst['Neutral'].colors.breakpoint_disabled = C.Red - self.set_colors(color_scheme) # Add a python parser so we can syntax highlight source while # debugging. - self.parser = PyColorize.Parser() + self.parser = PyColorize.Parser(style=color_scheme) + self.set_colors(color_scheme) # Set the prompt - the default prompt is '(Pdb)' self.prompt = prompt @@ -281,6 +281,7 @@ def __init__(self, color_scheme=None, completekey=None, def set_colors(self, scheme): """Shorthand access to the color table scheme selector method.""" self.color_scheme_table.set_active_scheme(scheme) + self.parser.style = scheme def trace_dispatch(self, frame, event, arg): try: @@ -451,9 +452,9 @@ def __format_line(self, tpl_line, filename, lineno, line, arrow = False): bp_mark = "" bp_mark_color = "" - scheme = self.color_scheme_table.active_scheme_name - new_line, err = self.parser.format2(line, 'str', scheme) - if not err: line = new_line + new_line, err = self.parser.format2(line, 'str') + if not err: + line = new_line bp = None if lineno in self.get_file_breaks(filename): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 10722097270..0c6d8b4aa76 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -473,10 +473,7 @@ def __init__(self, ipython_dir=None, profile_dir=None, # The following was in post_config_initialization self.init_inspector() - if py3compat.PY3: - self.raw_input_original = input - else: - self.raw_input_original = raw_input + self.raw_input_original = input self.init_completer() # TODO: init_io() needs to happen before init_traceback handlers # because the traceback handlers hardcode the stdout/stderr streams. @@ -577,10 +574,12 @@ def init_encoding(self): except AttributeError: self.stdin_encoding = 'ascii' - def init_syntax_highlighting(self): + + @observe('colors') + def init_syntax_highlighting(self, changes=None): # Python source parser/formatter for syntax highlighting - pyformat = PyColorize.Parser().format - self.pycolorize = lambda src: pyformat(src,'str',self.colors) + pyformat = PyColorize.Parser(style=self.colors).format + self.pycolorize = lambda src: pyformat(src,'str') def refresh_style(self): # No-op here, used in subclass diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 8679780d9a3..7678351546d 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -132,7 +132,6 @@ def test_unicode_completions(): nt.assert_true(isinstance(text, string_types)) nt.assert_true(isinstance(matches, list)) -@dec.onlyif(sys.version_info[0] >= 3, 'This test only applies in Py>=3') def test_latex_completions(): from IPython.core.latex_symbols import latex_symbols import random diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index eb753f1f758..f6a8cc27776 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -41,9 +41,14 @@ # updated. Do NOT insert any whitespace between the next line and the function # definition below. THIS_LINE_NUMBER = 43 # Put here the actual number of this line -def test_find_source_lines(): - nt.assert_equal(oinspect.find_source_lines(test_find_source_lines), - THIS_LINE_NUMBER+1) + +from unittest import TestCase + +class Test(TestCase): + + def test_find_source_lines(self): + self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines), + THIS_LINE_NUMBER+6) # A couple of utilities to ensure these tests work the same from a source or a @@ -322,7 +327,7 @@ def test_bool_raise(): def test_info_serialliar(): fib_tracker = [0] - i = inspector.info(SerialLiar(fib_tracker)) + inspector.info(SerialLiar(fib_tracker)) # Nested attribute access should be cut off at 100 levels deep to avoid # infinite loops: https://github.com/ipython/ipython/issues/9122 @@ -335,10 +340,9 @@ def test_calldef_none(): i = inspector.info(obj) nt.assert_is(i['call_def'], None) -if py3compat.PY3: - exec("def f_kwarg(pos, *, kwonly): pass") +def f_kwarg(pos, *, kwonly): + pass -@skipif(not py3compat.PY3) def test_definition_kwonlyargs(): i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)") diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 98e2cd586fa..52560b7366b 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -386,28 +386,18 @@ def _fixed_getinnerframes(etb, context=1, tb_offset=0): # can be recognized properly by ipython.el's py-traceback-line-re # (SyntaxErrors have to be treated specially because they have no traceback) -_parser = PyColorize.Parser() - def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None): numbers_width = INDENT_SIZE - 1 res = [] i = lnum - index - # This lets us get fully syntax-highlighted tracebacks. - if scheme is None: - ipinst = get_ipython() - if ipinst is not None: - scheme = ipinst.colors - else: - scheme = DEFAULT_SCHEME - - _line_format = _parser.format2 + _line_format = PyColorize.Parser(style=scheme).format2 for line in lines: line = py3compat.cast_unicode(line) - new_line, err = _line_format(line, 'str', scheme) + new_line, err = _line_format(line, 'str') if not err: line = new_line if i == lnum: @@ -1227,8 +1217,7 @@ def debugger(self, force=False): if force or self.call_pdb: if self.pdb is None: - self.pdb = self.debugger_cls( - self.color_scheme_table.active_scheme_name) + self.pdb = self.debugger_cls() # the system displayhook may have changed, restore the original # for pdb display_trap = DisplayTrap(hook=sys.__displayhook__) diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index 124eb2d4e3c..c845dd7442e 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -185,6 +185,8 @@ ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors, NeutralColors], _scheme_default) +Undefined = object() + class Parser(Colorable): """ Format colored Python source. """ @@ -199,11 +201,21 @@ def __init__(self, color_table=None, out = sys.stdout, parent=None, style=None): self.color_table = color_table and color_table or ANSICodeColors self.out = out + if not style: + self.style = self.default_style + else: + self.style = style + - def format(self, raw, out = None, scheme = ''): - return self.format2(raw, out, scheme)[0] + def format(self, raw, out=None, scheme=Undefined): + import warnings + if scheme is not Undefined: + warnings.warn('The `scheme` argument of IPython.utils.PyColorize:Parser.format is deprecated since IPython 6.0.' + 'It will have no effect. Set the parser `style` directly.', + stacklevel=2) + return self.format2(raw, out)[0] - def format2(self, raw, out = None, scheme = ''): + def format2(self, raw, out = None): """ Parse and send the colored source. If out and scheme are not specified, the defaults (given to @@ -227,7 +239,7 @@ def format2(self, raw, out = None, scheme = ''): self.out = out # Fast return of the unmodified input for NoColor scheme - if scheme == 'NoColor': + if self.style == 'NoColor': error = False self.out.write(raw) if string_output: @@ -236,7 +248,7 @@ def format2(self, raw, out = None, scheme = ''): return None,error # local shorthands - colors = self.color_table[scheme].colors + colors = self.color_table[self.style].colors self.colors = colors # put in object so __call__ sees it # Remove trailing whitespace and normalize tabs @@ -318,65 +330,3 @@ def __call__(self, toktype, toktext, start_pos, end_pos, line): # send text owrite('%s%s%s' % (color,toktext,colors.normal)) - -def main(argv=None): - """Run as a command-line script: colorize a python file or stdin using ANSI - color escapes and print to stdout. - - Inputs: - - - argv(None): a list of strings like sys.argv[1:] giving the command-line - arguments. If None, use sys.argv[1:]. - """ - - usage_msg = """%prog [options] [filename] - -Colorize a python file or stdin using ANSI color escapes and print to stdout. -If no filename is given, or if filename is -, read standard input.""" - - import optparse - parser = optparse.OptionParser(usage=usage_msg) - newopt = parser.add_option - newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store', - choices=['Linux','LightBG','NoColor'],default=_scheme_default, - help="give the color scheme to use. Currently only 'Linux'\ - (default) and 'LightBG' and 'NoColor' are implemented (give without\ - quotes)") - - opts,args = parser.parse_args(argv) - - if len(args) > 1: - parser.error("you must give at most one filename.") - - if len(args) == 0: - fname = '-' # no filename given; setup to read from stdin - else: - fname = args[0] - - if fname == '-': - stream = sys.stdin - else: - try: - stream = open(fname) - except IOError as msg: - print(msg, file=sys.stderr) - sys.exit(1) - - parser = Parser() - - # we need nested try blocks because pre-2.5 python doesn't support unified - # try-except-finally - try: - try: - # write colorized version to stdout - parser.format(stream.read(),scheme=opts.scheme_name) - except IOError as msg: - # if user reads through a pager and quits, don't print traceback - if msg.args != (32,'Broken pipe'): - raise - finally: - if stream is not sys.stdin: - stream.close() # in case a non-handled exception happened above - -if __name__ == "__main__": - main() diff --git a/IPython/utils/colorable.py b/IPython/utils/colorable.py index 9f7c5ac213c..611f19fedb4 100644 --- a/IPython/utils/colorable.py +++ b/IPython/utils/colorable.py @@ -22,5 +22,5 @@ class Colorable(Configurable): """ A subclass of configurable for all the classes that have a `default_scheme` """ - default_style=Unicode('lightbg').tag(config=True) + default_style=Unicode('LightBG').tag(config=True) diff --git a/IPython/utils/tests/test_pycolorize.py b/IPython/utils/tests/test_pycolorize.py index 6c7f36e76e1..57d4bfddec0 100644 --- a/IPython/utils/tests/test_pycolorize.py +++ b/IPython/utils/tests/test_pycolorize.py @@ -49,28 +49,28 @@ def __init__(self): def test_loop_colors(): - for scheme in ('Linux', 'NoColor','LightBG', 'Neutral'): + for style in ('Linux', 'NoColor','LightBG', 'Neutral'): def test_unicode_colorize(): - p = Parser() - f1 = p.format('1/0', 'str', scheme=scheme) - f2 = p.format(u'1/0', 'str', scheme=scheme) + p = Parser(style=style) + f1 = p.format('1/0', 'str') + f2 = p.format(u'1/0', 'str') nt.assert_equal(f1, f2) def test_parse_sample(): """and test writing to a buffer""" buf = io.StringIO() - p = Parser() - p.format(sample, buf, scheme=scheme) + p = Parser(style=style) + p.format(sample, buf) buf.seek(0) f1 = buf.read() nt.assert_not_in('ERROR', f1) def test_parse_error(): - p = Parser() - f1 = p.format(')', 'str', scheme=scheme) - if scheme != 'NoColor': + p = Parser(style=style) + f1 = p.format(')', 'str') + if style != 'NoColor': nt.assert_in('ERROR', f1) yield test_unicode_colorize From da5a98f891dfc1ae03c5dda449d83f8f8999dc2a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Oct 2016 16:51:45 +0100 Subject: [PATCH 0002/4199] Let IPython.lib.guisupport detect terminal-integrated event loops Closes gh-9974 --- IPython/core/interactiveshell.py | 2 ++ IPython/lib/guisupport.py | 27 ++++++++++++++-------- IPython/terminal/interactiveshell.py | 8 ++++--- IPython/terminal/pt_inputhooks/__init__.py | 13 ++++++----- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 0c6d8b4aa76..ab77854ad81 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2891,6 +2891,8 @@ def run_code(self, code_obj, result=None): # Things related to GUI support and pylab #------------------------------------------------------------------------- + active_eventloop = None + def enable_gui(self, gui=None): raise NotImplementedError('Implement enable_gui in a subclass') diff --git a/IPython/lib/guisupport.py b/IPython/lib/guisupport.py index e2fc1072ee7..5e13d4343c6 100644 --- a/IPython/lib/guisupport.py +++ b/IPython/lib/guisupport.py @@ -57,16 +57,10 @@ """ -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +from IPython.core.getipython import get_ipython #----------------------------------------------------------------------------- # wx @@ -84,6 +78,15 @@ def get_app_wx(*args, **kwargs): def is_event_loop_running_wx(app=None): """Is the wx event loop running.""" + # New way: check attribute on shell instance + ip = get_ipython() + if ip is not None: + if ip.active_eventloop and ip.active_eventloop == 'wx': + return True + # Fall through to checking the application, because Wx has a native way + # to check if the event loop is running, unlike Qt. + + # Old way: check Wx application if app is None: app = get_app_wx() if hasattr(app, '_in_event_loop'): @@ -118,6 +121,12 @@ def get_app_qt4(*args, **kwargs): def is_event_loop_running_qt4(app=None): """Is the qt4 event loop running.""" + # New way: check attribute on shell instance + ip = get_ipython() + if ip is not None: + return ip.active_eventloop and ip.active_eventloop.startswith('qt') + + # Old way: check attribute on QApplication singleton if app is None: app = get_app_qt4(['']) if hasattr(app, '_in_event_loop'): diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 9db67450c5a..0de3aaaf1d9 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -28,7 +28,7 @@ from .debugger import TerminalPdb, Pdb from .magics import TerminalMagics -from .pt_inputhooks import get_inputhook_func +from .pt_inputhooks import get_inputhook_name_and_func from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer from .shortcuts import register_ipython_shortcuts @@ -458,11 +458,13 @@ def inputhook(self, context): if self._inputhook is not None: self._inputhook(context) + active_eventloop = None def enable_gui(self, gui=None): if gui: - self._inputhook = get_inputhook_func(gui) + self.active_eventloop, self._inputhook =\ + get_inputhook_name_and_func(gui) else: - self._inputhook = None + self.active_eventloop = self._inputhook = None # Run !system commands directly, not through pipes, so terminal programs # work correctly. diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index 0f37b135a52..3766973e826 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -30,19 +30,20 @@ def __str__(self): "Supported event loops are: {}").format(self.name, ', '.join(backends + sorted(registered))) -def get_inputhook_func(gui): +def get_inputhook_name_and_func(gui): if gui in registered: - return registered[gui] + return gui, registered[gui] if gui not in backends: raise UnknownBackend(gui) if gui in aliases: - return get_inputhook_func(aliases[gui]) + return get_inputhook_name_and_func(aliases[gui]) + gui_mod = gui if gui == 'qt5': os.environ['QT_API'] = 'pyqt5' - gui = 'qt' + gui_mod = 'qt' - mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui) - return mod.inputhook + mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui_mod) + return gui, mod.inputhook From 61f82325e9848533f523e910c1f1e12175140c5b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Oct 2016 17:25:23 +0100 Subject: [PATCH 0003/4199] Update docs section on event loops This was outdated --- docs/source/interactive/reference.rst | 46 ++++++--------------------- 1 file changed, 10 insertions(+), 36 deletions(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index c18e32fb8ca..e79d713fecc 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -829,20 +829,10 @@ And pasting from IPython sessions works equally well:: GUI event loop support ====================== -.. versionadded:: 0.11 - The ``%gui`` magic and :mod:`IPython.lib.inputhook`. - IPython has excellent support for working interactively with Graphical User Interface (GUI) toolkits, such as wxPython, PyQt4/PySide, PyGTK and Tk. This is -implemented using Python's builtin ``PyOSInputHook`` hook. This implementation -is extremely robust compared to our previous thread-based version. The -advantages of this are: - -* GUIs can be enabled and disabled dynamically at runtime. -* The active GUI can be switched dynamically at runtime. -* In some cases, multiple GUIs can run simultaneously with no problems. -* There is a developer API in :mod:`IPython.lib.inputhook` for customizing - all of these things. +implemented by running the toolkit's event loop while IPython is waiting for +input. For users, enabling GUI event loop integration is simple. You simple use the :magic:`gui` magic as follows:: @@ -850,7 +840,7 @@ For users, enabling GUI event loop integration is simple. You simple use the %gui [GUINAME] With no arguments, ``%gui`` removes all GUI support. Valid ``GUINAME`` -arguments are ``wx``, ``qt``, ``gtk`` and ``tk``. +arguments include ``wx``, ``qt``, ``qt5``, ``gtk``, ``gtk3`` and ``tk``. Thus, to use wxPython interactively and create a running :class:`wx.App` object, do:: @@ -865,33 +855,17 @@ flag:: For information on IPython's matplotlib_ integration (and the ``matplotlib`` mode) see :ref:`this section `. -For developers that want to use IPython's GUI event loop integration in the -form of a library, these capabilities are exposed in library form in the -:mod:`IPython.lib.inputhook` and :mod:`IPython.lib.guisupport` modules. -Interested developers should see the module docstrings for more information, -but there are a few points that should be mentioned here. - -First, the ``PyOSInputHook`` approach only works in command line settings -where readline is activated. The integration with various eventloops -is handled somewhat differently (and more simply) when using the standalone -kernel, as in the qtconsole and notebook. +For developers that want to integrate additional event loops with IPython, see +:doc:`/config/eventloops`. -Second, when using the ``PyOSInputHook`` approach, a GUI application should -*not* start its event loop. Instead all of this is handled by the -``PyOSInputHook``. This means that applications that are meant to be used both +When running inside IPython with an integrated event loop, a GUI application +should *not* start its own event loop. This means that applications that are +meant to be used both in IPython and as standalone apps need to have special code to detects how the application is being run. We highly recommend using IPython's support for this. Since the details vary slightly between toolkits, we point you to the various -examples in our source directory :file:`examples/Embedding` that demonstrate -these capabilities. - -Third, unlike previous versions of IPython, we no longer "hijack" (replace -them with no-ops) the event loops. This is done to allow applications that -actually need to run the real event loops to do so. This is often needed to -process pending events at critical points. - -Finally, we also have a number of examples in our source directory -:file:`examples/Embedding` that demonstrate these capabilities. +examples in our source directory :file:`examples/IPython Kernel/gui/` that +demonstrate these capabilities. PyQt and PySide --------------- From 3f124e79ce8e5a31369dc422364c3a3b067b0ca3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 3 Oct 2016 17:25:55 +0100 Subject: [PATCH 0004/4199] Make python3 default Python for docs build --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index a6546d08e19..8358bed9c27 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -7,7 +7,7 @@ SPHINXBUILD = sphinx-build PAPER = SRCDIR = source BUILDDIR = build -PYTHON = python +PYTHON = python3 # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 From 3a5b79fca755449c28d6373e4a699e8fd91ee998 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 3 Oct 2016 23:53:56 -0700 Subject: [PATCH 0005/4199] Improve some (deprecation) warnings with versions and stacklevel. --- IPython/utils/path.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/IPython/utils/path.py b/IPython/utils/path.py index cca7a8e1edc..fa850812c7f 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -11,7 +11,6 @@ import errno import shutil import random -import tempfile import glob from warnings import warn from hashlib import md5 @@ -78,7 +77,7 @@ def unquote_filename(name, win32=(sys.platform=='win32')): unquoting is now taken care of by :func:`IPython.utils.process.arg_split`. """ warn("'unquote_filename' is deprecated since IPython 5.0 and should not " - "be used anymore", DeprecationWarning) + "be used anymore", DeprecationWarning, stacklevel=2) if win32: if name.startswith(("'", '"')) and name.endswith(("'", '"')): name = name[1:-1] @@ -105,7 +104,7 @@ def get_py_filename(name, force_win32=None): if force_win32 is not None: warn("The 'force_win32' argument to 'get_py_filename' is deprecated " "since IPython 5.0 and should not be used anymore", - DeprecationWarning) + DeprecationWarning, stacklevel=2) if not os.path.isfile(name) and not name.endswith('.py'): name += '.py' if os.path.isfile(name): @@ -256,31 +255,31 @@ def get_xdg_cache_dir(): @undoc def get_ipython_dir(): - warn("get_ipython_dir has moved to the IPython.paths module") + warn("get_ipython_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2) from IPython.paths import get_ipython_dir return get_ipython_dir() @undoc def get_ipython_cache_dir(): - warn("get_ipython_cache_dir has moved to the IPython.paths module") + warn("get_ipython_cache_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2) from IPython.paths import get_ipython_cache_dir return get_ipython_cache_dir() @undoc def get_ipython_package_dir(): - warn("get_ipython_package_dir has moved to the IPython.paths module") + warn("get_ipython_package_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2) from IPython.paths import get_ipython_package_dir return get_ipython_package_dir() @undoc def get_ipython_module_path(module_str): - warn("get_ipython_module_path has moved to the IPython.paths module") + warn("get_ipython_module_path has moved to the IPython.paths module since IPython 4.0.", stacklevel=2) from IPython.paths import get_ipython_module_path return get_ipython_module_path(module_str) @undoc def locate_profile(profile='default'): - warn("locate_profile has moved to the IPython.paths module") + warn("locate_profile has moved to the IPython.paths module since IPython 4.0.", stacklevel=2) from IPython.paths import locate_profile return locate_profile(profile=profile) @@ -371,7 +370,7 @@ def target_update(target,deps,cmd): def filehash(path): """Make an MD5 hash of a file, ignoring any differences in line ending characters.""" - warn("filehash() is deprecated") + warn("filehash() is deprecated since IPython 4.0", DeprecationWarning, stacklevel=2) with open(path, "rU") as f: return md5(py3compat.str_to_bytes(f.read())).hexdigest() From 509d8539c555ede6222d13cf1693388429213853 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 5 Oct 2016 20:20:39 +0200 Subject: [PATCH 0006/4199] Added mean + stdv to the %timeit magic - New tests pending - Corrected old ones --- IPython/core/magics/execution.py | 118 ++++++++++-------- IPython/core/tests/test_interactiveshell.py | 130 ++++++++++---------- 2 files changed, 129 insertions(+), 119 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index f445e8bd94a..336c63b1e95 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -15,6 +15,7 @@ import sys import time import timeit +import math from pdb import Restart # cProfile was added in Python2.5 @@ -71,23 +72,27 @@ class TimeitResult(object): """ - def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision): + def __init__(self, loops, repeat, average, stdev, all_runs, compile_time, precision): self.loops = loops self.repeat = repeat - self.best = best - self.worst = worst + self.average = average + self.stdev = stdev self.all_runs = all_runs self.compile_time = compile_time self._precision = precision def _repr_pretty_(self, p , cycle): - if self.loops == 1: # No s at "loops" if only one loop - unic = u"%d loop, best of %d: %s per loop" % (self.loops, self.repeat, - _format_time(self.best, self._precision)) - else: - unic = u"%d loops, best of %d: %s per loop" % (self.loops, self.repeat, - _format_time(self.best, self._precision)) - p.text(u'') + if self.loops == 1: # No s at "loops" if only one loop + unic = (u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" + % (self.loops, self.repeat, + _format_time(self.average, self._precision), + _format_time(self.stdev, self._precision))) + else: + unic = (u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" + % (self.loops, self.repeat, + _format_time(self.average, self._precision), + _format_time(self.stdev, self._precision))) + p.text(u'') class TimeitTemplateFiller(ast.NodeTransformer): @@ -117,7 +122,7 @@ def visit_For(self, node): class Timer(timeit.Timer): """Timer class that explicitly uses self.inner - + which is an undocumented implementation detail of CPython, not shared by PyPy. """ @@ -457,7 +462,7 @@ def run(self, parameter_s='', runner=None, """Run the named file inside IPython as a program. Usage:: - + %run [-n -i -e -G] [( -t [-N] | -d [-b] | -p [profile options] )] ( -m mod | file ) [args] @@ -652,7 +657,7 @@ def run(self, parameter_s='', runner=None, __name__save = self.shell.user_ns['__name__'] prog_ns['__name__'] = '__main__' main_mod = self.shell.user_module - + # Since '%run foo' emulates 'python foo.py' at the cmd line, we must # set the __file__ global in the script's namespace # TK: Is this necessary in interactive mode? @@ -852,7 +857,7 @@ def _run_with_debugger(self, code, code_ns, filename=None, continue else: break - + except: etype, value, tb = sys.exc_info() @@ -950,20 +955,20 @@ def timeit(self, line='', cell=None): :: In [1]: %timeit pass - 10000000 loops, best of 3: 53.3 ns per loop + 100000000 loops, average of 7: 5.48 ns +- 0.354 ns per loop (using standard deviation) In [2]: u = None In [3]: %timeit u is None - 10000000 loops, best of 3: 184 ns per loop + 10000000 loops, average of 7: 22.7 ns +- 2.33 ns per loop (using standard deviation) In [4]: %timeit -r 4 u == None - 1000000 loops, best of 4: 242 ns per loop + 10000000 loops, average of 4: 27.5 ns +- 2.91 ns per loop (using standard deviation) In [5]: import time In [6]: %timeit -n1 time.sleep(2) - 1 loop, best of 3: 2 s per loop + 1 loop, average of 7: 2 s +- 4.71 µs per loop (using standard deviation) The times reported by %timeit will be slightly higher than those @@ -978,10 +983,11 @@ def timeit(self, line='', cell=None): posix=False, strict=False) if stmt == "" and cell is None: return - + timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) - repeat = int(getattr(opts, "r", timeit.default_repeat)) + default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat + repeat = int(getattr(opts, "r", default_repeat)) precision = int(getattr(opts, "p", 3)) quiet = 'q' in opts return_result = 'o' in opts @@ -1036,22 +1042,26 @@ def timeit(self, line='', cell=None): # This is used to check if there is a huge difference between the # best and worst timings. # Issue: https://github.com/ipython/ipython/issues/6471 - worst_tuning = 0 if number == 0: # determine number so that 0.2 <= total time < 2.0 - number = 1 - for _ in range(1, 10): + for index in range(0, 10): + number = 10 ** index time_number = timer.timeit(number) - worst_tuning = max(worst_tuning, time_number / number) if time_number >= 0.2: break - number *= 10 + all_runs = timer.repeat(repeat, number) - best = min(all_runs) / number + timings = [ dt / number for dt in all_runs] + + def _avg(numbers): + return math.fsum(numbers) / len(numbers) + + def _stdev(numbers): + mean = _avg(numbers) + return (math.fsum([(x - mean) ** 2 for x in numbers]) / len(numbers)) ** 0.5 - worst = max(all_runs) / number - if worst_tuning: - worst = max(worst, worst_tuning) + average = _avg(timings) + stdev = _stdev(timings) if not quiet : # Check best timing is greater than zero to avoid a @@ -1059,20 +1069,20 @@ def timeit(self, line='', cell=None): # In cases where the slowest timing is lesser than a micosecond # we assume that it does not really matter if the fastest # timing is 4 times faster than the slowest timing or not. - if worst > 4 * best and best > 0 and worst > 1e-6: - print("The slowest run took %0.2f times longer than the " - "fastest. This could mean that an intermediate result " - "is being cached." % (worst / best)) if number == 1: # No s at "loops" if only one loop - print(u"%d loop, best of %d: %s per loop" % (number, repeat, - _format_time(best, precision))) + print(u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" + % (number, repeat, + _format_time(average, precision), + _format_time(stdev, precision))) else: - print(u"%d loops, best of %d: %s per loop" % (number, repeat, - _format_time(best, precision))) + print(u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" + % (number, repeat, + _format_time(average, precision), + _format_time(stdev, precision))) if tc > tc_min: print("Compiler time: %.2f s" % tc) if return_result: - return TimeitResult(number, repeat, best, worst, all_runs, tc, precision) + return TimeitResult(number, repeat, average, stdev, all_runs, tc, precision) @skip_doctest @needs_local_scope @@ -1083,16 +1093,16 @@ def time(self,line='', cell=None, local_ns=None): The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. - + This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - - In cell mode, you can time the cell body (a directly + - In cell mode, you can time the cell body (a directly following statement raises an error). - This function provides very basic timing functionality. Use the timeit + This function provides very basic timing functionality. Use the timeit magic for more control over the measurement. Examples @@ -1133,10 +1143,10 @@ def time(self,line='', cell=None, local_ns=None): """ # fail immediately if the given expression can't be compiled - + if line and cell: raise UsageError("Can't use statement directly after '%%time'!") - + if cell: expr = self.shell.input_transformer_manager.transform_cell(cell) else: @@ -1186,7 +1196,7 @@ def time(self,line='', cell=None, local_ns=None): cpu_user = end[0]-st[0] cpu_sys = end[1]-st[1] cpu_tot = cpu_user+cpu_sys - # On windows cpu_sys is always zero, so no new information to the next print + # On windows cpu_sys is always zero, so no new information to the next print if sys.platform != 'win32': print("CPU times: user %s, sys: %s, total: %s" % \ (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot))) @@ -1212,9 +1222,9 @@ def macro(self, parameter_s=''): so that magics are loaded in their transformed version to valid Python. If this option is given, the raw input as typed at the command line is used instead. - - -q: quiet macro definition. By default, a tag line is printed - to indicate the macro has been created, and then the contents of + + -q: quiet macro definition. By default, a tag line is printed + to indicate the macro has been created, and then the contents of the macro are printed. If this option is given, then no printout is produced once the macro is created. @@ -1277,7 +1287,7 @@ def macro(self, parameter_s=''): return macro = Macro(lines) self.shell.define_macro(name, macro) - if not ( 'q' in opts) : + if not ( 'q' in opts) : print('Macro `%s` created. To execute, type its name (without quotes).' % name) print('=== Macro contents: ===') print(macro, end=' ') @@ -1323,11 +1333,11 @@ def parse_breakpoint(text, current_file): return current_file, int(text) else: return text[:colon], int(text[colon+1:]) - + def _format_time(timespan, precision=3): """Formats the timespan in a human readable form""" import math - + if timespan >= 60.0: # we have more than a minute, format that in a human readable form # Idea from http://snipplr.com/view/5713/ @@ -1343,13 +1353,13 @@ def _format_time(timespan, precision=3): break return " ".join(time) - + # Unfortunately the unicode 'micro' symbol can cause problems in - # certain terminals. + # certain terminals. # See bug: https://bugs.launchpad.net/ipython/+bug/348466 # Try to prevent crashes by being more secure than it needs to # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set. - units = [u"s", u"ms",u'us',"ns"] # the save value + units = [u"s", u"ms",u'us',"ns"] # the save value if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: try: u'\xb5'.encode(sys.stdout.encoding) @@ -1357,7 +1367,7 @@ def _format_time(timespan, precision=3): except: pass scaling = [1, 1e3, 1e6, 1e9] - + if timespan > 0.0: order = min(-int(math.floor(math.log10(timespan)) // 3), 3) else: diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index db22c158b66..ba92852525c 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -120,16 +120,16 @@ def test_In_variable(self): newlen = len(ip.user_ns['In']) self.assertEqual(oldlen+1, newlen) self.assertEqual(ip.user_ns['In'][-1],'1;') - + def test_magic_names_in_string(self): ip.run_cell('a = """\n%exit\n"""') self.assertEqual(ip.user_ns['a'], '\n%exit\n') - + def test_trailing_newline(self): """test that running !(command) does not raise a SyntaxError""" ip.run_cell('!(true)\n', False) ip.run_cell('!(true)\n\n\n', False) - + def test_gh_597(self): """Pretty-printing lists of objects with non-ascii reprs may cause problems.""" @@ -139,7 +139,7 @@ def __repr__(self): import IPython.core.formatters f = IPython.core.formatters.PlainTextFormatter() f([Spam(),Spam()]) - + def test_future_flags(self): """Check that future flags are used for parsing code (gh-777)""" @@ -162,7 +162,7 @@ def test_future_unicode(self): finally: # Reset compiler flags so we don't mess up other tests. ip.compile.reset_compiler_flags() - + def test_can_pickle(self): "Can we pickle objects defined interactively (GH-29)" ip = get_ipython() @@ -171,9 +171,9 @@ def test_can_pickle(self): " def __init__(self,x=[]):\n" " list.__init__(self,x)")) ip.run_cell("w=Mylist([1,2,3])") - + from pickle import dumps - + # We need to swap in our main module - this is only necessary # inside the test framework, because IPython puts the interactive module # in place (but the test framework undoes this). @@ -184,7 +184,7 @@ def test_can_pickle(self): finally: sys.modules['__main__'] = _main self.assertTrue(isinstance(res, bytes)) - + def test_global_ns(self): "Code in functions must be able to access variables outside them." ip = get_ipython() @@ -234,7 +234,7 @@ def test_var_expand(self): ip.user_ns['f'] = b'Ca\xc3\xb1o' # This should not raise any exception: ip.var_expand(u'echo $f') - + def test_var_expand_local(self): """Test local variable expansion in !system and %magic calls""" # !system @@ -244,7 +244,7 @@ def test_var_expand_local(self): ' return ret[0]\n') res = ip.user_ns['test']() nt.assert_in('ttt', res) - + # %magic ip.run_cell('def makemacro():\n' ' macroname = "macro_var_expand_locals"\n' @@ -252,10 +252,10 @@ def test_var_expand_local(self): ip.user_ns['codestr'] = "str(12)" ip.run_cell('makemacro()') nt.assert_in('macro_var_expand_locals', ip.user_ns) - + def test_var_expand_self(self): """Test variable expansion with the name 'self', which was failing. - + See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218 """ ip.run_cell('class cTest:\n' @@ -264,7 +264,7 @@ def test_var_expand_self(self): ' res = !echo Variable: {self.classvar}\n' ' return res[0]\n') nt.assert_in('see me', ip.user_ns['cTest']().test()) - + def test_bad_var_expand(self): """var_expand on invalid formats shouldn't raise""" # SyntaxError @@ -273,19 +273,19 @@ def test_bad_var_expand(self): self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}") # ZeroDivisionError self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}") - + def test_silent_postexec(self): """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks""" pre_explicit = mock.Mock() pre_always = mock.Mock() post_explicit = mock.Mock() post_always = mock.Mock() - + ip.events.register('pre_run_cell', pre_explicit) ip.events.register('pre_execute', pre_always) ip.events.register('post_run_cell', post_explicit) ip.events.register('post_execute', post_always) - + try: ip.run_cell("1", silent=True) assert pre_always.called @@ -303,29 +303,29 @@ def test_silent_postexec(self): ip.events.unregister('pre_execute', pre_always) ip.events.unregister('post_run_cell', post_explicit) ip.events.unregister('post_execute', post_always) - + def test_silent_noadvance(self): """run_cell(silent=True) doesn't advance execution_count""" ec = ip.execution_count # silent should force store_history=False ip.run_cell("1", store_history=True, silent=True) - + self.assertEqual(ec, ip.execution_count) # double-check that non-silent exec did what we expected # silent to avoid ip.run_cell("1", store_history=True) self.assertEqual(ec+1, ip.execution_count) - + def test_silent_nodisplayhook(self): """run_cell(silent=True) doesn't trigger displayhook""" d = dict(called=False) - + trap = ip.display_trap save_hook = trap.hook - + def failing_hook(*args, **kwargs): d['called'] = True - + try: trap.hook = failing_hook res = ip.run_cell("1", silent=True) @@ -350,10 +350,10 @@ def test_print_softspace(self): In [2]: print 1,; print 2 1 2 """ - + def test_ofind_line_magic(self): from IPython.core.magic import register_line_magic - + @register_line_magic def lmagic(line): "A line magic" @@ -364,10 +364,10 @@ def lmagic(line): namespace = 'IPython internal', obj= lmagic.__wrapped__, parent = None) nt.assert_equal(lfind, info) - + def test_ofind_cell_magic(self): from IPython.core.magic import register_cell_magic - + @register_cell_magic def cmagic(line, cell): "A cell magic" @@ -454,7 +454,7 @@ def test_custom_exception(self): def my_handler(shell, etype, value, tb, tb_offset=None): called.append(etype) shell.showtraceback((etype, value, tb), tb_offset=tb_offset) - + ip.set_custom_exc((ValueError,), my_handler) try: res = ip.run_cell("raise ValueError('test')") @@ -465,7 +465,7 @@ def my_handler(shell, etype, value, tb, tb_offset=None): finally: # Reset the custom exception hook ip.set_custom_exc((), None) - + @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3") def test_future_environment(self): "Can we run code with & without the shell's __future__ imports?" @@ -474,7 +474,7 @@ def test_future_environment(self): self.assertEqual(ip.user_ns['a'], 0.5) ip.run_cell("b = 1/2", shell_futures=False) self.assertEqual(ip.user_ns['b'], 0) - + ip.compile.reset_compiler_flags() # This shouldn't leak to the shell's compiler ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False) @@ -551,7 +551,7 @@ def test_exit_code_ok(self): def test_exit_code_error(self): self.system('exit 1') self.assertEqual(ip.user_ns['_exit_code'], 1) - + @skipif(not hasattr(signal, 'SIGALRM')) def test_exit_code_signal(self): self.mktmp("import signal, time\n" @@ -559,7 +559,7 @@ def test_exit_code_signal(self): "time.sleep(1)\n") self.system("%s %s" % (sys.executable, self.fname)) self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM) - + @onlyif_cmds_exist("csh") def test_exit_code_signal_csh(self): SHELL = os.environ.get('SHELL', None) @@ -630,56 +630,56 @@ class TestAstTransform(unittest.TestCase): def setUp(self): self.negator = Negator() ip.ast_transformers.append(self.negator) - + def tearDown(self): ip.ast_transformers.remove(self.negator) - + def test_run_cell(self): with tt.AssertPrints('-34'): ip.run_cell('print (12 + 22)') - + # A named reference to a number shouldn't be transformed. ip.user_ns['n'] = 55 with tt.AssertNotPrints('-55'): ip.run_cell('print (n)') - + def test_timeit(self): called = set() def f(x): called.add(x) ip.push({'f':f}) - - with tt.AssertPrints("best of "): + + with tt.AssertPrints("average of "): ip.run_line_magic("timeit", "-n1 f(1)") self.assertEqual(called, {-1}) called.clear() - - with tt.AssertPrints("best of "): + + with tt.AssertPrints("average of "): ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)") self.assertEqual(called, {-2, -3}) - + def test_time(self): called = [] def f(x): called.append(x) ip.push({'f':f}) - + # Test with an expression with tt.AssertPrints("Wall time: "): ip.run_line_magic("time", "f(5+9)") self.assertEqual(called, [-14]) called[:] = [] - + # Test with a statement (different code path) with tt.AssertPrints("Wall time: "): ip.run_line_magic("time", "a = f(-3 + -2)") self.assertEqual(called, [5]) - + def test_macro(self): ip.push({'a':10}) # The AST transformation makes this do a+=-1 ip.define_macro("amacro", "a+=1\nprint(a)") - + with tt.AssertPrints("9"): ip.run_cell("amacro") with tt.AssertPrints("8"): @@ -697,37 +697,37 @@ class TestAstTransform2(unittest.TestCase): def setUp(self): self.intwrapper = IntegerWrapper() ip.ast_transformers.append(self.intwrapper) - + self.calls = [] def Integer(*args): self.calls.append(args) return args ip.push({"Integer": Integer}) - + def tearDown(self): ip.ast_transformers.remove(self.intwrapper) del ip.user_ns['Integer'] - + def test_run_cell(self): ip.run_cell("n = 2") self.assertEqual(self.calls, [(2,)]) - + # This shouldn't throw an error ip.run_cell("o = 2.0") self.assertEqual(ip.user_ns['o'], 2.0) - + def test_timeit(self): called = set() def f(x): called.add(x) ip.push({'f':f}) - - with tt.AssertPrints("best of "): + + with tt.AssertPrints("average of "): ip.run_line_magic("timeit", "-n1 f(1)") self.assertEqual(called, {(1,)}) called.clear() - - with tt.AssertPrints("best of "): + + with tt.AssertPrints("average of "): ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)") self.assertEqual(called, {(2,), (3,)}) @@ -740,10 +740,10 @@ class TestAstTransformError(unittest.TestCase): def test_unregistering(self): err_transformer = ErrorTransformer() ip.ast_transformers.append(err_transformer) - + with tt.AssertPrints("unregister", channel='stderr'): ip.run_cell("1 + 2") - + # This should have been removed. nt.assert_not_in(err_transformer, ip.ast_transformers) @@ -792,18 +792,18 @@ def test__IPYTHON__(): class DummyRepr(object): def __repr__(self): return "DummyRepr" - + def _repr_html_(self): return "dummy" - + def _repr_javascript_(self): return "console.log('hi');", {'key': 'value'} - + def test_user_variables(): # enable all formatters ip.display_formatter.active_types = ip.display_formatter.format_types - + ip.user_ns['dummy'] = d = DummyRepr() keys = {'dummy', 'doesnotexist'} r = ip.user_expressions({ key:key for key in keys}) @@ -818,14 +818,14 @@ def test_user_variables(): js, jsmd = d._repr_javascript_() nt.assert_equal(data.get('application/javascript'), js) nt.assert_equal(metadata.get('application/javascript'), jsmd) - + dne = r['doesnotexist'] nt.assert_equal(dne['status'], 'error') nt.assert_equal(dne['ename'], 'NameError') - + # back to text only ip.display_formatter.active_types = ['text/plain'] - + def test_user_expression(): # enable all formatters ip.display_formatter.active_types = ip.display_formatter.format_types @@ -843,14 +843,14 @@ def test_user_expression(): data = a['data'] metadata = a['metadata'] nt.assert_equal(data.get('text/plain'), '3') - + b = r['b'] nt.assert_equal(b['status'], 'error') nt.assert_equal(b['ename'], 'ZeroDivisionError') - + # back to text only ip.display_formatter.active_types = ['text/plain'] - + From 8be2bc9d5ce59aa63e2f8eb3f3b624ff12cd2231 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 5 Oct 2016 20:21:36 +0200 Subject: [PATCH 0007/4199] Deleted math import inside time format function --- IPython/core/magics/execution.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 336c63b1e95..35ed2f71c5c 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -1336,7 +1336,6 @@ def parse_breakpoint(text, current_file): def _format_time(timespan, precision=3): """Formats the timespan in a human readable form""" - import math if timespan >= 60.0: # we have more than a minute, format that in a human readable form From 1c446a83d75a9532577031d082ecc753bd8f1eb7 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 5 Oct 2016 23:24:04 +0200 Subject: [PATCH 0008/4199] Recovered trailing whitespace --- IPython/core/magics/execution.py | 40 +++---- IPython/core/tests/test_interactiveshell.py | 118 ++++++++++---------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 35ed2f71c5c..08382ed8866 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -122,7 +122,7 @@ def visit_For(self, node): class Timer(timeit.Timer): """Timer class that explicitly uses self.inner - + which is an undocumented implementation detail of CPython, not shared by PyPy. """ @@ -462,7 +462,7 @@ def run(self, parameter_s='', runner=None, """Run the named file inside IPython as a program. Usage:: - + %run [-n -i -e -G] [( -t [-N] | -d [-b] | -p [profile options] )] ( -m mod | file ) [args] @@ -657,7 +657,7 @@ def run(self, parameter_s='', runner=None, __name__save = self.shell.user_ns['__name__'] prog_ns['__name__'] = '__main__' main_mod = self.shell.user_module - + # Since '%run foo' emulates 'python foo.py' at the cmd line, we must # set the __file__ global in the script's namespace # TK: Is this necessary in interactive mode? @@ -857,7 +857,7 @@ def _run_with_debugger(self, code, code_ns, filename=None, continue else: break - + except: etype, value, tb = sys.exc_info() @@ -983,7 +983,7 @@ def timeit(self, line='', cell=None): posix=False, strict=False) if stmt == "" and cell is None: return - + timefunc = timeit.default_timer number = int(getattr(opts, "n", 0)) default_repeat = 7 if timeit.default_repeat < 7 else timeit.default_repeat @@ -1093,16 +1093,16 @@ def time(self,line='', cell=None, local_ns=None): The CPU and wall clock times are printed, and the value of the expression (if any) is returned. Note that under Win32, system time is always reported as 0, since it can not be measured. - + This function can be used both as a line and cell magic: - In line mode you can time a single-line statement (though multiple ones can be chained with using semicolons). - - In cell mode, you can time the cell body (a directly + - In cell mode, you can time the cell body (a directly following statement raises an error). - This function provides very basic timing functionality. Use the timeit + This function provides very basic timing functionality. Use the timeit magic for more control over the measurement. Examples @@ -1143,10 +1143,10 @@ def time(self,line='', cell=None, local_ns=None): """ # fail immediately if the given expression can't be compiled - + if line and cell: raise UsageError("Can't use statement directly after '%%time'!") - + if cell: expr = self.shell.input_transformer_manager.transform_cell(cell) else: @@ -1196,7 +1196,7 @@ def time(self,line='', cell=None, local_ns=None): cpu_user = end[0]-st[0] cpu_sys = end[1]-st[1] cpu_tot = cpu_user+cpu_sys - # On windows cpu_sys is always zero, so no new information to the next print + # On windows cpu_sys is always zero, so no new information to the next print if sys.platform != 'win32': print("CPU times: user %s, sys: %s, total: %s" % \ (_format_time(cpu_user),_format_time(cpu_sys),_format_time(cpu_tot))) @@ -1222,9 +1222,9 @@ def macro(self, parameter_s=''): so that magics are loaded in their transformed version to valid Python. If this option is given, the raw input as typed at the command line is used instead. - - -q: quiet macro definition. By default, a tag line is printed - to indicate the macro has been created, and then the contents of + + -q: quiet macro definition. By default, a tag line is printed + to indicate the macro has been created, and then the contents of the macro are printed. If this option is given, then no printout is produced once the macro is created. @@ -1287,7 +1287,7 @@ def macro(self, parameter_s=''): return macro = Macro(lines) self.shell.define_macro(name, macro) - if not ( 'q' in opts) : + if not ( 'q' in opts) : print('Macro `%s` created. To execute, type its name (without quotes).' % name) print('=== Macro contents: ===') print(macro, end=' ') @@ -1333,7 +1333,7 @@ def parse_breakpoint(text, current_file): return current_file, int(text) else: return text[:colon], int(text[colon+1:]) - + def _format_time(timespan, precision=3): """Formats the timespan in a human readable form""" @@ -1352,13 +1352,13 @@ def _format_time(timespan, precision=3): break return " ".join(time) - + # Unfortunately the unicode 'micro' symbol can cause problems in - # certain terminals. + # certain terminals. # See bug: https://bugs.launchpad.net/ipython/+bug/348466 # Try to prevent crashes by being more secure than it needs to # E.g. eclipse is able to print a µ, but has no sys.stdout.encoding set. - units = [u"s", u"ms",u'us',"ns"] # the save value + units = [u"s", u"ms",u'us',"ns"] # the save value if hasattr(sys.stdout, 'encoding') and sys.stdout.encoding: try: u'\xb5'.encode(sys.stdout.encoding) @@ -1366,7 +1366,7 @@ def _format_time(timespan, precision=3): except: pass scaling = [1, 1e3, 1e6, 1e9] - + if timespan > 0.0: order = min(-int(math.floor(math.log10(timespan)) // 3), 3) else: diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index ba92852525c..058f412f778 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -120,16 +120,16 @@ def test_In_variable(self): newlen = len(ip.user_ns['In']) self.assertEqual(oldlen+1, newlen) self.assertEqual(ip.user_ns['In'][-1],'1;') - + def test_magic_names_in_string(self): ip.run_cell('a = """\n%exit\n"""') self.assertEqual(ip.user_ns['a'], '\n%exit\n') - + def test_trailing_newline(self): """test that running !(command) does not raise a SyntaxError""" ip.run_cell('!(true)\n', False) ip.run_cell('!(true)\n\n\n', False) - + def test_gh_597(self): """Pretty-printing lists of objects with non-ascii reprs may cause problems.""" @@ -139,7 +139,7 @@ def __repr__(self): import IPython.core.formatters f = IPython.core.formatters.PlainTextFormatter() f([Spam(),Spam()]) - + def test_future_flags(self): """Check that future flags are used for parsing code (gh-777)""" @@ -162,7 +162,7 @@ def test_future_unicode(self): finally: # Reset compiler flags so we don't mess up other tests. ip.compile.reset_compiler_flags() - + def test_can_pickle(self): "Can we pickle objects defined interactively (GH-29)" ip = get_ipython() @@ -171,9 +171,9 @@ def test_can_pickle(self): " def __init__(self,x=[]):\n" " list.__init__(self,x)")) ip.run_cell("w=Mylist([1,2,3])") - + from pickle import dumps - + # We need to swap in our main module - this is only necessary # inside the test framework, because IPython puts the interactive module # in place (but the test framework undoes this). @@ -184,7 +184,7 @@ def test_can_pickle(self): finally: sys.modules['__main__'] = _main self.assertTrue(isinstance(res, bytes)) - + def test_global_ns(self): "Code in functions must be able to access variables outside them." ip = get_ipython() @@ -234,7 +234,7 @@ def test_var_expand(self): ip.user_ns['f'] = b'Ca\xc3\xb1o' # This should not raise any exception: ip.var_expand(u'echo $f') - + def test_var_expand_local(self): """Test local variable expansion in !system and %magic calls""" # !system @@ -244,7 +244,7 @@ def test_var_expand_local(self): ' return ret[0]\n') res = ip.user_ns['test']() nt.assert_in('ttt', res) - + # %magic ip.run_cell('def makemacro():\n' ' macroname = "macro_var_expand_locals"\n' @@ -252,10 +252,10 @@ def test_var_expand_local(self): ip.user_ns['codestr'] = "str(12)" ip.run_cell('makemacro()') nt.assert_in('macro_var_expand_locals', ip.user_ns) - + def test_var_expand_self(self): """Test variable expansion with the name 'self', which was failing. - + See https://github.com/ipython/ipython/issues/1878#issuecomment-7698218 """ ip.run_cell('class cTest:\n' @@ -264,7 +264,7 @@ def test_var_expand_self(self): ' res = !echo Variable: {self.classvar}\n' ' return res[0]\n') nt.assert_in('see me', ip.user_ns['cTest']().test()) - + def test_bad_var_expand(self): """var_expand on invalid formats shouldn't raise""" # SyntaxError @@ -273,19 +273,19 @@ def test_bad_var_expand(self): self.assertEqual(ip.var_expand(u"{asdf}"), u"{asdf}") # ZeroDivisionError self.assertEqual(ip.var_expand(u"{1/0}"), u"{1/0}") - + def test_silent_postexec(self): """run_cell(silent=True) doesn't invoke pre/post_run_cell callbacks""" pre_explicit = mock.Mock() pre_always = mock.Mock() post_explicit = mock.Mock() post_always = mock.Mock() - + ip.events.register('pre_run_cell', pre_explicit) ip.events.register('pre_execute', pre_always) ip.events.register('post_run_cell', post_explicit) ip.events.register('post_execute', post_always) - + try: ip.run_cell("1", silent=True) assert pre_always.called @@ -303,29 +303,29 @@ def test_silent_postexec(self): ip.events.unregister('pre_execute', pre_always) ip.events.unregister('post_run_cell', post_explicit) ip.events.unregister('post_execute', post_always) - + def test_silent_noadvance(self): """run_cell(silent=True) doesn't advance execution_count""" ec = ip.execution_count # silent should force store_history=False ip.run_cell("1", store_history=True, silent=True) - + self.assertEqual(ec, ip.execution_count) # double-check that non-silent exec did what we expected # silent to avoid ip.run_cell("1", store_history=True) self.assertEqual(ec+1, ip.execution_count) - + def test_silent_nodisplayhook(self): """run_cell(silent=True) doesn't trigger displayhook""" d = dict(called=False) - + trap = ip.display_trap save_hook = trap.hook - + def failing_hook(*args, **kwargs): d['called'] = True - + try: trap.hook = failing_hook res = ip.run_cell("1", silent=True) @@ -350,10 +350,10 @@ def test_print_softspace(self): In [2]: print 1,; print 2 1 2 """ - + def test_ofind_line_magic(self): from IPython.core.magic import register_line_magic - + @register_line_magic def lmagic(line): "A line magic" @@ -364,10 +364,10 @@ def lmagic(line): namespace = 'IPython internal', obj= lmagic.__wrapped__, parent = None) nt.assert_equal(lfind, info) - + def test_ofind_cell_magic(self): from IPython.core.magic import register_cell_magic - + @register_cell_magic def cmagic(line, cell): "A cell magic" @@ -454,7 +454,7 @@ def test_custom_exception(self): def my_handler(shell, etype, value, tb, tb_offset=None): called.append(etype) shell.showtraceback((etype, value, tb), tb_offset=tb_offset) - + ip.set_custom_exc((ValueError,), my_handler) try: res = ip.run_cell("raise ValueError('test')") @@ -465,7 +465,7 @@ def my_handler(shell, etype, value, tb, tb_offset=None): finally: # Reset the custom exception hook ip.set_custom_exc((), None) - + @skipif(sys.version_info[0] >= 3, "no differences with __future__ in py3") def test_future_environment(self): "Can we run code with & without the shell's __future__ imports?" @@ -474,7 +474,7 @@ def test_future_environment(self): self.assertEqual(ip.user_ns['a'], 0.5) ip.run_cell("b = 1/2", shell_futures=False) self.assertEqual(ip.user_ns['b'], 0) - + ip.compile.reset_compiler_flags() # This shouldn't leak to the shell's compiler ip.run_cell("from __future__ import division \nc=1/2", shell_futures=False) @@ -551,7 +551,7 @@ def test_exit_code_ok(self): def test_exit_code_error(self): self.system('exit 1') self.assertEqual(ip.user_ns['_exit_code'], 1) - + @skipif(not hasattr(signal, 'SIGALRM')) def test_exit_code_signal(self): self.mktmp("import signal, time\n" @@ -559,7 +559,7 @@ def test_exit_code_signal(self): "time.sleep(1)\n") self.system("%s %s" % (sys.executable, self.fname)) self.assertEqual(ip.user_ns['_exit_code'], -signal.SIGALRM) - + @onlyif_cmds_exist("csh") def test_exit_code_signal_csh(self): SHELL = os.environ.get('SHELL', None) @@ -630,26 +630,26 @@ class TestAstTransform(unittest.TestCase): def setUp(self): self.negator = Negator() ip.ast_transformers.append(self.negator) - + def tearDown(self): ip.ast_transformers.remove(self.negator) - + def test_run_cell(self): with tt.AssertPrints('-34'): ip.run_cell('print (12 + 22)') - + # A named reference to a number shouldn't be transformed. ip.user_ns['n'] = 55 with tt.AssertNotPrints('-55'): ip.run_cell('print (n)') - + def test_timeit(self): called = set() def f(x): called.add(x) ip.push({'f':f}) - - with tt.AssertPrints("average of "): + + with tt.AssertPrints("best of "): ip.run_line_magic("timeit", "-n1 f(1)") self.assertEqual(called, {-1}) called.clear() @@ -657,29 +657,29 @@ def f(x): with tt.AssertPrints("average of "): ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)") self.assertEqual(called, {-2, -3}) - + def test_time(self): called = [] def f(x): called.append(x) ip.push({'f':f}) - + # Test with an expression with tt.AssertPrints("Wall time: "): ip.run_line_magic("time", "f(5+9)") self.assertEqual(called, [-14]) called[:] = [] - + # Test with a statement (different code path) with tt.AssertPrints("Wall time: "): ip.run_line_magic("time", "a = f(-3 + -2)") self.assertEqual(called, [5]) - + def test_macro(self): ip.push({'a':10}) # The AST transformation makes this do a+=-1 ip.define_macro("amacro", "a+=1\nprint(a)") - + with tt.AssertPrints("9"): ip.run_cell("amacro") with tt.AssertPrints("8"): @@ -697,25 +697,25 @@ class TestAstTransform2(unittest.TestCase): def setUp(self): self.intwrapper = IntegerWrapper() ip.ast_transformers.append(self.intwrapper) - + self.calls = [] def Integer(*args): self.calls.append(args) return args ip.push({"Integer": Integer}) - + def tearDown(self): ip.ast_transformers.remove(self.intwrapper) del ip.user_ns['Integer'] - + def test_run_cell(self): ip.run_cell("n = 2") self.assertEqual(self.calls, [(2,)]) - + # This shouldn't throw an error ip.run_cell("o = 2.0") self.assertEqual(ip.user_ns['o'], 2.0) - + def test_timeit(self): called = set() def f(x): @@ -740,10 +740,10 @@ class TestAstTransformError(unittest.TestCase): def test_unregistering(self): err_transformer = ErrorTransformer() ip.ast_transformers.append(err_transformer) - + with tt.AssertPrints("unregister", channel='stderr'): ip.run_cell("1 + 2") - + # This should have been removed. nt.assert_not_in(err_transformer, ip.ast_transformers) @@ -792,18 +792,18 @@ def test__IPYTHON__(): class DummyRepr(object): def __repr__(self): return "DummyRepr" - + def _repr_html_(self): return "dummy" - + def _repr_javascript_(self): return "console.log('hi');", {'key': 'value'} - + def test_user_variables(): # enable all formatters ip.display_formatter.active_types = ip.display_formatter.format_types - + ip.user_ns['dummy'] = d = DummyRepr() keys = {'dummy', 'doesnotexist'} r = ip.user_expressions({ key:key for key in keys}) @@ -818,14 +818,14 @@ def test_user_variables(): js, jsmd = d._repr_javascript_() nt.assert_equal(data.get('application/javascript'), js) nt.assert_equal(metadata.get('application/javascript'), jsmd) - + dne = r['doesnotexist'] nt.assert_equal(dne['status'], 'error') nt.assert_equal(dne['ename'], 'NameError') - + # back to text only ip.display_formatter.active_types = ['text/plain'] - + def test_user_expression(): # enable all formatters ip.display_formatter.active_types = ip.display_formatter.format_types @@ -843,14 +843,14 @@ def test_user_expression(): data = a['data'] metadata = a['metadata'] nt.assert_equal(data.get('text/plain'), '3') - + b = r['b'] nt.assert_equal(b['status'], 'error') nt.assert_equal(b['ename'], 'ZeroDivisionError') - + # back to text only ip.display_formatter.active_types = ['text/plain'] - + From e7913fac8d11b6ca3827e03caf88b7a757097183 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 5 Oct 2016 23:48:02 +0200 Subject: [PATCH 0009/4199] Refactor TimeitResult --- IPython/core/magics/execution.py | 74 ++++++++++++++++---------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 08382ed8866..982e309a748 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -72,27 +72,45 @@ class TimeitResult(object): """ - def __init__(self, loops, repeat, average, stdev, all_runs, compile_time, precision): + def __init__(self, loops, repeat, all_runs, compile_time, precision): self.loops = loops self.repeat = repeat - self.average = average - self.stdev = stdev self.all_runs = all_runs self.compile_time = compile_time self._precision = precision - - def _repr_pretty_(self, p , cycle): + self.timings = [ dt / self.loops for dt in all_runs] + self._average = None + self._stdev = None + + @property + def average(self): + if self._average is None: + self._average = math.fsum(self.timings) / len(self.timings) + return self._average + + @property + def stdev(self): + if self._stdev is None: + mean = self.average + self._stdev = (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 + return self._stdev + + def __str__(self): if self.loops == 1: # No s at "loops" if only one loop - unic = (u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" - % (self.loops, self.repeat, - _format_time(self.average, self._precision), - _format_time(self.stdev, self._precision))) + return (u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" + % (self.loops, self.repeat, + _format_time(self.average, self._precision), + _format_time(self.stdev, self._precision))) else: - unic = (u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" - % (self.loops, self.repeat, - _format_time(self.average, self._precision), - _format_time(self.stdev, self._precision))) - p.text(u'') + return (u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" + % (self.loops, self.repeat, + _format_time(self.average, self._precision), + _format_time(self.stdev, self._precision))) + + def _repr_pretty_(self, p , cycle): + unic = self.__str__() + p.text(u'') + class TimeitTemplateFiller(ast.NodeTransformer): @@ -1051,17 +1069,7 @@ def timeit(self, line='', cell=None): break all_runs = timer.repeat(repeat, number) - timings = [ dt / number for dt in all_runs] - - def _avg(numbers): - return math.fsum(numbers) / len(numbers) - - def _stdev(numbers): - mean = _avg(numbers) - return (math.fsum([(x - mean) ** 2 for x in numbers]) / len(numbers)) ** 0.5 - - average = _avg(timings) - stdev = _stdev(timings) + timeit_result = TimeitResult(number, repeat, all_runs, tc, precision) if not quiet : # Check best timing is greater than zero to avoid a @@ -1069,20 +1077,12 @@ def _stdev(numbers): # In cases where the slowest timing is lesser than a micosecond # we assume that it does not really matter if the fastest # timing is 4 times faster than the slowest timing or not. - if number == 1: # No s at "loops" if only one loop - print(u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" - % (number, repeat, - _format_time(average, precision), - _format_time(stdev, precision))) - else: - print(u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" - % (number, repeat, - _format_time(average, precision), - _format_time(stdev, precision))) - if tc > tc_min: + print( timeit_result ) + + if tc > tc_min: print("Compiler time: %.2f s" % tc) if return_result: - return TimeitResult(number, repeat, average, stdev, all_runs, tc, precision) + return timeit_result @skip_doctest @needs_local_scope From 395b333769016ff8ab2446212c88e4b17442acb9 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 5 Oct 2016 23:49:51 +0200 Subject: [PATCH 0010/4199] Corrected old test (now with trailing withespace) --- IPython/core/tests/test_interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 058f412f778..c23ce40d02d 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -649,7 +649,7 @@ def f(x): called.add(x) ip.push({'f':f}) - with tt.AssertPrints("best of "): + with tt.AssertPrints("average of "): ip.run_line_magic("timeit", "-n1 f(1)") self.assertEqual(called, {-1}) called.clear() From 8504424ef1a9cf80706a00e6ed8f624a83f9b52e Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Thu, 6 Oct 2016 00:08:18 +0200 Subject: [PATCH 0011/4199] Removed caching from the TimeitResult properties --- IPython/core/magics/execution.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 982e309a748..9c22e3624a2 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -79,21 +79,15 @@ def __init__(self, loops, repeat, all_runs, compile_time, precision): self.compile_time = compile_time self._precision = precision self.timings = [ dt / self.loops for dt in all_runs] - self._average = None - self._stdev = None @property def average(self): - if self._average is None: - self._average = math.fsum(self.timings) / len(self.timings) - return self._average + return math.fsum(self.timings) / len(self.timings) @property def stdev(self): - if self._stdev is None: - mean = self.average - self._stdev = (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 - return self._stdev + mean = self.average + return self._stdev = (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 def __str__(self): if self.loops == 1: # No s at "loops" if only one loop From 2424f7c9aac544c700e5ccd70a02aed760c22be6 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Thu, 6 Oct 2016 00:10:31 +0200 Subject: [PATCH 0012/4199] Corrected a typo --- IPython/core/magics/execution.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 9c22e3624a2..41f3bf60912 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -87,7 +87,7 @@ def average(self): @property def stdev(self): mean = self.average - return self._stdev = (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 + return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 def __str__(self): if self.loops == 1: # No s at "loops" if only one loop From f259765c84be512aafbf9e5e0dd76f48ee106129 Mon Sep 17 00:00:00 2001 From: Tamir Bahar Date: Thu, 6 Oct 2016 01:13:15 +0300 Subject: [PATCH 0013/4199] Only suggest a named argument once. Added a check to the `python_func_kw_matches` completer to not show named arguments after they've been used in the function call. --- IPython/core/completer.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index f431146841a..d9419048464 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -886,8 +886,7 @@ def python_func_kw_matches(self,text): # parenthesis before the cursor # e.g. for "foo (1+bar(x), pa,a=1)", the candidate is "foo" tokens = regexp.findall(self.text_until_cursor) - tokens.reverse() - iterTokens = iter(tokens); openPar = 0 + iterTokens = reversed(tokens); openPar = 0 for token in iterTokens: if token == ')': @@ -912,6 +911,25 @@ def python_func_kw_matches(self,text): break except StopIteration: break + + # Find all named arguments already assigned to, as to avoid suggesting + # them again + usedNamedArgs = set() + par_level = -1 + for token, next_token in itertools.izip(tokens, tokens[1:]): + if token == '(': + par_level += 1 + elif token == ')': + par_level -= 1 + + if par_level != 0: + continue + + if next_token != '=': + continue + + usedNamedArgs.add(token) + # lookup the candidate callable matches either using global_matches # or attr_matches for dotted names if len(ids) == 1: @@ -926,7 +944,8 @@ def python_func_kw_matches(self,text): except: continue - for namedArg in namedArgs: + # Remove used named arguments from the list, no need to show twice + for namedArg in set(namedArgs) - usedNamedArgs: if namedArg.startswith(text): argMatches.append(u"%s=" %namedArg) return argMatches From 95ae1d86c59e930b90fb434b239d4abc2879cf51 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Thu, 6 Oct 2016 00:22:22 +0200 Subject: [PATCH 0014/4199] Restored old __init__ header and worst message --- IPython/core/magics/execution.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 41f3bf60912..a49e9669a84 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -71,10 +71,11 @@ class TimeitResult(object): compile_time: (float) time of statement compilation (s) """ - - def __init__(self, loops, repeat, all_runs, compile_time, precision): + def __init__(self, loops, repeat, best, worst, all_runs, compile_time, precision): self.loops = loops self.repeat = repeat + self.best = best + self.worst = worst self.all_runs = all_runs self.compile_time = compile_time self._precision = precision @@ -1063,7 +1064,9 @@ def timeit(self, line='', cell=None): break all_runs = timer.repeat(repeat, number) - timeit_result = TimeitResult(number, repeat, all_runs, tc, precision) + best = min(all_runs) / number + worst = max(all_runs) / number + timeit_result = TimeitResult(number, repeat, best, worst, all_runs, tc, precision) if not quiet : # Check best timing is greater than zero to avoid a @@ -1071,9 +1074,14 @@ def timeit(self, line='', cell=None): # In cases where the slowest timing is lesser than a micosecond # we assume that it does not really matter if the fastest # timing is 4 times faster than the slowest timing or not. - print( timeit_result ) - - if tc > tc_min: + if worst > 4 * best and best > 0 and worst > 1e-6: + print("The slowest run took %0.2f times longer than the " + "fastest. This could mean that an intermediate result " + "is being cached." % (worst / best)) + + print( timeit_result ) + + if tc > tc_min: print("Compiler time: %.2f s" % tc) if return_result: return timeit_result From c2e366c77343da01806d43e276eaf0317681940b Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Thu, 6 Oct 2016 00:27:23 +0200 Subject: [PATCH 0015/4199] Added the plural variable with another string formating --- IPython/core/magics/execution.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index a49e9669a84..a5eebb418d1 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -91,16 +91,10 @@ def stdev(self): return (math.fsum([(x - mean) ** 2 for x in self.timings]) / len(self.timings)) ** 0.5 def __str__(self): - if self.loops == 1: # No s at "loops" if only one loop - return (u"%s loop, average of %d: %s +- %s per loop (using standard deviation)" - % (self.loops, self.repeat, - _format_time(self.average, self._precision), - _format_time(self.stdev, self._precision))) - else: - return (u"%s loops, average of %d: %s +- %s per loop (using standard deviation)" - % (self.loops, self.repeat, - _format_time(self.average, self._precision), - _format_time(self.stdev, self._precision))) + return (u"%s loop%s, average of %d: %s +- %s per loop (using standard deviation)" + % (self.loops,"" if self.loops == 1 else "s", self.repeat, + _format_time(self.average, self._precision), + _format_time(self.stdev, self._precision))) def _repr_pretty_(self, p , cycle): unic = self.__str__() From bc6c5bfa7fe92008d6788801d80bf37a4006b22b Mon Sep 17 00:00:00 2001 From: Tamir Bahar Date: Thu, 6 Oct 2016 22:27:43 +0300 Subject: [PATCH 0016/4199] Changed `itertools.izip` to `zip` Python 2 related mistake fixed. --- IPython/core/completer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index d9419048464..056653762a4 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -916,7 +916,7 @@ def python_func_kw_matches(self,text): # them again usedNamedArgs = set() par_level = -1 - for token, next_token in itertools.izip(tokens, tokens[1:]): + for token, next_token in zip(tokens, tokens[1:]): if token == '(': par_level += 1 elif token == ')': From 181f693e103e44b0c1f95b6092490de9c92d34e5 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 7 Oct 2016 15:43:55 +0100 Subject: [PATCH 0017/4199] Exclude numpy._globals from deepreload Closes gh-9983, though not in a terribly satisfying way. --- IPython/lib/deepreload.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index 9795eac09c0..572ce783cf3 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -327,7 +327,8 @@ def deep_reload_hook(m): original_reload = imp.reload # Python 3 # Replacement for reload() -def reload(module, exclude=('sys', 'os.path', builtin_mod_name, '__main__')): +def reload(module, exclude=('sys', 'os.path', builtin_mod_name, '__main__', + 'numpy._globals')): """Recursively reload all modules used in the given module. Optionally takes a list of modules to exclude from reloading. The default exclude list contains sys, __main__, and __builtin__, to prevent, e.g., resetting From 0a52473ba4a1122ac873f83e3bc37e22bd7a7850 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 9 Oct 2016 17:49:09 +0100 Subject: [PATCH 0018/4199] Update install docs Including mentioning the [test] extra. Closes gh-9989 --- docs/source/install/install.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index c2fe2f94a6b..d3acc9f23b3 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -81,19 +81,19 @@ That's it. Installation from source ~~~~~~~~~~~~~~~~~~~~~~~~ -If you don't want to use :command:`pip`, or don't have it installed, +To install IPython from source, grab the latest stable tarball of IPython `from PyPI `__. Then do the following: .. code-block:: bash - $ tar -xzf ipython.tar.gz - $ cd ipython - $ pip install . + tar -xzf ipython-5.1.0.tar.gz + cd ipython-5.1.0 + # The [test] extra ensures test dependencies are installed too: + pip install .[test] Do not invoke ``setup.py`` directly as this can have undesirable consequences -for further upgrades. Try to also avoid any usage of ``easy_install`` that can -have similar undesirable consequences. +for further upgrades. We do not recommend using ``easy_install`` either. If you are installing to a location (like ``/usr/local``) that requires higher permissions, you may need to run the last command with :command:`sudo`. You can @@ -123,7 +123,7 @@ Then do: $ git clone https://github.com/ipython/ipython.git $ cd ipython - $ pip install -e . + $ pip install -e .[test] The :command:`pip install -e .` command allows users and developers to follow the development branch as it changes by creating links in the right places and From 4036b3d91cc3be0281cbee7612fff6732437b326 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 9 Oct 2016 18:02:18 +0100 Subject: [PATCH 0019/4199] Remove unused IPython.utils.rlineimpl readline module Also deprecate the use_readline parameter for IPCompleter --- IPython/core/completer.py | 16 +++---- IPython/core/interactiveshell.py | 1 - IPython/terminal/debugger.py | 1 - IPython/utils/rlineimpl.py | 74 ----------------------------- IPython/utils/tests/test_imports.py | 3 -- 5 files changed, 6 insertions(+), 89 deletions(-) delete mode 100644 IPython/utils/rlineimpl.py diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 056653762a4..6733259e998 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -25,6 +25,7 @@ import sys import unicodedata import string +import warnings from traitlets.config.configurable import Configurable from IPython.core.error import TryNext @@ -589,7 +590,7 @@ def _greedy_changed(self, change): ).tag(config=True) def __init__(self, shell=None, namespace=None, global_namespace=None, - use_readline=True, config=None, **kwargs): + use_readline=False, config=None, **kwargs): """IPCompleter() -> completer Return a completer object suitable for use by the readline library @@ -608,20 +609,15 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, both Python scopes are visible. use_readline : bool, optional - If true, use the readline library. This completer can still function - without readline, though in that case callers must provide some extra - information on each call about the current line.""" + DEPRECATED, ignored. + """ self.magic_escape = ESC_MAGIC self.splitter = CompletionSplitter() - # Readline configuration, only used by the rlcompleter method. if use_readline: - # We store the right version of readline so that later code - import IPython.utils.rlineimpl as readline - self.readline = readline - else: - self.readline = None + warnings.warn('The use_readline parameter is deprecated since IPython 6.0.', + DeprecationWarning, stacklevel=2) # _greedy_changed() depends on splitter and readline being defined: Completer.__init__(self, namespace=namespace, global_namespace=global_namespace, diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 0c6d8b4aa76..9aba5afd3c8 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1905,7 +1905,6 @@ def init_completer(self): self.Completer = IPCompleter(shell=self, namespace=self.user_ns, global_namespace=self.user_global_ns, - use_readline=False, parent=self, ) self.configurables.append(self.Completer) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index e7bd135f008..810299eb2e8 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -24,7 +24,6 @@ def get_prompt_tokens(cli): compl = IPCompleter(shell=self.shell, namespace={}, global_namespace={}, - use_readline=False, parent=self.shell, ) self._ptcomp = IPythonPTCompleter(compl) diff --git a/IPython/utils/rlineimpl.py b/IPython/utils/rlineimpl.py deleted file mode 100644 index e1cf03942cd..00000000000 --- a/IPython/utils/rlineimpl.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- -""" Imports and provides the 'correct' version of readline for the platform. - -Readline is used throughout IPython as:: - - import IPython.utils.rlineimpl as readline - -In addition to normal readline stuff, this module provides have_readline -boolean and _outputfile variable used in IPython.utils. -""" - -import sys -import warnings - -_rlmod_names = ['gnureadline', 'readline'] - -have_readline = False -for _rlmod_name in _rlmod_names: - try: - # import readline as _rl - _rl = __import__(_rlmod_name) - # from readline import * - globals().update({k:v for k,v in _rl.__dict__.items() if not k.startswith('_')}) - except ImportError: - pass - else: - have_readline = True - break - -if have_readline and (sys.platform == 'win32' or sys.platform == 'cli'): - try: - _outputfile=_rl.GetOutputFile() - except AttributeError: - warnings.warn("Failed GetOutputFile") - have_readline = False - -# Test to see if libedit is being used instead of GNU readline. -# Thanks to Boyd Waters for the original patch. -uses_libedit = False - -if have_readline: - # Official Python docs state that 'libedit' is in the docstring for libedit readline: - uses_libedit = _rl.__doc__ and 'libedit' in _rl.__doc__ - # Note that many non-System Pythons also do not use proper readline, - # but do not report libedit at all, nor are they linked dynamically against libedit. - # known culprits of this include: EPD, Fink - # There is not much we can do to detect this, until we find a specific failure - # case, rather than relying on the readline module to self-identify as broken. - -if uses_libedit and sys.platform == 'darwin': - _rl.parse_and_bind("bind ^I rl_complete") - warnings.warn('\n'.join(['', "*"*78, - "libedit detected - readline will not be well behaved, including but not limited to:", - " * crashes on tab completion", - " * incorrect history navigation", - " * corrupting long-lines", - " * failure to wrap or indent lines properly", - "It is highly recommended that you install gnureadline, which is installable with:", - " pip install gnureadline", - "*"*78]), - RuntimeWarning) - -# the clear_history() function was only introduced in Python 2.4 and is -# actually optional in the readline API, so we must explicitly check for its -# existence. Some known platforms actually don't have it. This thread: -# http://mail.python.org/pipermail/python-dev/2003-August/037845.html -# has the original discussion. - -if have_readline: - try: - _rl.clear_history - except AttributeError: - def clear_history(): pass - _rl.clear_history = clear_history diff --git a/IPython/utils/tests/test_imports.py b/IPython/utils/tests/test_imports.py index 98ee66acd95..170079d2490 100644 --- a/IPython/utils/tests/test_imports.py +++ b/IPython/utils/tests/test_imports.py @@ -12,9 +12,6 @@ def test_import_ipstruct(): def test_import_PyColorize(): from IPython.utils import PyColorize -def test_import_rlineimpl(): - from IPython.utils import rlineimpl - def test_import_strdispatch(): from IPython.utils import strdispatch From a0aad12e53e84208c5793cc5369548d7a4020182 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 9 Oct 2016 18:11:12 +0100 Subject: [PATCH 0020/4199] Clean up dangling reference to IPCompleter.readline --- IPython/core/completer.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 6733259e998..932370684bb 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -552,9 +552,6 @@ def _greedy_changed(self, change): self.splitter.delims = GREEDY_DELIMS else: self.splitter.delims = DELIMS - - if self.readline: - self.readline.set_completer_delims(self.splitter.delims) merge_completions = Bool(True, help="""Whether to merge completion results into a single list From 711ae16a70bbe2d0c94b01df62dec0e5c11d7ee6 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 9 Oct 2016 19:01:20 +0100 Subject: [PATCH 0021/4199] Tweak wording of warning message --- IPython/core/completer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 932370684bb..1d3344899a5 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -613,7 +613,7 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, self.splitter = CompletionSplitter() if use_readline: - warnings.warn('The use_readline parameter is deprecated since IPython 6.0.', + warnings.warn('The use_readline parameter is deprecated and ignored since IPython 6.0.', DeprecationWarning, stacklevel=2) # _greedy_changed() depends on splitter and readline being defined: From 508d364b316015b819ee716f01a8acf8d46a9a8f Mon Sep 17 00:00:00 2001 From: Moez Bouhlel Date: Mon, 10 Oct 2016 12:47:27 +0100 Subject: [PATCH 0022/4199] fix borken demo.py --- IPython/lib/demo.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index 4db31aab358..fa285b995ad 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -183,7 +183,6 @@ import shlex import sys -from IPython.utils import io from IPython.utils.text import marquee from IPython.utils import openpy from IPython.utils import py3compat @@ -538,7 +537,7 @@ def reload(self): self.src_blocks = src_b # also build syntax-highlighted source - self.src_blocks_colored = map(self.ip_colorize,self.src_blocks) + self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks)) # ensure clean namespace and seek offset self.reset() @@ -572,8 +571,8 @@ def pre_cmd(self): """Method called before executing each block. This one simply clears the screen.""" - from IPython.utils.terminal import term_clear - term_clear() + from IPython.utils.terminal import _term_clear + _term_clear() class ClearDemo(ClearMixin,Demo): pass From 7bc96b9f63a94cb18336199fb9c6d0b74a606029 Mon Sep 17 00:00:00 2001 From: Moez Bouhlel Date: Mon, 10 Oct 2016 12:50:18 +0100 Subject: [PATCH 0023/4199] support running outside jupyter/ipython use pygments for highlighting --- IPython/lib/demo.py | 79 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 16 deletions(-) diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index fa285b995ad..2a6dcaf3018 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -41,6 +41,9 @@ The classes here all include a few methods meant to make customization by subclassing more convenient. Their docstrings below have some more details: + - highlight(): format every block and optionally highlight comments and + docstring content. + - marquee(): generates a marquee to provide visible on-screen markers at each block start and end. @@ -182,6 +185,7 @@ import re import shlex import sys +import pygments from IPython.utils.text import marquee from IPython.utils import openpy @@ -200,7 +204,8 @@ class Demo(object): re_auto = re_mark('auto') re_auto_all = re_mark('auto_all') - def __init__(self,src,title='',arg_str='',auto_all=None): + def __init__(self,src,title='',arg_str='',auto_all=None, format_rst=False, + formatter='terminal', style='default'): """Make a new demo object. To run the demo, simply call the object. See the module docstring for full details and an example (you can use @@ -226,6 +231,15 @@ def __init__(self,src,title='',arg_str='',auto_all=None): applies to the whole demo. It is an attribute of the object, and can be changed at runtime simply by reassigning it to a boolean value. + + - format_rst(False): a bool to enable comments and doc strings + formating with pygments rst lexer + + - formatter('terminal'): a string of pygments formatter name to be + used. Useful values for terminals: terminal, terminal256, + terminal16m + + - style('default'): a string of pygments style name to be used. """ if hasattr(src, "read"): # It seems to be a file or a file-like object @@ -246,16 +260,25 @@ def __init__(self,src,title='',arg_str='',auto_all=None): self.auto_all = auto_all self.src = src - # get a few things from ipython. While it's a bit ugly design-wise, - # it ensures that things like color scheme and the like are always in - # sync with the ipython mode being used. This class is only meant to - # be used inside ipython anyways, so it's OK. - ip = get_ipython() # this is in builtins whenever IPython is running - self.ip_ns = ip.user_ns - self.ip_colorize = ip.pycolorize - self.ip_showtb = ip.showtraceback - self.ip_run_cell = ip.run_cell - self.shell = ip + self.inside_ipython = "get_ipython" in globals() + if self.inside_ipython: + # get a few things from ipython. While it's a bit ugly design-wise, + # it ensures that things like color scheme and the like are always in + # sync with the ipython mode being used. This class is only meant to + # be used inside ipython anyways, so it's OK. + ip = get_ipython() # this is in builtins whenever IPython is running + self.ip_ns = ip.user_ns + self.ip_colorize = ip.pycolorize + self.ip_showtb = ip.showtraceback + self.ip_run_cell = ip.run_cell + self.shell = ip + + self.formatter = pygments.formatters.get_formatter_by_name(formatter, + style=style) + self.python_lexer = pygments.lexers.get_lexer_by_name("py3") + self.format_rst = format_rst + if format_rst: + self.rst_lexer = pygments.lexers.get_lexer_by_name("rst") # load user data and initialize data structures self.reload() @@ -303,7 +326,7 @@ def reload(self): self.src_blocks = src_blocks # also build syntax-highlighted source - self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks)) + self.src_blocks_colored = list(map(self.highlight,self.src_blocks)) # ensure clean namespace and seek offset self.reset() @@ -383,7 +406,7 @@ def edit(self,index=None): new_block = f.read() # update the source and colored block self.src_blocks[index] = new_block - self.src_blocks_colored[index] = self.ip_colorize(new_block) + self.src_blocks_colored[index] = self.highlight(new_block) self.block_index = index # call to run with the newly edited index self() @@ -462,9 +485,11 @@ def __call__(self,index=None): sys.argv = save_argv except: - self.ip_showtb(filename=self.fname) + if self.inside_ipython: + self.ip_showtb(filename=self.fname) else: - self.ip_ns.update(self.user_ns) + if self.inside_ipython: + self.ip_ns.update(self.user_ns) if self.block_index == self.nblocks: mq1 = self.marquee('END OF DEMO') @@ -489,6 +514,28 @@ def post_cmd(self): """Method called after executing each block.""" pass + def highlight(self, block): + """Method called on each block to highlight it content""" + tokens = pygments.lex(block, self.python_lexer) + if self.format_rst: + from pygments.token import Token + toks = [] + for token in tokens: + if token[0] == Token.String.Doc and len(token[1]) > 6: + toks += pygments.lex(token[1][:3], self.python_lexer) + # parse doc string content by rst lexer + toks += pygments.lex(token[1][3:-3], self.rst_lexer) + toks += pygments.lex(token[1][-3:], self.python_lexer) + elif token[0] == Token.Comment.Single: + toks.append((Token.Comment.Single, token[1][0])) + # parse comment content by rst lexer + # remove the extrat newline added by rst lexer + toks += list(pygments.lex(token[1][1:], self.rst_lexer))[:-1] + else: + toks.append(token) + tokens = toks + return pygments.format(tokens, self.formatter) + class IPythonDemo(Demo): """Class for interactive demos with IPython's input processing applied. @@ -537,7 +584,7 @@ def reload(self): self.src_blocks = src_b # also build syntax-highlighted source - self.src_blocks_colored = list(map(self.ip_colorize,self.src_blocks)) + self.src_blocks_colored = list(map(self.highlight,self.src_blocks)) # ensure clean namespace and seek offset self.reset() From cb8151e113a8f4781893058982726b397b23092b Mon Sep 17 00:00:00 2001 From: Moez Bouhlel Date: Mon, 10 Oct 2016 12:57:17 +0100 Subject: [PATCH 0024/4199] add __main__ entry to demo.py module --- IPython/lib/demo.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index 2a6dcaf3018..51c44b5eacc 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -627,3 +627,43 @@ class ClearDemo(ClearMixin,Demo): class ClearIPDemo(ClearMixin,IPythonDemo): pass + + +def slide(file_path, noclear=False, format_rst=True, formatter="terminal", + style="native", auto_all=False, delimiter='...'): + if noclear: + demo_class = Demo + else: + demo_class = ClearDemo + demo = demo_class(file_path, format_rst=format_rst, formatter=formatter, + style=style, auto_all=auto_all) + while not demo.finished: + demo() + try: + py3compat.input('\n' + delimiter) + except KeyboardInterrupt: + exit(1) + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser(description='Run python demos') + parser.add_argument('--noclear', '-C', action='store_true', + help='Do not clear terminal on each slide') + parser.add_argument('--rst', '-r', action='store_true', + help='Highlight comments and dostrings as rst') + parser.add_argument('--formatter', '-f', default='terminal', + help='pygments formatter name could be: terminal, ' + 'terminal256, terminal16m') + parser.add_argument('--style', '-s', default='default', + help='pygments style name') + parser.add_argument('--auto', '-a', action='store_true', + help='Run all blocks automatically without' + 'confirmation') + parser.add_argument('--delimiter', '-d', default='...', + help='slides delimiter added after each slide run') + parser.add_argument('file', nargs=1, + help='python demo file') + args = parser.parse_args() + slide(args.file[0], noclear=args.noclear, format_rst=args.rst, + formatter=args.formatter, style=args.style, auto_all=args.auto, + delimiter=args.delimiter) From 3e97b06ac96c78cdaf6f6b775232ee7bd3610ccf Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 6 Oct 2016 16:04:39 -0700 Subject: [PATCH 0025/4199] Pass parent to child for configuration to propagate --- IPython/core/interactiveshell.py | 6 +++--- IPython/core/ultratb.py | 26 ++++++++++++++------------ IPython/utils/PyColorize.py | 7 +------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 0c6d8b4aa76..3f3182331ec 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -578,7 +578,7 @@ def init_encoding(self): @observe('colors') def init_syntax_highlighting(self, changes=None): # Python source parser/formatter for syntax highlighting - pyformat = PyColorize.Parser(style=self.colors).format + pyformat = PyColorize.Parser(style=self.colors, parent=self).format self.pycolorize = lambda src: pyformat(src,'str') def refresh_style(self): @@ -1569,7 +1569,7 @@ def init_history(self): def init_traceback_handlers(self, custom_exceptions): # Syntax error handler. - self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor') + self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor', parent=self) # The interactive one is initialized with an offset, meaning we always # want to remove the topmost item in the traceback, which is our own @@ -1578,7 +1578,7 @@ def init_traceback_handlers(self, custom_exceptions): color_scheme='NoColor', tb_offset = 1, check_cache=check_linecache_ipython, - debugger_cls=self.debugger_cls) + debugger_cls=self.debugger_cls, parent=self) # The instance will store a pointer to the system-wide exception hook, # so that runtime code (such as magics) can access it. This is because diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 52560b7366b..e03fda4f6b6 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -387,13 +387,11 @@ def _fixed_getinnerframes(etb, context=1, tb_offset=0): # (SyntaxErrors have to be treated specially because they have no traceback) -def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None): +def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, _line_format=(lambda x,_:x,None)): numbers_width = INDENT_SIZE - 1 res = [] i = lnum - index - _line_format = PyColorize.Parser(style=scheme).format2 - for line in lines: line = py3compat.cast_unicode(line) @@ -586,9 +584,9 @@ class ListTB(TBTools): Because they are meant to be called without a full traceback (only a list), instances of this class can't call the interactive pdb debugger.""" - def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None): + def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None): TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb, - ostream=ostream, parent=parent) + ostream=ostream, parent=parent,config=config) def __call__(self, etype, value, elist): self.ostream.flush() @@ -801,7 +799,8 @@ class VerboseTB(TBTools): def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None, tb_offset=0, long_header=False, include_vars=True, - check_cache=None, debugger_cls = None): + check_cache=None, debugger_cls = None, + parent=None, config=None): """Specify traceback offset, headers and color scheme. Define how many frames to drop from the tracebacks. Calling it with @@ -809,7 +808,7 @@ def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None, their own code at the top of the traceback (VerboseTB will first remove that frame before printing the traceback info).""" TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb, - ostream=ostream) + ostream=ostream, parent=parent, config=config) self.tb_offset = tb_offset self.long_header = long_header self.include_vars = include_vars @@ -1010,9 +1009,10 @@ def linereader(file=file, lnum=[lnum], getline=ulinecache.getline): if index is None: return level else: + _line_format = PyColorize.Parser(style=col_scheme, parent=self).format2 return '%s%s' % (level, ''.join( _format_traceback_lines(lnum, index, lines, Colors, lvals, - col_scheme))) + _line_format))) def prepare_chained_exception_message(self, cause): direct_cause = "\nThe above exception was the direct cause of the following exception:\n" @@ -1277,7 +1277,8 @@ class FormattedTB(VerboseTB, ListTB): def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False, ostream=None, tb_offset=0, long_header=False, include_vars=False, - check_cache=None, debugger_cls=None): + check_cache=None, debugger_cls=None, + parent=None, config=None): # NEVER change the order of this list. Put new modes at the end: self.valid_modes = ['Plain', 'Context', 'Verbose'] @@ -1286,7 +1287,8 @@ def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False, VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb, ostream=ostream, tb_offset=tb_offset, long_header=long_header, include_vars=include_vars, - check_cache=check_cache, debugger_cls=debugger_cls) + check_cache=check_cache, debugger_cls=debugger_cls, + parent=parent, config=config) # Different types of tracebacks are joined with different separators to # form a single string. They are taken from this dict @@ -1415,8 +1417,8 @@ def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs): class SyntaxTB(ListTB): """Extension which holds some state: the last exception value""" - def __init__(self, color_scheme='NoColor'): - ListTB.__init__(self, color_scheme) + def __init__(self, color_scheme='NoColor', parent=None, config=None): + ListTB.__init__(self, color_scheme, parent=parent, config=config) self.last_syntax_error = None def __call__(self, etype, value, elist): diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index c845dd7442e..15e77e336bb 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -44,12 +44,7 @@ import token import tokenize -try: - generate_tokens = tokenize.generate_tokens -except AttributeError: - # Python 3. Note that we use the undocumented _tokenize because it expects - # strings, not bytes. See also Python issue #9969. - generate_tokens = tokenize._tokenize +generate_tokens = tokenize.generate_tokens from IPython.utils.coloransi import TermColors, InputTermColors ,ColorScheme, ColorSchemeTable from IPython.utils.py3compat import PY3 From 2184193645869a926e80a77af04f8fb64a0d0c54 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 11 Oct 2016 21:13:44 -0400 Subject: [PATCH 0026/4199] MNT: remove unneeded pylab imports These are better done through the pyplot module rather than pyplab. --- IPython/core/pylabtools.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index e7327e58e8c..3a8bf2e8ed3 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -159,7 +159,7 @@ def mpl_execfile(fname,*where,**kw): properly handle interactive rendering.""" import matplotlib - import matplotlib.pylab as pylab + import matplotlib.pyplot as plt #print '*** Matplotlib runner ***' # dbg # turn off rendering until end of script @@ -168,9 +168,10 @@ def mpl_execfile(fname,*where,**kw): safe_execfile(fname,*where,**kw) matplotlib.interactive(is_interactive) # make rendering call now, if the user tried to do it - if pylab.draw_if_interactive.called: - pylab.draw() - pylab.draw_if_interactive.called = False + if plt.draw_if_interactive.called: + plt.draw() + plt.draw_if_interactive.called = False + return mpl_execfile @@ -297,12 +298,12 @@ def activate_matplotlib(backend): # This must be imported last in the matplotlib series, after # backend/interactivity choices have been made - import matplotlib.pylab as pylab + import matplotlib.pyplot as plt - pylab.show._needmain = False + plt.show._needmain = False # We need to detect at runtime whether show() is called by the user. # For this, we wrap it into a decorator which adds a 'called' flag. - pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive) + plt.draw_if_interactive = flag_calls(plt.draw_if_interactive) def import_pylab(user_ns, import_all=True): From 7bca3522e82ed5558e42826746ab6ffe666c8c8e Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 11 Oct 2016 21:15:01 -0400 Subject: [PATCH 0027/4199] MNT: add hook for mpl > 1.5 This will properly handle > 1 figure being updated in `%run` --- IPython/core/pylabtools.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 3a8bf2e8ed3..35ff07b9ca8 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -172,6 +172,13 @@ def mpl_execfile(fname,*where,**kw): plt.draw() plt.draw_if_interactive.called = False + # re-draw everything that is stale + try: + da = plt.draw_all + except AttributeError: + pass + else: + da() return mpl_execfile From fa81a65ccedfc872bc6bc98f47e0684882a95d84 Mon Sep 17 00:00:00 2001 From: Adam Eury Date: Tue, 11 Oct 2016 21:41:06 -0400 Subject: [PATCH 0028/4199] feat(JSON): Add expanded metadata to JSON display class --- IPython/core/display.py | 67 +++++++++++++++++++++--------- IPython/core/tests/test_display.py | 33 +++++++++------ 2 files changed, 67 insertions(+), 33 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 4a943e4dbb4..4fe28d9085c 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -190,7 +190,7 @@ def display_pretty(*objs, **kwargs): def display_html(*objs, **kwargs): """Display the HTML representation of an object. - + Note: If raw=False and the object does not have a HTML representation, no HTML will be shown. @@ -513,13 +513,35 @@ def _repr_svg_(self): class JSON(DisplayObject): """JSON expects a JSON-able dict or list - + not an already-serialized JSON string. - + Scalar types (None, number, string) are not allowed, only dict or list containers. """ # wrap data in a property, which warns about passing already-serialized JSON _data = None + def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None): + """Create a JSON display object given raw data. + + Parameters + ---------- + data : dict or list + JSON data to display. Not an already-serialized JSON string. + Scalar types (None, number, string) are not allowed, only dict + or list containers. + url : unicode + A URL to download the data from. + filename : unicode + Path to a local file to load the data from. + expanded : boolean + Metadata to control whether a JSON display component is expanded. + metadata: dict + Specify extra metadata to attach to the json display object. + """ + self.expanded = expanded + self.metadata = metadata + super(JSON, self).__init__(data=data, url=url, filename=filename) + def _check_data(self): if self.data is not None and not isinstance(self.data, (dict, list)): raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data)) @@ -527,7 +549,7 @@ def _check_data(self): @property def data(self): return self._data - + @data.setter def data(self, data): if isinstance(data, string_types): @@ -535,8 +557,14 @@ def data(self, data): data = json.loads(data) self._data = data + def _data_and_metadata(self): + md = {'expanded': self.expanded} + if self.metadata: + md.update(self.metadata) + return self.data, md + def _repr_json_(self): - return self.data + return self._data_and_metadata() css_t = """$("head").append($("").attr({ rel: "stylesheet", @@ -562,7 +590,7 @@ def __init__(self, data=None, url=None, filename=None, lib=None, css=None): In the Notebook, the containing element will be available as `element`, and jQuery will be available. Content appended to `element` will be - visible in the output area. + visible in the output area. Parameters ---------- @@ -622,7 +650,7 @@ def _pngxy(data): def _jpegxy(data): """read the (width, height) from a JPEG header""" # adapted from http://www.64lines.com/jpeg-width-height - + idx = 4 while True: block_size = struct.unpack('>H', data[idx:idx+2])[0] @@ -755,10 +783,10 @@ def __init__(self, data=None, url=None, filename=None, format=None, self.unconfined = unconfined self.metadata = metadata super(Image, self).__init__(data=data, url=url, filename=filename) - + if retina: self._retina_shape() - + def _retina_shape(self): """load pixel-doubled width and height from image data""" if not self.embed: @@ -872,7 +900,7 @@ def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=Non elif os.path.exists(data): filename = data data = None - + if data and not embed: msg = ''.join([ "To embed videos, you must pass embed=True ", @@ -894,13 +922,13 @@ def _repr_html_(self): Your browser does not support the video element. """.format(url) return output - + # Embedded videos are base64-encoded. mimetype = self.mimetype if self.filename is not None: if not mimetype: mimetype, _ = mimetypes.guess_type(self.filename) - + with open(self.filename, 'rb') as f: video = f.read() else: @@ -910,7 +938,7 @@ def _repr_html_(self): b64_video = video else: b64_video = base64_encode(video).decode('ascii').rstrip() - + output = """