From 8e65bf09c3be5e6b7d43e4145f129c7f66f6af2f Mon Sep 17 00:00:00 2001 From: memeplex Date: Sun, 7 Aug 2016 14:26:46 -0300 Subject: [PATCH 0001/1594] Allow to pass a pygments class to highlighting_style. Fixes https://github.com/ipython/ipython/issues/9749. --- IPython/terminal/interactiveshell.py | 23 ++++++++++++++--------- docs/source/config/details.rst | 7 ++++--- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 077d92c9c42..af3eb53d944 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -8,10 +8,10 @@ from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC from IPython.utils import io -from IPython.utils.py3compat import PY3, cast_unicode_py2, input +from IPython.utils.py3compat import PY3, cast_unicode_py2, input, string_types from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum +from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode from prompt_toolkit.filters import (HasFocus, Condition, IsDone) @@ -23,6 +23,7 @@ from prompt_toolkit.styles import PygmentsStyle, DynamicStyle from pygments.styles import get_style_by_name, get_all_styles +from pygments.style import Style from pygments.token import Token from .debugger import TerminalPdb, Pdb @@ -132,8 +133,9 @@ def debugger_cls(self): help="Enable mouse support in the prompt" ).tag(config=True) - highlighting_style = Unicode('legacy', - help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) + highlighting_style = Union([Unicode('legacy'), Type(klass=Style)], + help="""The name or class of a Pygments style to use for syntax + highlighting: \n %s""" % ', '.join(get_all_styles()) ).tag(config=True) @@ -143,7 +145,7 @@ def _highlighting_style_changed(self, change): self.refresh_style() def refresh_style(self): - self._style = self._make_style_from_name(self.highlighting_style) + self._style = self._make_style_from_name_or_cls(self.highlighting_style) highlighting_style_overrides = Dict( @@ -229,7 +231,7 @@ def prompt(): if cell and (cell != last_cell): history.append(cell) - self._style = self._make_style_from_name(self.highlighting_style) + self._style = self._make_style_from_name_or_cls(self.highlighting_style) style = DynamicStyle(lambda: self._style) editing_mode = getattr(EditingMode, self.editing_mode.upper()) @@ -249,14 +251,14 @@ def prompt(): self._pt_app, eventloop=self._eventloop, output=create_output(true_color=self.true_color)) - def _make_style_from_name(self, name): + def _make_style_from_name_or_cls(self, name_or_cls): """ Small wrapper that make an IPython compatible style from a style name We need that to add style for prompt ... etc. """ style_overrides = {} - if name == 'legacy': + if name_or_cls == 'legacy': legacy = self.colors.lower() if legacy == 'linux': style_cls = get_style_by_name('monokai') @@ -287,7 +289,10 @@ def _make_style_from_name(self, name): else : raise ValueError('Got unknown colors: ', legacy) else : - style_cls = get_style_by_name(name) + if isinstance(name_or_cls, string_types): + style_cls = get_style_by_name(name_or_cls) + else: + style_cls = name_or_cls style_overrides = { Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 6bed3c68c91..d00eac5758b 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -93,9 +93,10 @@ is set to ``'legacy'``. It has four case-insensitive values: should be legible on either dark or light terminal backgrounds. *linux* is optimised for dark backgrounds and *lightbg* for light ones. -``TerminalInteractiveShell.highlighting_style`` determines prompt colours and syntax -highlighting. It takes the name of a Pygments style as a string, or the special -value ``'legacy'`` to pick a style in accordance with ``InteractiveShell.colors``. +``TerminalInteractiveShell.highlighting_style`` determines prompt colours and +syntax highlighting. It takes the name (as a string) or class (as a subclass of +``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'`` +to pick a style in accordance with ``InteractiveShell.colors``. You can see the Pygments styles available on your system by running:: From c5bee47512792b84b2a9e973a63a248ce44f9d69 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 9 Aug 2016 14:11:24 +0100 Subject: [PATCH 0002/1594] Also capture execution results using sys.displayhook From discussion on mailing list. It's not clear if this is what we want to do, or if it should be controlled by a separate option, but it's submitted for consideration. --- IPython/core/displayhook.py | 14 ++++++++++++++ IPython/utils/capture.py | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 07d733e22d2..d6d108d6a3e 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -293,3 +293,17 @@ def flush(self): # IronPython blocks here forever if sys.platform != "cli": gc.collect() + + +class CapturingDisplayHook(object): + def __init__(self, shell, outputs=None): + self.shell = shell + if outputs is None: + outputs = [] + self.outputs = outputs + + def __call__(self, result=None): + if result is None: + return + format_dict, md_dict = self.shell.display_formatter.format(result) + self.outputs.append((format_dict, md_dict)) diff --git a/IPython/utils/capture.py b/IPython/utils/capture.py index 1731bf21a92..d129c0376d8 100644 --- a/IPython/utils/capture.py +++ b/IPython/utils/capture.py @@ -137,6 +137,7 @@ def __init__(self, stdout=True, stderr=True, display=True): def __enter__(self): from IPython.core.getipython import get_ipython from IPython.core.displaypub import CapturingDisplayPublisher + from IPython.core.displayhook import CapturingDisplayHook self.sys_stdout = sys.stdout self.sys_stderr = sys.stderr @@ -156,7 +157,9 @@ def __enter__(self): self.save_display_pub = self.shell.display_pub self.shell.display_pub = CapturingDisplayPublisher() outputs = self.shell.display_pub.outputs - + self.save_display_hook = sys.displayhook + sys.displayhook = CapturingDisplayHook(shell=self.shell, + outputs=outputs) return CapturedIO(stdout, stderr, outputs) @@ -165,5 +168,6 @@ def __exit__(self, exc_type, exc_value, traceback): sys.stderr = self.sys_stderr if self.display and self.shell: self.shell.display_pub = self.save_display_pub + sys.displayhook = self.save_display_hook From 4ad1eea41d602ec8546eca6f9beeec21f9f884da Mon Sep 17 00:00:00 2001 From: anantkaushik89 Date: Fri, 12 Aug 2016 11:42:41 +0530 Subject: [PATCH 0003/1594] cleanup unused code from utils/process.py --- IPython/utils/process.py | 38 +++----------------------------------- 1 file changed, 3 insertions(+), 35 deletions(-) diff --git a/IPython/utils/process.py b/IPython/utils/process.py index a274f43f3a4..905d56aab60 100644 --- a/IPython/utils/process.py +++ b/IPython/utils/process.py @@ -41,6 +41,9 @@ def find_cmd(cmd): from IPython.utils.process import pycmd2argv argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp')) + Note, The code for pycmd2argv has been removed now as it was not used + anywhere. get_ipython_module_path should give us that same result. + Parameters ---------- cmd : str @@ -52,41 +55,6 @@ def find_cmd(cmd): return path -def is_cmd_found(cmd): - """Check whether executable `cmd` exists or not and return a bool.""" - try: - find_cmd(cmd) - return True - except FindCmdError: - return False - - -def pycmd2argv(cmd): - r"""Take the path of a python command and return a list (argv-style). - - This only works on Python based command line programs and will find the - location of the ``python`` executable using ``sys.executable`` to make - sure the right version is used. - - For a given path ``cmd``, this returns [cmd] if cmd's extension is .exe, - .com or .bat, and [, cmd] otherwise. - - Parameters - ---------- - cmd : string - The path of the command. - - Returns - ------- - argv-style list. - """ - ext = os.path.splitext(cmd)[1] - if ext in ['.exe', '.com', '.bat']: - return [cmd] - else: - return [sys.executable, cmd] - - def abbrev_cwd(): """ Return abbreviated version of cwd, e.g. d:mydir """ cwd = py3compat.getcwd().replace('\\','/') From c6bcb2b93f1bea2349088b31b570fdfb78bf219f Mon Sep 17 00:00:00 2001 From: Hassan Kibirige Date: Fri, 12 Aug 2016 18:58:53 -0500 Subject: [PATCH 0004/1594] Remove access to 'savefig.dpi', use figure.dpi `ipykernel` now uses `figure.dpi` to control the dpi of the image to be created. This means that `dpi` property of the figure object is a reliable source of truth for the users preferences. --- IPython/core/pylabtools.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 815b8d7c7aa..0a07def30b6 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -97,9 +97,7 @@ def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs): if not fig.axes and not fig.lines: return - dpi = rcParams['savefig.dpi'] - if dpi == 'figure': - dpi = fig.dpi + dpi = fig.dpi if fmt == 'retina': dpi = dpi * 2 fmt = 'png' From de84d5a44feb7cddfada8b1c5b5003d6453695f6 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 13 Aug 2016 13:55:40 +0100 Subject: [PATCH 0005/1594] Back to development --- IPython/core/release.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index a9beed34e09..3064cce5aa5 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -20,11 +20,11 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 5 -_version_minor = 1 +_version_minor = 2 _version_patch = 0 _version_extra = '.dev' # _version_extra = 'rc1' -_version_extra = '' # Uncomment this for full releases +# _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 codename = '' From 3074aa87ac68e5a7e367e6823e20d1f4c5727c9a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 14 Aug 2016 11:56:26 +0100 Subject: [PATCH 0006/1594] Switch master to development of 6.0 I'm thinking about this because we've just released 5.1, but I'm happy for it to wait a bit longer if we prefer. As planned, 6.0 will require Python 3, while we will continue to support 5.x for some time for Python 2 users. Before merging this, we should send a message to the mailing list for any Python 2 users following master, and make a 5.x branch off master. --- .travis.yml | 19 ------------------- IPython/core/release.py | 6 ++---- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 47d42d6fd75..ebd880a3d0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,30 +5,12 @@ python: - 3.5 - 3.4 - 3.3 - - 2.7 - - pypy sudo: false before_install: - git clone --quiet --depth 1 https://github.com/minrk/travis-wheels travis-wheels - 'if [[ $GROUP != js* ]]; then COVERAGE=""; fi' install: - pip install "setuptools>=18.5" - # Installs PyPy (+ its Numpy). Based on @frol comment at: - # https://github.com/travis-ci/travis-ci/issues/5027 - - | - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then - export PYENV_ROOT="$HOME/.pyenv" - if [ -f "$PYENV_ROOT/bin/pyenv" ]; then - cd "$PYENV_ROOT" && git pull - else - rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" - fi - export PYPY_VERSION="5.3.1" - "$PYENV_ROOT/bin/pyenv" install "pypy-$PYPY_VERSION" - virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" - source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" - pip install https://bitbucket.org/pypy/numpy/get/master.zip - fi - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] - pip install codecov script: @@ -41,4 +23,3 @@ after_success: matrix: allow_failures: - python: nightly - - python: pypy diff --git a/IPython/core/release.py b/IPython/core/release.py index 3064cce5aa5..577e71b1699 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -19,8 +19,8 @@ # IPython version information. An empty _version_extra corresponds to a full # release. 'dev' as a _version_extra string means this is a development # version -_version_major = 5 -_version_minor = 2 +_version_major = 6 +_version_minor = 0 _version_patch = 0 _version_extra = '.dev' # _version_extra = 'rc1' @@ -116,8 +116,6 @@ 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Topic :: System :: Shells' ] From 6fabe0bae574495cf18c4a716858b5d665cda2b0 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 14 Aug 2016 18:44:37 +0100 Subject: [PATCH 0007/1594] Deprecate -e flag for %notebook magic Maybe the magic did something else in the past? Now the flag is just confusing. I've left it in place so it will still work, but have no effect. --- IPython/core/magics/basic.py | 40 ++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 4767724eee6..3235599e5ca 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -3,6 +3,7 @@ from __future__ import print_function from __future__ import absolute_import +import argparse import io import sys from pprint import pformat @@ -548,11 +549,7 @@ def precision(self, s=''): @magic_arguments.magic_arguments() @magic_arguments.argument( '-e', '--export', action='store_true', default=False, - help='Export IPython history as a notebook. The filename argument ' - 'is used to specify the notebook name and format. For example ' - 'a filename of notebook.ipynb will result in a notebook name ' - 'of "notebook" and a format of "json". Likewise using a ".py" ' - 'file extension will write the notebook as a Python script' + help=argparse.SUPPRESS ) @magic_arguments.argument( 'filename', type=unicode_type, @@ -563,22 +560,25 @@ def notebook(self, s): """Export and convert IPython notebooks. This function can export the current IPython history to a notebook file. - For example, to export the history to "foo.ipynb" do "%notebook -e foo.ipynb". - To export the history to "foo.py" do "%notebook -e foo.py". + For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb". + To export the history to "foo.py" do "%notebook foo.py". + + The -e or --export flag is deprecated in IPython 5.2, and will be + removed in the future. """ args = magic_arguments.parse_argstring(self.notebook, s) from nbformat import write, v4 - if args.export: - cells = [] - hist = list(self.shell.history_manager.get_range()) - if(len(hist)<=1): - raise ValueError('History is empty, cannot export') - for session, execution_count, source in hist[:-1]: - cells.append(v4.new_code_cell( - execution_count=execution_count, - source=source - )) - nb = v4.new_notebook(cells=cells) - with io.open(args.filename, 'w', encoding='utf-8') as f: - write(nb, f, version=4) + + cells = [] + hist = list(self.shell.history_manager.get_range()) + if(len(hist)<=1): + raise ValueError('History is empty, cannot export') + for session, execution_count, source in hist[:-1]: + cells.append(v4.new_code_cell( + execution_count=execution_count, + source=source + )) + nb = v4.new_notebook(cells=cells) + with io.open(args.filename, 'w', encoding='utf-8') as f: + write(nb, f, version=4) From bb5deb660427810897fcf7b4d8c432c897ce5ffb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 14 Aug 2016 11:37:45 -0700 Subject: [PATCH 0008/1594] Warn about universal wheels in the docs. --- docs/source/coredev/release_process.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index feec4f8125a..9dbca7a9900 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -176,8 +176,10 @@ Run the ``release`` script, this step requires having a current wheel, Python ./tools/release This makes the tarballs, zipfiles, and wheels, and put them under the ``dist/`` -folder. Be sure to test the ``wheel`` and the ``sdist`` locally before uploading -them to PyPI. +folder. Be sure to test the ``wheels`` and the ``sdist`` locally before +uploading them to PyPI. We do not use an universal wheel as each wheel, +depending on the version of Python it is built for install an ``ipython2`` or +``ipython3`` script. Using an universal wheel prevent this. Use the following to actually upload the result of the build:: From 635420751db1f453dc086ea0bde03c21296fdf27 Mon Sep 17 00:00:00 2001 From: Rounak Banik Date: Mon, 15 Aug 2016 16:28:07 +0530 Subject: [PATCH 0009/1594] Update README.rst --- README.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index f50965a4ae0..d7dbd5fa2e4 100644 --- a/README.rst +++ b/README.rst @@ -19,7 +19,7 @@ Overview ======== Welcome to IPython. Our full documentation is available on `ipython.readthedocs.io -`_ and contain information on how to install, use +`_ and contains information on how to install, use and contribute to the project. Officially, IPython requires Python version 2.7, or 3.3 and above. @@ -32,7 +32,7 @@ if you want to use these. -Developement and Instant runnimg +Development and Instant runnimg ================================ You can find the latest version of the development documentation on `readthedocs @@ -43,7 +43,7 @@ by typing at the terminal:: $ python -m IPython -Or see the `developement installation docs +Or see the `development installation docs `_ for the latest revision on read the docs. From 85dcb365dfc514e5d755cb8806310cecb0f9cbf0 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 15 Aug 2016 12:28:07 +0100 Subject: [PATCH 0010/1594] Remove mention of exporting to .py file with %notebook --- IPython/core/magics/basic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 3235599e5ca..781fa72e57d 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -561,7 +561,6 @@ def notebook(self, s): This function can export the current IPython history to a notebook file. For example, to export the history to "foo.ipynb" do "%notebook foo.ipynb". - To export the history to "foo.py" do "%notebook foo.py". The -e or --export flag is deprecated in IPython 5.2, and will be removed in the future. From 4648a8632048d946bafa95e0a1354c2c8bfe89ac Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 15 Aug 2016 12:34:58 +0100 Subject: [PATCH 0011/1594] Reword a bit --- docs/source/coredev/release_process.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 9dbca7a9900..16b8e6a4bf4 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -177,9 +177,9 @@ Run the ``release`` script, this step requires having a current wheel, Python This makes the tarballs, zipfiles, and wheels, and put them under the ``dist/`` folder. Be sure to test the ``wheels`` and the ``sdist`` locally before -uploading them to PyPI. We do not use an universal wheel as each wheel, -depending on the version of Python it is built for install an ``ipython2`` or -``ipython3`` script. Using an universal wheel prevent this. +uploading them to PyPI. We do not use an universal wheel as each wheel +installs an ``ipython2`` or ``ipython3`` script, depending on the version of +Python it is built for. Using an universal wheel would prevent this. Use the following to actually upload the result of the build:: From 01562d6cc5bcee64a34b0a1eb7c58aff4419b041 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 15 Aug 2016 13:07:12 +0100 Subject: [PATCH 0012/1594] More changes to indicate Python 3 requirement --- IPython/__init__.py | 4 ++-- README.rst | 4 ++-- docs/source/install/install.rst | 2 +- setup.py | 5 +++-- tools/toollib.py | 3 +-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/IPython/__init__.py b/IPython/__init__.py index 9b450da6a0c..6bb5ba76096 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -30,8 +30,8 @@ # Don't forget to also update setup.py when this changes! v = sys.version_info -if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)): - raise ImportError('IPython requires Python version 2.7 or 3.3 or above.') +if v[:2] < (3,3): + raise ImportError('IPython requires Python version 3.3 or above.') del v # Make it easy to import extensions - they are always directly on pythonpath. diff --git a/README.rst b/README.rst index f50965a4ae0..d821ae528a7 100644 --- a/README.rst +++ b/README.rst @@ -22,8 +22,8 @@ Welcome to IPython. Our full documentation is available on `ipython.readthedocs `_ and contain information on how to install, use contribute to the project. -Officially, IPython requires Python version 2.7, or 3.3 and above. -IPython 1.x is the last IPython version to support Python 2.6 and 3.2. +Officially, IPython requires Python version 3.3 and above. +IPython 5.x is the last IPython version to support Python 2.7. The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*. See the `Jupyter installation docs `__ diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index eb6db4507ab..c2fe2f94a6b 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -4,7 +4,7 @@ Installing IPython ================== -IPython requires Python 2.7 or ≥ 3.3. +IPython 6 requires Python ≥ 3.3. IPython 5.x can be installed on Python 2. Quick Install diff --git a/setup.py b/setup.py index d23d5eb3f21..f03db180a72 100755 --- a/setup.py +++ b/setup.py @@ -27,8 +27,8 @@ # This check is also made in IPython/__init__, don't forget to update both when # changing Python version requirements. v = sys.version_info -if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)): - error = "ERROR: IPython requires Python version 2.7 or 3.3 or above." +if v[:2] < (3,3): + error = "ERROR: IPython requires Python version 3.3 or above." print(error, file=sys.stderr) sys.exit(1) @@ -239,6 +239,7 @@ def run(self): extras_require['all'] = everything if 'setuptools' in sys.modules: + setuptools_extra_args['python_requires'] = '>=3.3' setuptools_extra_args['zip_safe'] = False setuptools_extra_args['entry_points'] = { 'console_scripts': find_entry_points(), diff --git a/tools/toollib.py b/tools/toollib.py index ad71bd063a3..37439058ff3 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -21,8 +21,7 @@ sdists = './setup.py sdist --formats=gztar,zip' # Binary dists def buildwheels(): - for py in ('2', '3'): - sh('python%s setupegg.py bdist_wheel' % py) + sh('python3 setupegg.py bdist_wheel' % py) # Utility functions def sh(cmd): From 2546c926fad6f5dd1678bdad44a5b59e2ec49d16 Mon Sep 17 00:00:00 2001 From: anantkaushik89 Date: Tue, 16 Aug 2016 13:27:06 +0530 Subject: [PATCH 0013/1594] Incorporating review comments --- IPython/utils/process.py | 8 ++------ docs/source/whatsnew/pr/incompat-funcs-removed.rst | 9 +++++++++ 2 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 docs/source/whatsnew/pr/incompat-funcs-removed.rst diff --git a/IPython/utils/process.py b/IPython/utils/process.py index 905d56aab60..05dd7a69a71 100644 --- a/IPython/utils/process.py +++ b/IPython/utils/process.py @@ -37,12 +37,8 @@ def find_cmd(cmd): is a risk you will find the wrong one. Instead find those using the following code and looking for the application itself:: - from IPython.utils.path import get_ipython_module_path - from IPython.utils.process import pycmd2argv - argv = pycmd2argv(get_ipython_module_path('IPython.terminal.ipapp')) - - Note, The code for pycmd2argv has been removed now as it was not used - anywhere. get_ipython_module_path should give us that same result. + import sys + argv = [sys.executable, '-m', 'IPython.terminal'] Parameters ---------- diff --git a/docs/source/whatsnew/pr/incompat-funcs-removed.rst b/docs/source/whatsnew/pr/incompat-funcs-removed.rst new file mode 100644 index 00000000000..ee0b8dbb9c2 --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-funcs-removed.rst @@ -0,0 +1,9 @@ +Functions Removed in 6.x Development cycle +------------------------------------------ + +The following functions have been removed in the +development cycle marked for the development cycle +marked for Milestone 6.0. + +* is_cmd_found +* pycmd2argv From f3745929d554ec707fad54eed94d823f05529c1d Mon Sep 17 00:00:00 2001 From: kaushikanant Date: Tue, 16 Aug 2016 13:30:44 +0530 Subject: [PATCH 0014/1594] Update incompat-funcs-removed.rst --- docs/source/whatsnew/pr/incompat-funcs-removed.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/whatsnew/pr/incompat-funcs-removed.rst b/docs/source/whatsnew/pr/incompat-funcs-removed.rst index ee0b8dbb9c2..acce8bbdc4b 100644 --- a/docs/source/whatsnew/pr/incompat-funcs-removed.rst +++ b/docs/source/whatsnew/pr/incompat-funcs-removed.rst @@ -2,8 +2,7 @@ Functions Removed in 6.x Development cycle ------------------------------------------ The following functions have been removed in the -development cycle marked for the development cycle -marked for Milestone 6.0. +development cycle marked for Milestone 6.0. * is_cmd_found * pycmd2argv From 30a7e23e19b728249673c1e1e9420464095b97b0 Mon Sep 17 00:00:00 2001 From: kaushikanant Date: Tue, 16 Aug 2016 13:31:46 +0530 Subject: [PATCH 0015/1594] Update incompat-funcs-removed.rst --- docs/source/whatsnew/pr/incompat-funcs-removed.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/whatsnew/pr/incompat-funcs-removed.rst b/docs/source/whatsnew/pr/incompat-funcs-removed.rst index acce8bbdc4b..06476a12970 100644 --- a/docs/source/whatsnew/pr/incompat-funcs-removed.rst +++ b/docs/source/whatsnew/pr/incompat-funcs-removed.rst @@ -4,5 +4,5 @@ Functions Removed in 6.x Development cycle The following functions have been removed in the development cycle marked for Milestone 6.0. -* is_cmd_found -* pycmd2argv +* IPython/utils/process.py - is_cmd_found +* IPython/utils/process.py - pycmd2argv From 6ef2911494eeab5d7b3967cdf23e2822d48f68dd Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Wed, 17 Aug 2016 13:49:25 +0200 Subject: [PATCH 0016/1594] resolve path to temporary directory to ensure that 'assert_equal' tests also work when $TMPDIR is a symlink --- IPython/core/tests/test_paths.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_paths.py b/IPython/core/tests/test_paths.py index d0a87681d3b..20257ba7a72 100644 --- a/IPython/core/tests/test_paths.py +++ b/IPython/core/tests/test_paths.py @@ -17,7 +17,7 @@ from IPython.testing.decorators import skip_win32 from IPython.utils.tempdir import TemporaryDirectory -TMP_TEST_DIR = tempfile.mkdtemp() +TMP_TEST_DIR = os.path.realpath(tempfile.mkdtemp()) HOME_TEST_DIR = os.path.join(TMP_TEST_DIR, "home_test_dir") XDG_TEST_DIR = os.path.join(HOME_TEST_DIR, "xdg_test_dir") XDG_CACHE_DIR = os.path.join(HOME_TEST_DIR, "xdg_cache_dir") From 2ed56dd7602d8b631188bf64442d8a6b45362445 Mon Sep 17 00:00:00 2001 From: "Denis S. Tereshchenko" Date: Thu, 18 Aug 2016 17:18:40 +0300 Subject: [PATCH 0017/1594] auto-injection of deep-reload removed --- IPython/core/builtin_trap.py | 11 ----------- IPython/core/interactiveshell.py | 15 --------------- IPython/lib/deepreload.py | 18 ------------------ .../source/whatsnew/pr/incompat-no-dreload.rst | 3 +++ 4 files changed, 3 insertions(+), 44 deletions(-) create mode 100644 docs/source/whatsnew/pr/incompat-no-dreload.rst diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py index 909a555c733..b3c9fdf9564 100644 --- a/IPython/core/builtin_trap.py +++ b/IPython/core/builtin_trap.py @@ -52,17 +52,6 @@ def __init__(self, shell=None): 'quit': HideBuiltin, 'get_ipython': self.shell.get_ipython, } - # Recursive reload function - try: - from IPython.lib import deepreload - if self.shell.deep_reload: - from warnings import warn - warn("Automatically replacing builtin `reload` by `deepreload.reload` is deprecated since IPython 4.0, please import `reload` explicitly from `IPython.lib.deepreload", DeprecationWarning) - self.auto_builtins['reload'] = deepreload._dreload - else: - self.auto_builtins['dreload']= deepreload._dreload - except ImportError: - pass def __enter__(self): if self._nested_level == 0: diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index dd1271556d1..10722097270 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -260,21 +260,6 @@ class InteractiveShell(SingletonConfigurable): help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)." ).tag(config=True) debug = Bool(False).tag(config=True) - deep_reload = Bool(False, help= - """ - **Deprecated** - - Will be removed in IPython 6.0 - - Enable deep (recursive) reloading by default. IPython can use the - deep_reload module which reloads changes in modules recursively (it - replaces the reload() function, so you don't need to change anything to - use it). `deep_reload` forces a full reload of modules whose code may - have changed, which the default reload() function does not. When - deep_reload is off, IPython will use the normal reload(), but - deep_reload will still be available as dreload(). - """ - ).tag(config=True) disable_failing_post_execute = Bool(False, help="Don't call post-execute functions that have failed in the past." ).tag(config=True) diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index 521acf352b0..9795eac09c0 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -341,21 +341,3 @@ def reload(module, exclude=('sys', 'os.path', builtin_mod_name, '__main__')): return deep_reload_hook(module) finally: found_now = {} - - -def _dreload(module, **kwargs): - """ - **deprecated** - - import reload explicitly from `IPython.lib.deepreload` to use it - - """ - # this was marked as deprecated and for 5.0 removal, but - # IPython.core_builtin_trap have a Deprecation warning for 6.0, so cannot - # remove that now. - warn(""" -injecting `dreload` in interactive namespace is deprecated since IPython 4.0. -Please import `reload` explicitly from `IPython.lib.deepreload`. -""", DeprecationWarning, stacklevel=2) - reload(module, **kwargs) - diff --git a/docs/source/whatsnew/pr/incompat-no-dreload.rst b/docs/source/whatsnew/pr/incompat-no-dreload.rst new file mode 100644 index 00000000000..89210823901 --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-no-dreload.rst @@ -0,0 +1,3 @@ +The `--deep-reload` flag and the corresponding options to inject `dreload` or +`reload` into the interactive namespace have been removed. You have to +explicitly import `reload` from `IPython.lib.deepreload` to use it. From 8be861cfd8ca27010c51e0d41925772750b339f6 Mon Sep 17 00:00:00 2001 From: Chilaka Ramakrishna Date: Sat, 20 Aug 2016 00:22:21 +0530 Subject: [PATCH 0018/1594] removed Ipython.utils.warn --- IPython/utils/warn.py | 65 ------------------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 IPython/utils/warn.py diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py deleted file mode 100644 index dd4852227ba..00000000000 --- a/IPython/utils/warn.py +++ /dev/null @@ -1,65 +0,0 @@ -# encoding: utf-8 -""" -Utilities for warnings. Shoudn't we just use the built in warnings module. -""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -from __future__ import print_function - -import sys -import warnings - -warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning) - -def warn(msg,level=2,exit_val=1): - """Deprecated - - Standard warning printer. Gives formatting consistency. - - Output is sent to sys.stderr. - - Options: - - -level(2): allows finer control: - 0 -> Do nothing, dummy function. - 1 -> Print message. - 2 -> Print 'WARNING:' + message. (Default level). - 3 -> Print 'ERROR:' + message. - 4 -> Print 'FATAL ERROR:' + message and trigger a sys.exit(exit_val). - - -exit_val (1): exit value returned by sys.exit() for a level 4 - warning. Ignored for all other levels.""" - - warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning) - if level>0: - header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] - print(header[level], msg, sep='', file=sys.stderr) - if level == 4: - print('Exiting.\n', file=sys.stderr) - sys.exit(exit_val) - - -def info(msg): - """Deprecated - - Equivalent to warn(msg,level=1).""" - - warn(msg,level=1) - - -def error(msg): - """Deprecated - - Equivalent to warn(msg,level=3).""" - - warn(msg,level=3) - - -def fatal(msg,exit_val=1): - """Deprecated - - Equivalent to warn(msg,exit_val=exit_val,level=4).""" - - warn(msg,exit_val=exit_val,level=4) From 761d333c839f082ec27611e9729907ec1040da41 Mon Sep 17 00:00:00 2001 From: Chilaka Ramakrishna Date: Sat, 20 Aug 2016 02:54:44 +0530 Subject: [PATCH 0019/1594] added version6.rst and removed IPython.utils.warn --- docs/source/whatsnew/version6.rst | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/source/whatsnew/version6.rst diff --git a/docs/source/whatsnew/version6.rst b/docs/source/whatsnew/version6.rst new file mode 100644 index 00000000000..6748a939526 --- /dev/null +++ b/docs/source/whatsnew/version6.rst @@ -0,0 +1,9 @@ +============ + 6.x Series +============ + +IPython 6.1 +=========== + +* IPython.utils.warn was deprecated in IPython 4.0, and has now been removed. Instead builtin warnings module is used + :ghpull:`9889` \ No newline at end of file From 9ea60c068530f3f9a62dacf15e89b61b43952b3e Mon Sep 17 00:00:00 2001 From: Chilaka Ramakrishna Date: Sat, 20 Aug 2016 23:54:45 +0530 Subject: [PATCH 0020/1594] removed Ipython.utils.warn and created and rst file documenting changes in docs/source/whatsnew/pr --- docs/source/whatsnew/pr/removed-Ipython-utils-warn.rst | 2 ++ docs/source/whatsnew/version6.rst | 9 --------- 2 files changed, 2 insertions(+), 9 deletions(-) create mode 100644 docs/source/whatsnew/pr/removed-Ipython-utils-warn.rst delete mode 100644 docs/source/whatsnew/version6.rst diff --git a/docs/source/whatsnew/pr/removed-Ipython-utils-warn.rst b/docs/source/whatsnew/pr/removed-Ipython-utils-warn.rst new file mode 100644 index 00000000000..faf055f5b71 --- /dev/null +++ b/docs/source/whatsnew/pr/removed-Ipython-utils-warn.rst @@ -0,0 +1,2 @@ +IPython.utils.warn was deprecated in IPython 4.0, and has now been removed. +instead of Ipython.utils.warn inbuilt warning module is used. diff --git a/docs/source/whatsnew/version6.rst b/docs/source/whatsnew/version6.rst deleted file mode 100644 index 6748a939526..00000000000 --- a/docs/source/whatsnew/version6.rst +++ /dev/null @@ -1,9 +0,0 @@ -============ - 6.x Series -============ - -IPython 6.1 -=========== - -* IPython.utils.warn was deprecated in IPython 4.0, and has now been removed. Instead builtin warnings module is used - :ghpull:`9889` \ No newline at end of file From f95a8ef28bb05dfb1f7fc94ddbfc0934359bf0c4 Mon Sep 17 00:00:00 2001 From: pietvo Date: Sun, 21 Aug 2016 23:30:13 +0200 Subject: [PATCH 0021/1594] Update prompts.py Get rid of spurious newline after the output prompt (Out[n]: ) in cases where prompt_toolkit is not used (e.g. running ipython inside Emacs) --- IPython/terminal/prompts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index 732a711ac1e..f52862b1ace 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -71,4 +71,4 @@ def write_output_prompt(self): if self.shell.pt_cli: self.shell.pt_cli.print_tokens(tokens) else: - print(*(s for t, s in tokens), sep='') + sys.stdout.write(''.join(s for t, s in tokens)) From 99ecd7e768ce72930d5741f77570e0b399810d3a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 21 Aug 2016 20:30:24 -0700 Subject: [PATCH 0022/1594] Fix:Typo in readme --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 9005326aa49..2dad8e608ce 100644 --- a/README.rst +++ b/README.rst @@ -32,8 +32,8 @@ if you want to use these. -Development and Instant runnimg -================================ +Development and Instant runnig +============================== You can find the latest version of the development documentation on `readthedocs `_. From e29b23ddebd6de36be7734b6a12e2cd84a245410 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 23 Aug 2016 11:09:10 -0700 Subject: [PATCH 0023/1594] Improve our error messages for non compatibility. --- IPython/__init__.py | 18 ++++++++++++------ README.rst | 42 +++++++++++++++++++++++++++++++++++++++--- setup.py | 15 ++++++++++++--- 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/IPython/__init__.py b/IPython/__init__.py index 6bb5ba76096..c551eb23c23 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -22,17 +22,24 @@ import os import sys -import warnings #----------------------------------------------------------------------------- # Setup everything #----------------------------------------------------------------------------- # Don't forget to also update setup.py when this changes! -v = sys.version_info -if v[:2] < (3,3): - raise ImportError('IPython requires Python version 3.3 or above.') -del v +if sys.version_info < (3,3): + raise ImportError( +""" +IPython 6.0+ does not support Python 2.6, 2.7, 3.0, 3.1, or 3.2. +When using Python 2.7, please install IPython 5.x LTS Long Term Support version. +Beginning with IPython 6.0, Python 3.3 and above is required. + +See IPython `README.rst` file for more information: + + https://github.com/ipython/ipython/blob/master/README.rst + +""") # Make it easy to import extensions - they are always directly on pythonpath. # Therefore, non-IPython modules can be added to extensions directory. @@ -143,4 +150,3 @@ def start_kernel(argv=None, **kwargs): """ from IPython.kernel.zmq.kernelapp import launch_new_instance return launch_new_instance(argv=argv, **kwargs) - diff --git a/README.rst b/README.rst index 9005326aa49..f87f22fd285 100644 --- a/README.rst +++ b/README.rst @@ -36,16 +36,52 @@ Development and Instant runnimg ================================ You can find the latest version of the development documentation on `readthedocs -`_. +`_. You can run IPython from this directory without even installing it system-wide by typing at the terminal:: - + $ python -m IPython Or see the `development installation docs `_ -for the latest revision on read the docs. +for the latest revision on read the docs. Documentation and installation instructions for older version of IPython can be found on the `IPython website `_ + + + +IPython requires Python version 3 or above +========================================== + +Starting with version 6.0, IPython does not support Python 2.7, 3.0, 3.1, or +3.2. + +For a version compatible with Python 2.7, please install the 5.x LTS Long Term +Support version. + +If you are encountering this error message you are likely trying to install or +use IPython from source. You need to checkout the remote 5.x branch. If you are +using git the following should work: + + $ git fetch origin + $ git checkout -b origin/5.x + +If you encounter this error message with a regular install of IPython, then you +likely need to update your package manager, for example if you are using `pip` +check the version of pip with + + $ pip --version + +You will need to update pip to the version 8.2 or greater. If you are not using +pip, please inquiry with the maintainers of the package for your package +manager. + +For more information see one of our blog posts: + + http://blog.jupyter.org/2016/07/08/ipython-5-0-released/ + +As well as the following Pull-Request for discussion: + + https://github.com/ipython/ipython/pull/9900 diff --git a/setup.py b/setup.py index f03db180a72..5d70626d8b1 100755 --- a/setup.py +++ b/setup.py @@ -26,9 +26,18 @@ # This check is also made in IPython/__init__, don't forget to update both when # changing Python version requirements. -v = sys.version_info -if v[:2] < (3,3): - error = "ERROR: IPython requires Python version 3.3 or above." +if sys.version_info < (3,3): + error = """ +IPython 6.0+ does not support Python 2.6, 2.7, 3.0, 3.1, or 3.2. +When using Python 2.7, please install IPython 5.x LTS Long Term Support version. +Beginning with IPython 6.0, Python 3.3 and above is required. + +See IPython `README.rst` file for more information: + + https://github.com/ipython/ipython/blob/master/README.rst + +""" + print(error, file=sys.stderr) sys.exit(1) From 8528e689821099fa3421a7c6e55bc729968ccef8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 23 Aug 2016 17:02:26 -0700 Subject: [PATCH 0024/1594] Update README.rst --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2dad8e608ce..f7b29f32072 100644 --- a/README.rst +++ b/README.rst @@ -32,8 +32,8 @@ if you want to use these. -Development and Instant runnig -============================== +Development and Instant running +=============================== You can find the latest version of the development documentation on `readthedocs `_. From d4db511f1a81563a64700082f0a042e07d15658e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 24 Aug 2016 11:10:31 -0700 Subject: [PATCH 0025/1594] Add warning on documentation for stop of python 2 support. --- docs/source/conf.py | 21 ++++++++++++++++----- docs/source/coredev/release_process.rst | 8 +++++++- docs/source/overview.rst | 3 ++- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1fbf9609745..eda465c4ea2 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -83,6 +83,8 @@ # The suffix of source filenames. source_suffix = '.rst' +rst_prolog = '' + def is_stable(extra): for ext in {'dev', 'b', 'rc'}: if ext in extra: @@ -93,13 +95,22 @@ def is_stable(extra): tags.add('ipystable') else: tags.add('ipydev') - rst_prolog = """ - .. warning:: + rst_prolog += """ +.. warning:: + + This documentation is for a development version of IPython. There may be + significant differences from the latest stable release. +""" + +rst_prolog += """ +.. important:: - This documentation is for a development version of IPython. There may be - significant differences from the latest stable release. + This is the documentation for IPython version > 6.0 which is had + stopped compatibility for python version lower than 3.3. If you are + looking for a version of IPython compatible with python 2.7 please see + the documentation for the IPython 5.x LTS (Long term support branch) - """ +""" # The master toctree document. master_doc = 'index' diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 16b8e6a4bf4..dda82996745 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -170,6 +170,12 @@ Get a fresh clone of the tag for building the release:: 8. Run the release script ------------------------- +.. important:: + + Following releases instructions have information to release IPython 5.x and + 6.x both on python 2 and python 3. When reasing IPython 6+, ignore the step + for python2. + Run the ``release`` script, this step requires having a current wheel, Python >=3.4 and Python 2.7.:: @@ -189,7 +195,7 @@ It should posts them to ``archive.ipython.org``. You will need to use `twine `_ ) manually to actually upload on PyPI. Unlike setuptools, twine is able to upload packages -over SSL. +over SSL:: twine upload dist/* diff --git a/docs/source/overview.rst b/docs/source/overview.rst index ff39e169976..65eb60c0b0f 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -239,7 +239,8 @@ This functionality is optional and now part of the `ipyparallel Portability and Python requirements ----------------------------------- -As of the 2.0 release, IPython works with Python 2.7 and 3.3 or above. +Version 6.0 of IPython work with python 3.3 and above. +Version 2.0 to 5 works with Python 2.7 and 3.3 or above. Version 1.0 additionally worked with Python 2.6 and 3.2. Version 0.12 was the first version to fully support Python 3. From e1c9375c1b50e563bd0aff899cca862190f01814 Mon Sep 17 00:00:00 2001 From: Matteo Date: Sat, 27 Aug 2016 10:25:12 +0200 Subject: [PATCH 0026/1594] Added '%matplotlib agg' option. Behaves quite like inline, but it does not display figures automatically. --- IPython/core/pylabtools.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 815b8d7c7aa..c37649d7d1f 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -23,6 +23,7 @@ 'osx': 'MacOSX', 'nbagg': 'nbAgg', 'notebook': 'nbAgg', + 'agg': 'agg', 'inline' : 'module://ipykernel.pylab.backend_inline'} # We also need a reverse backends2guis mapping that will properly choose which @@ -261,6 +262,8 @@ def find_gui_and_backend(gui=None, gui_select=None): if gui and gui != 'auto': # select backend based on requested gui backend = backends[gui] + if gui == 'agg': + gui = None else: # We need to read the backend from the original data structure, *not* # from mpl.rcParams, since a prior invocation of %matplotlib may have From a676d8eaf02dabaa76a9b584090c9733eb9e8f84 Mon Sep 17 00:00:00 2001 From: kaushikanant Date: Sun, 28 Aug 2016 20:47:50 +0530 Subject: [PATCH 0027/1594] Edit the example when not to use find_cmd command --- IPython/utils/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/utils/process.py b/IPython/utils/process.py index 05dd7a69a71..bdcf8ef98a8 100644 --- a/IPython/utils/process.py +++ b/IPython/utils/process.py @@ -38,7 +38,7 @@ def find_cmd(cmd): following code and looking for the application itself:: import sys - argv = [sys.executable, '-m', 'IPython.terminal'] + argv = [sys.executable, '-m', 'IPython'] Parameters ---------- From a4a1ec72e9d06070a927a9a1f3b1d6ee675ce50e Mon Sep 17 00:00:00 2001 From: Matteo Date: Mon, 29 Aug 2016 12:18:27 +0200 Subject: [PATCH 0028/1594] Updated docstring for agg backend and gui Updated the list of possible values for gui in the docstring, according to my previous commit. --- IPython/core/pylabtools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index c37649d7d1f..e4dad07a8e4 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -246,7 +246,7 @@ def find_gui_and_backend(gui=None, gui_select=None): Parameters ---------- gui : str - Can be one of ('tk','gtk','wx','qt','qt4','inline'). + Can be one of ('tk','gtk','wx','qt','qt4','inline','agg'). gui_select : str Can be one of ('tk','gtk','wx','qt','qt4','inline'). This is any gui already selected by the shell. @@ -254,7 +254,7 @@ def find_gui_and_backend(gui=None, gui_select=None): Returns ------- A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg', - 'WXAgg','Qt4Agg','module://ipykernel.pylab.backend_inline'). + 'WXAgg','Qt4Agg','module://ipykernel.pylab.backend_inline','agg'). """ import matplotlib From dc52f7ed5e733e4a8b322ca0e2f3092658b24014 Mon Sep 17 00:00:00 2001 From: Yuri Numerov Date: Wed, 26 Aug 2015 11:04:26 +0200 Subject: [PATCH 0029/1594] Modified ipython banner This is a squash of all the commits found in `https://github.com/ipython/ipython/pull/8773` - updated banner - updated banner again - fixed type - modified ipython banner - attempt at fixing rebase issues - modified ipython banner - fixed git screwup - updated banner - updated banner again - fixed type - fixed accidental deleted gui_reference restoration --- IPython/core/usage.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/IPython/core/usage.py b/IPython/core/usage.py index a3d17ddda04..5bf300f9f7d 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -325,20 +325,16 @@ """ -quick_guide = """\ -? -> Introduction and overview of IPython's features. -%quickref -> Quick reference. -help -> Python's own help system. -object? -> Details about 'object', use 'object??' for extra details. +quick_guide = "Type '?', '%quickref' or 'help' for help, and 'x?/x??' for object details\n" + +gui_note = """\ +%guiref -> A brief reference about the graphical user interface. """ -default_banner_parts = [ - 'Python %s\n' % (sys.version.split('\n')[0],), - 'Type "copyright", "credits" or "license" for more information.\n\n', - 'IPython {version} -- An enhanced Interactive Python.\n'.format( - version=release.version, - ), - quick_guide +default_banner_parts = ["Python %s\n"%sys.version.split("\n")[0], + "Type 'copyright', 'credits' or 'license' for more information\n" , + 'IPython {version} -- An enhanced Interactive Python.\n'.format(version=release.version), + quick_guide ] default_banner = ''.join(default_banner_parts) From 840693c92d92b23355e0a47544249ba6a16a0739 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 25 Aug 2016 11:53:50 -0700 Subject: [PATCH 0030/1594] Finish banner with BDFL Authoritative decision. (https://github.com/ipython/ipython/pull/8773#issuecomment-242253779) --- IPython/core/usage.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 5bf300f9f7d..b31724579cf 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -76,6 +76,20 @@ At your system command line, type 'ipython -h' to see the command line options available. This document only describes interactive features. +GETTING HELP +------------ + +Within IPython you have various way to access help: + + ? -> Introduction and overview of IPython's features (this screen). + object? -> Details about 'object'. + object?? -> More detailed, verbose information about 'object'. + %quickref -> Quick reference of all IPython specific syntax and magics. + help -> Access Python's own help system. + +If you are in terminal IPython you can quit this screen by pressing `q`. + + MAIN FEATURES ------------- @@ -325,16 +339,9 @@ """ -quick_guide = "Type '?', '%quickref' or 'help' for help, and 'x?/x??' for object details\n" - -gui_note = """\ -%guiref -> A brief reference about the graphical user interface. -""" - default_banner_parts = ["Python %s\n"%sys.version.split("\n")[0], "Type 'copyright', 'credits' or 'license' for more information\n" , - 'IPython {version} -- An enhanced Interactive Python.\n'.format(version=release.version), - quick_guide + "IPython {version} -- An enhanced Interactive Python. Type '?' for help.\n".format(version=release.version), ] default_banner = ''.join(default_banner_parts) From d78f6ae7e939d8c1be62ab93f11b5d7932effaba Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 30 Aug 2016 11:57:37 -0700 Subject: [PATCH 0031/1594] Cleanup some of the skip-if decorators. Initially push to know what needed to finish `https://github.com/ipython/ipython/pull/9491`. Ended up cleaning a few tests, and imports. --- IPython/core/tests/test_run.py | 4 +- IPython/core/tests/test_shellapp.py | 12 ------ IPython/lib/tests/test_pretty.py | 59 +++-------------------------- IPython/testing/decorators.py | 1 - 4 files changed, 6 insertions(+), 70 deletions(-) diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index e3ade579548..e6c20ecbd2f 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -19,7 +19,6 @@ from os.path import join as pjoin import random import sys -import tempfile import textwrap import unittest @@ -209,7 +208,7 @@ def test_builtins_type(self): def test_run_profile( self ): """Test that the option -p, which invokes the profiler, do not crash by invoking execfile""" - _ip = get_ipython() + get_ipython() self.run_tmpfile_p() @@ -368,7 +367,6 @@ def test_ignore_sys_exit(self): with tt.AssertNotPrints('SystemExit'): _ip.magic('run -e %s' % self.fname) - @dec.skip_without('nbformat') # Requires jsonschema def test_run_nb(self): """Test %run notebook.ipynb""" from nbformat import v4, writes diff --git a/IPython/core/tests/test_shellapp.py b/IPython/core/tests/test_shellapp.py index 8e15743a1c4..81342696a7f 100644 --- a/IPython/core/tests/test_shellapp.py +++ b/IPython/core/tests/test_shellapp.py @@ -19,7 +19,6 @@ from IPython.testing import decorators as dec from IPython.testing import tools as tt -from IPython.utils.py3compat import PY3 sqlite_err_maybe = dec.module_not_available('sqlite3') SQLITE_NOT_AVAILABLE_ERROR = ('WARNING: IPython History requires SQLite,' @@ -55,14 +54,3 @@ def test_py_script_file_attribute_interactively(self): out, err = tt.ipexec(self.fname, options=['-i'], commands=['"__file__" in globals()', 'exit()']) self.assertIn("False", out) - - @dec.skip_win32 - @dec.skipif(PY3) - def test_py_script_file_compiler_directive(self): - """Test `__future__` compiler directives with `ipython -i file.py`""" - src = "from __future__ import division\n" - self.mktmp(src) - - out, err = tt.ipexec(self.fname, options=['-i'], - commands=['type(1/2)', 'exit()']) - self.assertIn('float', out) diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index 6f11e99cb07..4cf804180a4 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -7,13 +7,13 @@ from __future__ import print_function from collections import Counter, defaultdict, deque, OrderedDict -import types, string, ctypes +import types, string import nose.tools as nt from IPython.lib import pretty -from IPython.testing.decorators import (skip_without, py2_only, py3_only, - cpython2_only) +from IPython.testing.decorators import (skip_without, py2_only, py3_only) + from IPython.utils.py3compat import PY3, unicode_to_str if PY3: @@ -161,7 +161,7 @@ def test_pprint_break_repr(): def test_bad_repr(): """Don't catch bad repr errors""" with nt.assert_raises(ZeroDivisionError): - output = pretty.pretty(BadRepr()) + pretty.pretty(BadRepr()) class BadException(Exception): def __str__(self): @@ -178,7 +178,7 @@ def __repr__(self): def test_really_bad_repr(): with nt.assert_raises(BadException): - output = pretty.pretty(ReallyBadRepr()) + pretty.pretty(ReallyBadRepr()) class SA(object): @@ -485,52 +485,3 @@ def test_mappingproxy(): ] for obj, expected in cases: nt.assert_equal(pretty.pretty(obj), expected) - -@cpython2_only # In PyPy, types.DictProxyType is dict -def test_dictproxy(): - # This is the dictproxy constructor itself from the Python API, - DP = ctypes.pythonapi.PyDictProxy_New - DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object - - underlying_dict = {} - mp_recursive = DP(underlying_dict) - underlying_dict[0] = mp_recursive - underlying_dict[-3] = underlying_dict - - cases = [ - (DP({}), "dict_proxy({})"), - (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"), - (DP({k: k.lower() for k in string.ascii_uppercase}), - "dict_proxy({'A': 'a',\n" - " 'B': 'b',\n" - " 'C': 'c',\n" - " 'D': 'd',\n" - " 'E': 'e',\n" - " 'F': 'f',\n" - " 'G': 'g',\n" - " 'H': 'h',\n" - " 'I': 'i',\n" - " 'J': 'j',\n" - " 'K': 'k',\n" - " 'L': 'l',\n" - " 'M': 'm',\n" - " 'N': 'n',\n" - " 'O': 'o',\n" - " 'P': 'p',\n" - " 'Q': 'q',\n" - " 'R': 'r',\n" - " 'S': 's',\n" - " 'T': 't',\n" - " 'U': 'u',\n" - " 'V': 'v',\n" - " 'W': 'w',\n" - " 'X': 'x',\n" - " 'Y': 'y',\n" - " 'Z': 'z'})"), - (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"), - ] - for obj, expected in cases: - nt.assert_is_instance(obj, types.DictProxyType) # Meta-test - nt.assert_equal(pretty.pretty(obj), expected) - nt.assert_equal(pretty.pretty(underlying_dict), - "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}") diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index 087555d46bc..f31af9170fe 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -336,7 +336,6 @@ def skip_file_no_x11(name): known_failure_py3 = knownfailureif(sys.version_info[0] >= 3, 'This test is known to fail on Python 3.') -cpython2_only = skipif(PY3 or PYPY, "This test only runs on CPython 2.") py2_only = skipif(PY3, "This test only runs on Python 2.") py3_only = skipif(PY2, "This test only runs on Python 3.") From 138b3a4aa3279ffaa570630a8e5355bf860f1bc6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jul 2016 12:21:55 -0700 Subject: [PATCH 0032/1594] Do not update the unders if they are user defined Closes jupyter/notebook#1628 (once there are tests). Still shift the internal reference to self._,__,___ but do not assign it in user ns. I would expect this to be a change of behavior and have the (slight) side effect that if any of the _, __, or __ are defined, then none of these are updated. We could update the logic to do the right think on leapfrog _, __ or __ if user-set, but is it worth it. If _ is in builtins, then _ will not update the history and _ will be the builtins, unless user set it explicitly in which case it takes precedence. Summary if user have set _ _ == value set by the user elif _ in builtins: _ == value in builtins._ else: _ == previous result. Note that this logic may fall down if the use set _ to a specific value, and have this save value returned while _ is also in builtin: In [1]: import gettext ; gettext.install('foo') In [2]: _ = 'Example' In [3]: _ Out[3]: 'Example' In [4]: _ Out[4]: 'Example' In [5]: _ Out[5]: > --- IPython/core/displayhook.py | 27 +++++++++++++++++++------- IPython/core/tests/test_displayhook.py | 27 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 07d733e22d2..83941e6e767 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -76,6 +76,9 @@ def check_for_underscore(self): # particular uses _, so we need to stay away from it. if '_' in builtin_mod.__dict__: try: + user_value = self.shell.user_ns['_'] + if user_value is not self._: + return del self.shell.user_ns['_'] except KeyError: pass @@ -195,13 +198,23 @@ def update_user_ns(self, result): if result is not self.shell.user_ns['_oh']: if len(self.shell.user_ns['_oh']) >= self.cache_size and self.do_full_cache: self.cull_cache() - # Don't overwrite '_' and friends if '_' is in __builtin__ (otherwise - # we cause buggy behavior for things like gettext). - if '_' not in builtin_mod.__dict__: - self.___ = self.__ - self.__ = self._ - self._ = result + # Don't overwrite '_' and friends if '_' is in __builtin__ + # (otherwise we cause buggy behavior for things like gettext). and + # do not overwrite _, __ or ___ if one of these has been assigned + # by the user. + update_unders = True + for unders in ['_'*i for i in range(1,4)]: + if not unders in self.shell.user_ns: + continue + if getattr(self, unders) is not self.shell.user_ns.get(unders): + update_unders = False + + self.___ = self.__ + self.__ = self._ + self._ = result + + if ('_' not in builtin_mod.__dict__) and (update_unders): self.shell.push({'_':self._, '__':self.__, '___':self.___}, interactive=False) @@ -209,7 +222,7 @@ def update_user_ns(self, result): # hackish access to top-level namespace to create _1,_2... dynamically to_main = {} if self.do_full_cache: - new_result = '_'+repr(self.prompt_count) + new_result = '_%s' % self.prompt_count to_main[new_result] = result self.shell.push(to_main, interactive=False) self.shell.user_ns['_oh'][self.prompt_count] = result diff --git a/IPython/core/tests/test_displayhook.py b/IPython/core/tests/test_displayhook.py index 3cca42a8089..67b99d59823 100644 --- a/IPython/core/tests/test_displayhook.py +++ b/IPython/core/tests/test_displayhook.py @@ -26,3 +26,30 @@ def test_output_quiet(): with AssertNotPrints('2'): ip.run_cell('1+1;\n#commented_out_function()', store_history=True) + +def test_underscore_no_overrite_user(): + ip.run_cell('_ = 42', store_history=True) + ip.run_cell('1+1', store_history=True) + + with AssertPrints('42'): + ip.run_cell('print(_)', store_history=True) + + ip.run_cell('del _', store_history=True) + ip.run_cell('6+6', store_history=True) + with AssertPrints('12'): + ip.run_cell('_', store_history=True) + + +def test_underscore_no_overrite_builtins(): + ip.run_cell("import gettext ; gettext.install('foo')", store_history=True) + ip.run_cell('3+3', store_history=True) + + with AssertPrints('gettext'): + ip.run_cell('print(_)', store_history=True) + + ip.run_cell('_ = "userset"', store_history=True) + + with AssertPrints('userset'): + ip.run_cell('print(_)', store_history=True) + ip.run_cell('import builtins; del builtins._') + From 579c3b55dcddf62def08971732836de15ede0037 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 31 Aug 2016 13:22:57 +0100 Subject: [PATCH 0033/1594] Stop stripping encoding cookie As far as I can tell, it's no longer a syntax error to have the magic encoding comment when parsing a unicode string. Since IPython 6 doesn't support Python 2, we can simply stop making this change. Closes gh-9919 --- IPython/core/inputsplitter.py | 2 -- IPython/core/inputtransformer.py | 24 ------------------- IPython/core/tests/test_inputtransformer.py | 26 --------------------- 3 files changed, 52 deletions(-) diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index ac14747d69c..2d0ca2dcf11 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -26,7 +26,6 @@ from IPython.core.inputtransformer import (leading_indent, classic_prompt, ipy_prompt, - strip_encoding_cookie, cellmagic, assemble_logical_lines, help_end, @@ -485,7 +484,6 @@ def __init__(self, line_input_checker=True, physical_line_transforms=None, classic_prompt(), ipy_prompt(), cellmagic(end_on_blank_line=line_input_checker), - strip_encoding_cookie(), ] self.assemble_logical_lines = assemble_logical_lines() diff --git a/IPython/core/inputtransformer.py b/IPython/core/inputtransformer.py index cd8519b22c9..811d12814e7 100644 --- a/IPython/core/inputtransformer.py +++ b/IPython/core/inputtransformer.py @@ -9,7 +9,6 @@ from IPython.core.splitinput import LineInfo from IPython.utils import tokenize2 -from IPython.utils.openpy import cookie_comment_re from IPython.utils.py3compat import with_metaclass, PY3 from IPython.utils.tokenize2 import generate_tokens, untokenize, TokenError @@ -505,29 +504,6 @@ def leading_indent(): line = (yield line) -@CoroutineInputTransformer.wrap -def strip_encoding_cookie(): - """Remove encoding comment if found in first two lines - - If the first or second line has the `# coding: utf-8` comment, - it will be removed. - """ - line = '' - while True: - line = (yield line) - # check comment on first two lines - for i in range(2): - if line is None: - break - if cookie_comment_re.match(line): - line = (yield "") - else: - line = (yield line) - - # no-op on the rest of the cell - while line is not None: - line = (yield line) - _assign_pat = \ r'''(?P(\s*) ([\w\.]+) # Initial identifier diff --git a/IPython/core/tests/test_inputtransformer.py b/IPython/core/tests/test_inputtransformer.py index ebad8ab6d36..27e67d8dd0c 100644 --- a/IPython/core/tests/test_inputtransformer.py +++ b/IPython/core/tests/test_inputtransformer.py @@ -78,13 +78,6 @@ def transform_checker(tests, transformer, **kwargs): (' ',' '), # blank lines are kept intact ], - strip_encoding_cookie = - [ - ('# -*- encoding: utf-8 -*-', ''), - ('# coding: latin-1', ''), - ], - - # Tests for the escape transformer to leave normal code alone escaped_noesc = [ (' ', ' '), @@ -255,20 +248,6 @@ def transform_checker(tests, transformer, **kwargs): ], ], - strip_encoding_cookie = - [ - [ - ('# -*- coding: utf-8 -*-', ''), - ('foo', 'foo'), - ], - [ - ('#!/usr/bin/env python', '#!/usr/bin/env python'), - ('# -*- coding: latin-1 -*-', ''), - # only the first-two lines - ('# -*- coding: latin-1 -*-', '# -*- coding: latin-1 -*-'), - ], - ], - multiline_datastructure_prompt = [ [('>>> a = [1,','a = [1,'), ('... 2]','2]'), @@ -379,11 +358,6 @@ def test_ipy_prompt(): (u'In [1]: bar', 'In [1]: bar'), ], ipt.ipy_prompt) -def test_coding_cookie(): - tt.check_pairs(transform_and_reset(ipt.strip_encoding_cookie), syntax['strip_encoding_cookie']) - for example in syntax_ml['strip_encoding_cookie']: - transform_checker(example, ipt.strip_encoding_cookie) - def test_assemble_logical_lines(): tests = \ [ [(u"a = \\", None), From cfd8c8eec40d51cdcc6ca70d2d8cd02091234316 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 31 Aug 2016 16:34:48 +0100 Subject: [PATCH 0034/1594] Add whatsnew entry --- docs/source/whatsnew/pr/capture-displayhook.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/source/whatsnew/pr/capture-displayhook.rst diff --git a/docs/source/whatsnew/pr/capture-displayhook.rst b/docs/source/whatsnew/pr/capture-displayhook.rst new file mode 100644 index 00000000000..5952f3c02f6 --- /dev/null +++ b/docs/source/whatsnew/pr/capture-displayhook.rst @@ -0,0 +1,3 @@ +- The :cellmagic:`capture` magic can now capture the result of a cell (from an + expression on the last line), as well as printed and displayed output. + :ghpull:`9851`. From 1ca71ed13aca783f801f50c47f4a6dc7b17a8e8f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 31 Aug 2016 11:18:10 -0700 Subject: [PATCH 0035/1594] Update phrasing with Carol suggestions. --- docs/source/conf.py | 15 +++++++++------ docs/source/coredev/release_process.rst | 6 +++--- docs/source/overview.rst | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index eda465c4ea2..33440a249fb 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -98,17 +98,20 @@ def is_stable(extra): rst_prolog += """ .. warning:: - This documentation is for a development version of IPython. There may be - significant differences from the latest stable release. + This documentation covers a development version of IPython. The development + version may differ significantly from the latest stable release. """ rst_prolog += """ .. important:: - This is the documentation for IPython version > 6.0 which is had - stopped compatibility for python version lower than 3.3. If you are - looking for a version of IPython compatible with python 2.7 please see - the documentation for the IPython 5.x LTS (Long term support branch) + This documentation covers IPython versions 6.0 and higher. Beginning with + version 6.0, IPython stopped supporting compatibility with Python versions + lower than 3.3 including all versions of Python 2.7. + + If you are looking for an IPython version compatible with Python 2.7, + please use the IPython 5.x LTS release and refer to its documentation (LTS + is the long term support release). """ diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index dda82996745..c8255acd411 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -172,9 +172,9 @@ Get a fresh clone of the tag for building the release:: .. important:: - Following releases instructions have information to release IPython 5.x and - 6.x both on python 2 and python 3. When reasing IPython 6+, ignore the step - for python2. + These steps cover instructions for creating releases of IPython 5.x LTS and + IPython 6.x. Ignore release steps for Python 2 when releasing IPython 6.x + which no longer supports Python 2. Run the ``release`` script, this step requires having a current wheel, Python >=3.4 and Python 2.7.:: diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 65eb60c0b0f..b3a4aabac3e 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -239,8 +239,8 @@ This functionality is optional and now part of the `ipyparallel Portability and Python requirements ----------------------------------- -Version 6.0 of IPython work with python 3.3 and above. -Version 2.0 to 5 works with Python 2.7 and 3.3 or above. +Version 6.0+ supports compatibility with Python 3.3 and higher. +Versions 2.0 to 5.x work with Python 2.7.x releases and Python 3.3 and higher. Version 1.0 additionally worked with Python 2.6 and 3.2. Version 0.12 was the first version to fully support Python 3. From 403739a63aecbf87a9d96ebd84cb1870f3015f2c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 1 Sep 2016 12:43:11 +0100 Subject: [PATCH 0036/1594] Only make .tar.gz sdists when releasing PEP 527, which was just accepted, says that there can only be one sdist per release. Tarballs are already the more common sdist format on PyPI, so let's go with that. --- tools/toollib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/toollib.py b/tools/toollib.py index 37439058ff3..bc0ed615cef 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -18,7 +18,7 @@ # Build commands # Source dists -sdists = './setup.py sdist --formats=gztar,zip' +sdists = './setup.py sdist --formats=gztar' # Binary dists def buildwheels(): sh('python3 setupegg.py bdist_wheel' % py) From 8d9d689280bc210d88a2a0a99a23fb928c431c45 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 1 Sep 2016 15:20:43 +0100 Subject: [PATCH 0037/1594] Update release docs for PEP 527 --- docs/source/coredev/release_process.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 16b8e6a4bf4..cf9a28c3407 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -175,7 +175,7 @@ Run the ``release`` script, this step requires having a current wheel, Python ./tools/release -This makes the tarballs, zipfiles, and wheels, and put them under the ``dist/`` +This makes the tarballs and wheels, and puts them under the ``dist/`` folder. Be sure to test the ``wheels`` and the ``sdist`` locally before uploading them to PyPI. We do not use an universal wheel as each wheel installs an ``ipython2`` or ``ipython3`` script, depending on the version of From 1b8eae7488aa4e2bfe7e27a4b01543add6468692 Mon Sep 17 00:00:00 2001 From: Carl Smith Date: Fri, 2 Sep 2016 12:04:23 +0100 Subject: [PATCH 0038/1594] Add shortcut to edit cell --- IPython/terminal/shortcuts.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py index 456d4e3379e..bc5911aab27 100644 --- a/IPython/terminal/shortcuts.py +++ b/IPython/terminal/shortcuts.py @@ -62,6 +62,10 @@ def register_ipython_shortcuts(registry, shell): filter=(HasFocus(DEFAULT_BUFFER) & EmacsInsertMode()))(newline_with_copy_margin) + registry.add_binding(Keys.F2, + filter=HasFocus(DEFAULT_BUFFER) + )(open_input_in_editor) + if shell.display_completions == 'readlinelike': registry.add_binding(Keys.ControlI, filter=(HasFocus(DEFAULT_BUFFER) @@ -170,7 +174,9 @@ def newline_with_copy_margin(event): pos_diff = cursor_start_pos - cursor_end_pos b.cursor_right(count=pos_diff) - +def open_input_in_editor(event): + event.cli.current_buffer.tempfile_suffix = ".py" + event.cli.current_buffer.open_in_editor(event.cli) if sys.platform == 'win32': From ee66c768060d6e1f81d52f67d18adcce6f5c1593 Mon Sep 17 00:00:00 2001 From: Bibo Hao Date: Thu, 8 Sep 2016 03:03:10 +0800 Subject: [PATCH 0039/1594] Show (Call) Signature of object first. When user press Shift+Tab to call up a Tooltip to show the information of a function/method/callable object, I suggest IPython display (Call) Signature fist, so that users can know to call the function quickly. For object with much information, the (Call) Signature will be hidden in Jupyter Notebook. --- IPython/core/oinspect.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 971e4dac3a6..c5b9f777833 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -658,6 +658,9 @@ def code_formatter(text): else: # General Python objects + append_field(_mime, 'Signature', 'definition', code_formatter) + append_field(_mime, 'Call signature', 'call_def', code_formatter) + append_field(_mime, 'Type', 'type_name') # Base class for old-style instances @@ -671,9 +674,8 @@ def code_formatter(text): append_field(_mime, 'Namespace', 'namespace') append_field(_mime, 'Length', 'length') - append_field(_mime, 'File', 'file'), - append_field(_mime, 'Signature', 'definition', code_formatter) - + append_field(_mime, 'File', 'file') + # Source or docstring, depending on detail level and whether # source found. if detail_level > 0: @@ -683,10 +685,8 @@ def code_formatter(text): append_field(_mime, 'Class docstring', 'class_docstring', formatter) append_field(_mime, 'Init docstring', 'init_docstring', formatter) - append_field(_mime, 'Call signature', 'call_def', code_formatter) append_field(_mime, 'Call docstring', 'call_docstring', formatter) - - + return self.format_mime(_mime) From 65c8ea84a32d7c403cd3238d2d038c9b062501fb Mon Sep 17 00:00:00 2001 From: Chilaka Ramakrishna Date: Fri, 9 Sep 2016 20:21:27 +0530 Subject: [PATCH 0040/1594] added namespace condition in IPcompleter --- IPython/core/completer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 87b13b1c5d8..f431146841a 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1164,6 +1164,9 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): if cursor_pos is None: cursor_pos = len(line_buffer) if text is None else len(text) + if self.use_main_ns: + self.namespace = __main__.__dict__ + if PY3: base_text = text if not line_buffer else line_buffer[:cursor_pos] From dc59d18ce480e6bdede8b372be2c4bbfd83dbb14 Mon Sep 17 00:00:00 2001 From: Piotr Przetacznik Date: Fri, 9 Sep 2016 23:24:02 +0200 Subject: [PATCH 0041/1594] Add more information about adding kernels to jupyter Add: - information about current solution with virtualenv, - add deprecated solution. --- docs/source/install/kernel_install.rst | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index c34287d9d12..b5486a04dcb 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -53,3 +53,33 @@ For example, using conda environments: The ``--name`` value is used by Jupyter internally. These commands will overwrite any existing kernel with the same name. ``--display-name`` is what you see in the notebook menus. + +Using virtualenv you can add your new environments by linking to specific instance of your Python: + +.. sourcecode:: bash + + python -m ipykernel install --prefix=/path/to/new_env --name python_new_env + +Note that this command will create new configuration for kernel in one of it's prefered location (see ``jupyter --paths`` command for more details): + +* system-wide (e.g. /usr/local/share), +* in Jupyter's env (sys.prefix/share), +* per-user (~/.local/share or ~/Library/share) + +You can also create configuration in temprary location and install it in Jupyter (copy configuration files) with: + +.. sourcecode:: bash + + ipython kernel install --prefix /tmp + jupyter kernelspec install /tmp/share/jupyter/kernels/python3 + +**Deprecated:** You can also create configuration for new environment by new configuration's file in `~/.ipython/kernels/my_env/kernel.json` with following content:: + + { + "argv": ["~/path/to/env/bin/python", "-m", "IPython.kernel", + "-f", "{connection_file}"], + "display_name": "Python 3 (my new env)", + "language": "python" + } + +Please note that kernel detection in standard ``~/.ipython/`` location is supported as part of backward-compatibility and may not be provided in further versions. From 24031baa364284fcacef77c39ab8df96f5891aff Mon Sep 17 00:00:00 2001 From: Piotr Przetacznik Date: Sat, 10 Sep 2016 12:49:41 +0200 Subject: [PATCH 0042/1594] Fix typo --- docs/source/install/kernel_install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index b5486a04dcb..cbaead74a63 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -66,7 +66,7 @@ Note that this command will create new configuration for kernel in one of it's p * in Jupyter's env (sys.prefix/share), * per-user (~/.local/share or ~/Library/share) -You can also create configuration in temprary location and install it in Jupyter (copy configuration files) with: +You can also create configuration in temporary location and install it in Jupyter (copy configuration files) with: .. sourcecode:: bash From 7ec9c16d8e0ef8c0ecbe09a4598ce307b3fc1c4b Mon Sep 17 00:00:00 2001 From: mbyt Date: Sun, 11 Sep 2016 21:19:25 +0200 Subject: [PATCH 0043/1594] -m IPython.terminal.debugger trying to enabling debugging analog to pdb by `python -m IPython.terminal.debugger myscript.py` --- IPython/terminal/debugger.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 36dda896b88..501d7202067 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -75,3 +75,8 @@ def cmdloop(self, intro=None): def set_trace(): TerminalPdb().set_trace() + +if __name__ == '__main__': + import pdb + pdb.Pdb = TerminalPdb + pdb.main() From 5d4209a6b177db17288842b20599d607f27af9af Mon Sep 17 00:00:00 2001 From: Jamshed Vesuna Date: Sun, 11 Sep 2016 15:57:13 -0700 Subject: [PATCH 0044/1594] Only track unique history of commands --- IPython/terminal/interactiveshell.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 5ad8d2f87ed..cde9ba2e35e 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -138,7 +138,7 @@ def debugger_cls(self): highlighting: \n %s""" % ', '.join(get_all_styles()) ).tag(config=True) - + @observe('highlighting_style') @observe('colors') def _highlighting_style_changed(self, change): @@ -183,7 +183,7 @@ def _displayhook_class_default(self): help="Automatically set the terminal title" ).tag(config=True) - display_completions = Enum(('column', 'multicolumn','readlinelike'), + display_completions = Enum(('column', 'multicolumn','readlinelike'), help= ( "Options for displaying tab completions, 'column', 'multicolumn', and " "'readlinelike'. These options are for `prompt_toolkit`, see " "`prompt_toolkit` documentation for more information." @@ -230,6 +230,7 @@ def prompt(): cell = cell.rstrip() if cell and (cell != last_cell): history.append(cell) + last_cell = cell self._style = self._make_style_from_name_or_cls(self.highlighting_style) style = DynamicStyle(lambda: self._style) @@ -255,7 +256,7 @@ def _make_style_from_name_or_cls(self, name_or_cls): """ Small wrapper that make an IPython compatible style from a style name - We need that to add style for prompt ... etc. + We need that to add style for prompt ... etc. """ style_overrides = {} if name_or_cls == 'legacy': From 5f59e120d5ada4d733dd322dd661af2219037c53 Mon Sep 17 00:00:00 2001 From: Piotr Przetacznik Date: Mon, 12 Sep 2016 16:02:01 +0200 Subject: [PATCH 0045/1594] Add additional information to installing ipython docs --- docs/source/install/kernel_install.rst | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index cbaead74a63..3072d69da92 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -54,32 +54,22 @@ The ``--name`` value is used by Jupyter internally. These commands will overwrit any existing kernel with the same name. ``--display-name`` is what you see in the notebook menus. -Using virtualenv you can add your new environments by linking to specific instance of your Python: +Using virtualenv or conda envs, you can make your IPython kernel in one env available to Jupyter in a different env. To do so, run ipykernel install from the kernel's env, with --prefix pointing to the Jupyter env: .. sourcecode:: bash - python -m ipykernel install --prefix=/path/to/new_env --name python_new_env - + /path/to/kernel/env/bin/python -m ipykernel install --prefix=/path/to/jupyter/env --name 'python-my-env' + Note that this command will create new configuration for kernel in one of it's prefered location (see ``jupyter --paths`` command for more details): * system-wide (e.g. /usr/local/share), * in Jupyter's env (sys.prefix/share), * per-user (~/.local/share or ~/Library/share) -You can also create configuration in temporary location and install it in Jupyter (copy configuration files) with: +In case where you want to edit generated kernelspec configuration before installing it you can do the same with two steps approach. You can create configuration in temporary location and install it in Jupyter (copy configuration files) with: .. sourcecode:: bash ipython kernel install --prefix /tmp jupyter kernelspec install /tmp/share/jupyter/kernels/python3 -**Deprecated:** You can also create configuration for new environment by new configuration's file in `~/.ipython/kernels/my_env/kernel.json` with following content:: - - { - "argv": ["~/path/to/env/bin/python", "-m", "IPython.kernel", - "-f", "{connection_file}"], - "display_name": "Python 3 (my new env)", - "language": "python" - } - -Please note that kernel detection in standard ``~/.ipython/`` location is supported as part of backward-compatibility and may not be provided in further versions. From d9eecc73486a8dc53d19721d81a35a33bf9c6a37 Mon Sep 17 00:00:00 2001 From: Piotr Przetacznik Date: Mon, 12 Sep 2016 18:28:24 +0200 Subject: [PATCH 0046/1594] Rephrase two steps installing kernel in docs --- docs/source/install/kernel_install.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index 3072d69da92..26436fc17d9 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -66,10 +66,15 @@ Note that this command will create new configuration for kernel in one of it's p * in Jupyter's env (sys.prefix/share), * per-user (~/.local/share or ~/Library/share) -In case where you want to edit generated kernelspec configuration before installing it you can do the same with two steps approach. You can create configuration in temporary location and install it in Jupyter (copy configuration files) with: +If you want to edit the kernelspec before installing it, you can do so in two steps. +First, ask IPython to write its spec to a temporary location: .. sourcecode:: bash ipython kernel install --prefix /tmp - jupyter kernelspec install /tmp/share/jupyter/kernels/python3 +edit the files in /tmp/share/jupyter/kernels/python3 to your liking, then when you are ready, tell Jupyter to install it (this will copy the files into a place Jupyter will look): + +.. sourcecode:: bash + + jupyter kernelspec install /tmp/share/jupyter/kernels/python3 From 190ffa3cae4da1c2d13d746914551a12f4278500 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 13 Sep 2016 10:57:29 +0100 Subject: [PATCH 0047/1594] Don't require win_unicode_console on Python 3.6 It looks like the changes Drekin's win_unicode_console makes have essentially been integrated into Python 3.6, so it will use the Unicode APIs for Windows console access by default. See [PEP 528](https://www.python.org/dev/peps/pep-0528/). So we shouldn't need to load WUC on Python 3.6, and it may even have some strange interactions. --- IPython/terminal/interactiveshell.py | 5 +++++ setup.py | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index cde9ba2e35e..9db67450c5a 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -340,6 +340,11 @@ def prompt_for_code(self): return document.text def enable_win_unicode_console(self): + if sys.version_info >= (3, 6): + # Since PEP 528, Python uses the unicode APIs for the Windows + # console by default, so WUC shouldn't be needed. + return + import win_unicode_console if PY3: diff --git a/setup.py b/setup.py index 5d70626d8b1..8429aa980fc 100755 --- a/setup.py +++ b/setup.py @@ -218,7 +218,8 @@ def run(self): ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'], ':sys_platform != "win32"': ['pexpect'], ':sys_platform == "darwin"': ['appnope'], - ':sys_platform == "win32"': ['colorama', 'win_unicode_console>=0.5'], + ':sys_platform == "win32"': ['colorama'], + ':sys_platform == "win32" and python_version < "3.6"': ['win_unicode_console>=0.5'], 'test:python_version == "2.7"': ['mock'], }) # FIXME: re-specify above platform dependencies for pip < 6 From 7c12b021ee7bdcaf8cec814a624203d8e74aab08 Mon Sep 17 00:00:00 2001 From: Piotr Przetacznik Date: Tue, 13 Sep 2016 13:11:15 +0200 Subject: [PATCH 0048/1594] Apply grammar corrections for ipython kernels installation docs --- docs/source/install/kernel_install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index 26436fc17d9..aa389647ec6 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -60,7 +60,7 @@ Using virtualenv or conda envs, you can make your IPython kernel in one env avai /path/to/kernel/env/bin/python -m ipykernel install --prefix=/path/to/jupyter/env --name 'python-my-env' -Note that this command will create new configuration for kernel in one of it's prefered location (see ``jupyter --paths`` command for more details): +Note that this command will create a new configuration for the kernel in one of the prefered location (see ``jupyter --paths`` command for more details): * system-wide (e.g. /usr/local/share), * in Jupyter's env (sys.prefix/share), From ba43c3fe3fc6a0778a9411780f1cfdd0b136b882 Mon Sep 17 00:00:00 2001 From: tillahoffmann Date: Wed, 14 Sep 2016 09:45:10 +0100 Subject: [PATCH 0049/1594] Add set_trace to core debugger. --- IPython/core/debugger.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 591e4c3b8ca..7965c25dfc8 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -621,3 +621,14 @@ def do_where(self, arg): self.print_stack_trace() do_w = do_where + + +def set_trace(frame=None, condition=True): + """ + Start debugging from `frame` if `condition` is satisfied. + + If frame is not specified, debugging starts from caller's frame. + """ + if condition: + pdb = Pdb() + pdb.set_trace() From 99b5ad4cec4f80b39777a45aca6c4c00ee60d716 Mon Sep 17 00:00:00 2001 From: tillahoffmann Date: Wed, 14 Sep 2016 13:06:24 +0100 Subject: [PATCH 0050/1594] Remove condition from set_trace. --- IPython/core/debugger.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 7965c25dfc8..8091bea998a 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -623,12 +623,11 @@ def do_where(self, arg): do_w = do_where -def set_trace(frame=None, condition=True): - """ - Start debugging from `frame` if `condition` is satisfied. - - If frame is not specified, debugging starts from caller's frame. - """ - if condition: - pdb = Pdb() - pdb.set_trace() +def set_trace(frame=None): + """ + Start debugging from `frame`. + + If frame is not specified, debugging starts from caller's frame. + """ + pdb = Pdb() + pdb.set_trace() From 908750a6c0a95c775b109eac373f55d626defa88 Mon Sep 17 00:00:00 2001 From: tillahoffmann Date: Thu, 15 Sep 2016 08:02:51 +0100 Subject: [PATCH 0051/1594] Fix unused frame variable. --- IPython/core/debugger.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 8091bea998a..47bc92f350a 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -629,5 +629,4 @@ def set_trace(frame=None): If frame is not specified, debugging starts from caller's frame. """ - pdb = Pdb() - pdb.set_trace() + Pdb().set_trace(frame or sys._getframe().f_back) From 9b36b69645414cf38e83d9f693f73bb8d8369872 Mon Sep 17 00:00:00 2001 From: tillahoffmann Date: Thu, 15 Sep 2016 08:30:13 +0100 Subject: [PATCH 0052/1594] Add frame parameter to terminal debugger. --- IPython/terminal/debugger.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 501d7202067..821a45b5bf3 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -7,6 +7,8 @@ from prompt_toolkit.shortcuts import create_prompt_application from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.enums import EditingMode +import sys + class TerminalPdb(Pdb): def __init__(self, *args, **kwargs): @@ -72,8 +74,14 @@ def cmdloop(self, intro=None): except Exception: raise -def set_trace(): - TerminalPdb().set_trace() + +def set_trace(frame=None): + """ + Start debugging from `frame`. + + If frame is not specified, debugging starts from caller's frame. + """ + TerminalPdb().set_trace(frame or sys._getframe().f_back) if __name__ == '__main__': From 35b84f7737441c98a5c785627ad2b3fc707d2642 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 16 Sep 2016 10:50:20 +0100 Subject: [PATCH 0053/1594] Some mpl backends have no corresponding GUI Hopefully fixes a test failure on Windows where mpl tries to activate an 'agg' gui. Should we just manually define the backend2gui dict instead of inverting backends and then modifying it? --- IPython/core/pylabtools.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index c0d5fb10f15..5ef654328ab 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -39,6 +39,10 @@ backend2gui['GTK3Cairo'] = 'gtk3' backend2gui['WX'] = 'wx' backend2gui['CocoaAgg'] = 'osx' +# And some backends that don't need GUI integration +del backend2gui['nbAgg'] +del backend2gui['agg'] +del backend2gui['module://ipykernel.pylab.backend_inline'] #----------------------------------------------------------------------------- # Matplotlib utilities From 4b53350acfa604aebb097203c9feb568a08d00f5 Mon Sep 17 00:00:00 2001 From: Chilaka Ramakrishna Date: Fri, 16 Sep 2016 23:26:07 +0530 Subject: [PATCH 0054/1594] corrected split with rsplit --- 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 159169d6eb9..f445e8bd94a 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -437,7 +437,7 @@ def _debug_post_mortem(self): def _debug_exec(self, code, breakpoint): if breakpoint: - (filename, bp_line) = breakpoint.split(':', 1) + (filename, bp_line) = breakpoint.rsplit(':', 1) bp_line = int(bp_line) else: (filename, bp_line) = (None, None) From d6299bc6ebb90fdea8de85acbe02d279b7854175 Mon Sep 17 00:00:00 2001 From: mbyt Date: Thu, 15 Sep 2016 22:26:53 +0200 Subject: [PATCH 0055/1594] enable quitting for -m IPython.terminal.debugger --- IPython/terminal/debugger.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 821a45b5bf3..1c9bf04aadd 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -86,5 +86,11 @@ def set_trace(frame=None): if __name__ == '__main__': import pdb + # IPython.core.debugger.Pdb.trace_dispatch shall not catch + # bdb.BdbQuit. When started through __main__ and an exeption + # happend after hitting "c", this is needed in order to + # be able to quit the debugging session (see #9950). + old_trace_dispatch = pdb.Pdb.trace_dispatch pdb.Pdb = TerminalPdb + pdb.Pdb.trace_dispatch = old_trace_dispatch pdb.main() From 168364a781fb5b779848a3b46d8e740fd06c244d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 17 Sep 2016 21:33:42 +0100 Subject: [PATCH 0056/1594] Catch UnicodeDecodeError from file lying about its encoding Closes gh-9954 I'd like to show a more useful error, but we're several layers away from the code that knows the filename, and I don't want to duplicate a load of code from the traceback module. This prevents it from crashing IPython, at least. --- IPython/core/ultratb.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 2e4268f8955..98e2cd586fa 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1130,6 +1130,12 @@ def get_records(self, etb, number_of_lines_of_context, tb_offset): # problems, but it generates empty tracebacks for console errors # (5 blanks lines) where none should be returned. return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset) + except UnicodeDecodeError: + # This can occur if a file's encoding magic comment is wrong. + # I can't see a way to recover without duplicating a bunch of code + # from the stdlib traceback module. --TK + error('\nUnicodeDecodeError while processing traceback.\n') + return None except: # FIXME: I've been getting many crash reports from python 2.3 # users, traceable to inspect.py. If I can find a small test-case From 45830139ec7f4ad2108e7098e980fa6a191f57d7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 18 Sep 2016 19:13:45 -0700 Subject: [PATCH 0057/1594] recommend GhPro as a replacemetn for custom tools --- tools/backport_pr.py | 4 ++++ tools/github_stats.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tools/backport_pr.py b/tools/backport_pr.py index eb405fc669c..a8da3afce42 100755 --- a/tools/backport_pr.py +++ b/tools/backport_pr.py @@ -161,6 +161,10 @@ def should_backport(labels=None, milestone=None, project='ipython/ipython'): if __name__ == '__main__': project = 'ipython/ipython' + + print("DEPRECATE: backport_pr.py is deprecated and is is now recommended" + "to install `ghpro` from PyPI.", file=sys.stderr) + args = list(sys.argv) if len(args) >= 2: if '/' in args[1]: diff --git a/tools/github_stats.py b/tools/github_stats.py index efe34a84699..a333dd25660 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -110,6 +110,10 @@ def report(issues, show_urls=False): #----------------------------------------------------------------------------- if __name__ == "__main__": + + print("DEPRECATE: backport_pr.py is deprecated and is is now recommended" + "to install `ghpro` from PyPI.", file=sys.stderr) + # deal with unicode if sys.version_info < (3,): sys.stdout = codecs.getwriter('utf8')(sys.stdout) From 25edc75e2b8cbed0e332b1215b22bc9313e311a0 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 18 Sep 2016 19:23:02 -0700 Subject: [PATCH 0058/1594] Document how to backport --- docs/source/coredev/index.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 571b3cd20cf..fec87c08612 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -17,6 +17,33 @@ For instruction on how to make a developer install see :ref:`devinstall`. release_process +Backporting Pull requests +------------------------- + +All pull requests should usually be made against ``master``, if a Pull Request +need to be backported to an earlier release; then it should be tagged with the +correct ``milestone``. We then use `ghpro ` +to automatically list and apply the PR on other branches. For example: + +.. code-block:: bash + + $ backport-pr todo --milestone 5.2 + [...snip..] + The following PRs have been backported + 9848 + 9851 + 9953 + 9955 + The following PRs should be backported: + 9417 + 9863 + 9925 + 9947 + + $ backport-pr apply 5.x 9947 + [...snip...] + + Old Documentation ================= From 1490d8de0f29cc5e31b59cc7cfca1268eca904e9 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 19 Sep 2016 11:21:00 +0100 Subject: [PATCH 0059/1594] Add whatsnew note on F2 to open editor I forgot to do this when I added the feature. --- docs/source/whatsnew/pr/f2-edit-input.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 docs/source/whatsnew/pr/f2-edit-input.rst diff --git a/docs/source/whatsnew/pr/f2-edit-input.rst b/docs/source/whatsnew/pr/f2-edit-input.rst new file mode 100644 index 00000000000..6416bba5ca0 --- /dev/null +++ b/docs/source/whatsnew/pr/f2-edit-input.rst @@ -0,0 +1,3 @@ +- You can now press F2 while typing at a terminal prompt to edit the contents + in your favourite terminal editor. Set the :envvar:`EDITOR` environment + variable to pick which editor is used. From 3e812afa6e1f917695b517fc077ae54e5dab6c79 Mon Sep 17 00:00:00 2001 From: mbyt Date: Mon, 19 Sep 2016 18:03:02 +0200 Subject: [PATCH 0060/1594] fixing typo in comment --- IPython/terminal/debugger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 1c9bf04aadd..29a8848ffa7 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -87,7 +87,7 @@ def set_trace(frame=None): if __name__ == '__main__': import pdb # IPython.core.debugger.Pdb.trace_dispatch shall not catch - # bdb.BdbQuit. When started through __main__ and an exeption + # bdb.BdbQuit. When started through __main__ and an exception # happend after hitting "c", this is needed in order to # be able to quit the debugging session (see #9950). old_trace_dispatch = pdb.Pdb.trace_dispatch From b817f5e219785654cb4cbda0a1bd9f81b5f717b8 Mon Sep 17 00:00:00 2001 From: mbyt Date: Mon, 19 Sep 2016 19:06:49 +0200 Subject: [PATCH 0061/1594] fixing another typo in comment --- IPython/terminal/debugger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 29a8848ffa7..e7bd135f008 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -88,7 +88,7 @@ def set_trace(frame=None): import pdb # IPython.core.debugger.Pdb.trace_dispatch shall not catch # bdb.BdbQuit. When started through __main__ and an exception - # happend after hitting "c", this is needed in order to + # happened after hitting "c", this is needed in order to # be able to quit the debugging session (see #9950). old_trace_dispatch = pdb.Pdb.trace_dispatch pdb.Pdb = TerminalPdb From 82fd2b341574766013866cffaa96c12b7c04e099 Mon Sep 17 00:00:00 2001 From: mbyt Date: Thu, 22 Sep 2016 21:19:14 +0200 Subject: [PATCH 0062/1594] restore sys.modules["__main__"] in the debugger needed to e.g. run standard unittests within the debugger see #9941 --- IPython/core/debugger.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 47bc92f350a..11f4b44a901 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -227,10 +227,14 @@ def __init__(self, color_scheme=None, completekey=None, self.shell = get_ipython() if self.shell is None: + save_main = sys.modules['__main__'] # No IPython instance running, we must create one from IPython.terminal.interactiveshell import \ TerminalInteractiveShell self.shell = TerminalInteractiveShell.instance() + # needed by any code which calls __import__("__main__") after + # the debugger was entered. See also #9941. + sys.modules['__main__'] = save_main if color_scheme is not None: warnings.warn( From 1c2eba4ca77d68c65c8bd108215373db70b8c476 Mon Sep 17 00:00:00 2001 From: Fermi paradox Date: Mon, 26 Sep 2016 13:21:42 +0300 Subject: [PATCH 0063/1594] Doc update. Reasoning behind PopupWidget removal. Short explanation of [why it was removed](https://gitter.im/jupyter/jupyter?at=57e7075c7270539a6d843a4e). --- docs/source/whatsnew/version3_widget_migration.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/whatsnew/version3_widget_migration.rst b/docs/source/whatsnew/version3_widget_migration.rst index 1014abea697..08856eea599 100644 --- a/docs/source/whatsnew/version3_widget_migration.rst +++ b/docs/source/whatsnew/version3_widget_migration.rst @@ -11,7 +11,8 @@ Upgrading Notebooks "Widget" suffix was removed from the end of the class name. i.e. ``ButtonWidget`` is now ``Button``. 3. ``ContainerWidget`` was renamed to ``Box``. -4. ``PopupWidget`` was removed from IPython. If you use the +4. ``PopupWidget`` was removed from IPython, because bootstrapjs was + problematic (creates global variables, etc.). If you use the ``PopupWidget``, try using a ``Box`` widget instead. If your notebook can't live without the popup functionality, subclass the ``Box`` widget (both in Python and JS) and use JQuery UI's ``draggable()`` From 4335860f8de8f9abdc0b418a932e0c3c4cd47d5f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 30 Sep 2016 10:24:52 -0700 Subject: [PATCH 0064/1594] 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 0065/1594] 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 0066/1594] 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 0067/1594] 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 0068/1594] 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 0069/1594] 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 0070/1594] 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 0071/1594] 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 0072/1594] 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 0073/1594] 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 0074/1594] 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 0075/1594] 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 0076/1594] 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 0077/1594] 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 0078/1594] 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 0079/1594] 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 0080/1594] 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 0081/1594] 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 0082/1594] 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 0083/1594] 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 0084/1594] 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 0085/1594] 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 0086/1594] 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 0087/1594] 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 0088/1594] 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 0089/1594] 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 0090/1594] 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 0091/1594] 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 = """