From b072562a471675a614af02a986cc882827ce9076 Mon Sep 17 00:00:00 2001 From: sukisuki Date: Mon, 13 Apr 2015 12:10:22 -0400 Subject: [PATCH 0001/4859] fixed base64 embedding for video on python3 python 2 compatible --- IPython/core/display.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index e353af215e3..d66bc866ef0 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -6,6 +6,7 @@ from __future__ import print_function +import base64 import json import mimetypes import os @@ -869,14 +870,14 @@ def _repr_html_(self): mimetype, encoding = mimetypes.guess_type(self.filename) video = open(self.filename, 'rb').read() - video_encoded = video.encode('base64') + video_encoded = base64.b64encode(video) else: video_encoded = self.data mimetype = self.mimetype output = """""".format(mimetype, video_encoded) + """.format(mimetype, video_encoded.decode('utf-8')) return output def reload(self): From 752eb4326a22565b36a36200981d90d738f0d599 Mon Sep 17 00:00:00 2001 From: sukisuki Date: Mon, 13 Apr 2015 12:43:02 -0400 Subject: [PATCH 0002/4859] Changed decode line: base64 can only produce ASCII characters --- IPython/core/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index d66bc866ef0..d69819f3eb6 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -877,7 +877,7 @@ def _repr_html_(self): output = """""".format(mimetype, video_encoded.decode('utf-8')) + """.format(mimetype, video_encoded.decode('ASCII')) return output def reload(self): From 0ca23b4f7d1943fa63e4bf2096307735afefc854 Mon Sep 17 00:00:00 2001 From: sukisuki Date: Wed, 15 Apr 2015 06:56:13 -0400 Subject: [PATCH 0003/4859] added basic test - ensure video embedding doesn't outright fail - check that the generated url is correct --- IPython/core/tests/test_display.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index fca6963f5d1..5d827e32829 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -2,6 +2,7 @@ # Distributed under the terms of the Modified BSD License. import json +import tempfile import os import warnings @@ -149,4 +150,12 @@ def test_json(): nt.assert_equal(len(w), 1) nt.assert_equal(j._repr_json_(), lis) - +def test_video_embedding(): + """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash""" + with tempfile.NamedTemporaryFile(suffix='.mp4') as f: + with open(f.name,'wb') as f: + f.write(b'abc') + + v = display.Video(f.name, embed=True) + html = v._repr_html_() + nt.assert_in('src="data:video/mp4;base64,YWJj"',html) From e97b7e68a3bb2f4871ff75b63bb9ef3923907173 Mon Sep 17 00:00:00 2001 From: jc Date: Wed, 24 Jun 2015 11:44:25 +0300 Subject: [PATCH 0004/4859] fix to autoreload for cases when module has no __name__ attribute --- IPython/extensions/autoreload.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/extensions/autoreload.py b/IPython/extensions/autoreload.py index 8459dc71f08..60d95725791 100644 --- a/IPython/extensions/autoreload.py +++ b/IPython/extensions/autoreload.py @@ -186,7 +186,7 @@ def filename_and_mtime(self, module): if not hasattr(module, '__file__') or module.__file__ is None: return None, None - if module.__name__ == '__main__': + if getattr(module, '__name__', None) == '__main__': # we cannot reload(__main__) return None, None From e3c0dab8a050d7e2190f18864f1de48fe5ee2a10 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 28 Sep 2015 19:46:59 +0200 Subject: [PATCH 0005/4859] fallback to in-memory if creating new history session fails --- IPython/core/history.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/IPython/core/history.py b/IPython/core/history.py index adae60dc2be..f63870397d8 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -513,12 +513,18 @@ def __init__(self, shell=None, config=None, **traits): self.save_flag = threading.Event() self.db_input_cache_lock = threading.Lock() self.db_output_cache_lock = threading.Lock() + + try: + self.new_session() + except OperationalError: + self.log.error("Failed to create history session in %s. History will not be saved.", + self.hist_file, exc_info=True) + self.hist_file = ':memory:' + if self.enabled and self.hist_file != ':memory:': self.save_thread = HistorySavingThread(self) self.save_thread.start() - self.new_session() - def _get_hist_file_name(self, profile=None): """Get default history file name based on the Shell's profile. From 38e5960aaaf0cfcff4b509fb3f1ac028807eb0d0 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 9 Oct 2015 15:09:47 +0200 Subject: [PATCH 0006/4859] Use in-memory history for sphinx directive --- IPython/sphinxext/ipython_directive.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index a52e9b5c13a..704420f68e3 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -135,16 +135,9 @@ import warnings import shutil -# To keep compatibility with various python versions -try: - from hashlib import md5 -except ImportError: - from md5 import md5 # Third-party -import sphinx from docutils.parsers.rst import directives -from docutils import nodes from sphinx.util.compat import Directive # Our own @@ -285,6 +278,7 @@ def __init__(self, exec_lines=None): # Create config object for IPython config = Config() + config.HistoryManager.hist_file = ':memory:' config.InteractiveShell.autocall = False config.InteractiveShell.autoindent = False config.InteractiveShell.colors = 'NoColor' From fd6e72da7a4dcf73083264d2596c78fa570ee38d Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 9 Oct 2015 15:20:56 +0200 Subject: [PATCH 0007/4859] save figures in the output directory by default, instead of the input directory --- IPython/sphinxext/ipython_directive.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index 704420f68e3..d6054490adf 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -850,14 +850,14 @@ def get_config_options(self): config = self.state.document.settings.env.config # get config variables to set figure output directory - confdir = self.state.document.settings.env.app.confdir + outdir = self.state.document.settings.env.app.outdir savefig_dir = config.ipython_savefig_dir source_dir = os.path.dirname(self.state.document.current_source) if savefig_dir is None: - savefig_dir = config.html_static_path + savefig_dir = config.html_static_path or '_static' if isinstance(savefig_dir, list): - savefig_dir = savefig_dir[0] # safe to assume only one path? - savefig_dir = os.path.join(confdir, savefig_dir) + savefig_dir = os.path.join(*savefig_dir) + savefig_dir = os.path.join(outdir, savefig_dir) # get regex and prompt stuff rgxin = config.ipython_rgxin From c962d136426ba24eeac9c78978b1d27bb3eb5350 Mon Sep 17 00:00:00 2001 From: Hoyt Koepke Date: Thu, 15 Oct 2015 14:19:08 -0700 Subject: [PATCH 0008/4859] BUGFIX: check for None moved earlier. If records is None, then format_records still tries to iterate over it, causing an exception. This PR moves the check for None earlier. --- IPython/core/ultratb.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 639635e2d34..41df70b4d03 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1026,10 +1026,11 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con head = self.prepare_header(etype, self.long_header) records = self.get_records(etb, number_of_lines_of_context, tb_offset) - frames = self.format_records(records) if records is None: return "" + frames = self.format_records(records) + formatted_exception = self.format_exception(etype, evalue) if records: filepath, lnum = records[-1][1:3] From f06a50447a8787d464e223428757aa6496ad8d64 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 11 Nov 2015 16:19:22 -0800 Subject: [PATCH 0009/4859] untest install-ext which is deprecated --- IPython/core/tests/{ => daft_extension}/daft_extension.py | 0 IPython/core/tests/daft_extension/setup.py | 5 +++++ IPython/core/tests/test_magic.py | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) rename IPython/core/tests/{ => daft_extension}/daft_extension.py (100%) create mode 100644 IPython/core/tests/daft_extension/setup.py diff --git a/IPython/core/tests/daft_extension.py b/IPython/core/tests/daft_extension/daft_extension.py similarity index 100% rename from IPython/core/tests/daft_extension.py rename to IPython/core/tests/daft_extension/daft_extension.py diff --git a/IPython/core/tests/daft_extension/setup.py b/IPython/core/tests/daft_extension/setup.py new file mode 100644 index 00000000000..ed00d79703f --- /dev/null +++ b/IPython/core/tests/daft_extension/setup.py @@ -0,0 +1,5 @@ +from distutils.core import setup +setup(name='daft_extension', + version='1.0', + py_modules=['daft_extension'], + ) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 9bbe3c36f4f..70777bf0631 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -611,8 +611,8 @@ def test_extension(): try: _ip.ipython_dir = tmpdir.name nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") - url = os.path.join(os.path.dirname(__file__), "daft_extension.py") - _ip.magic("install_ext %s" % url) + url = os.path.join(os.path.dirname(__file__), "daft_extension") + _ip.system("pip install %s" % url) _ip.user_ns.pop('arq', None) invalidate_caches() # Clear import caches _ip.magic("load_ext daft_extension") From d5a459d5bc63c7f6f07410e37f6ff4f6404df121 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 13 Nov 2015 10:51:08 +0100 Subject: [PATCH 0010/4859] override vformat instead of _vformat in our eval formatters avoids being caught out by changes in private API this needs to be backported in order to support Python 3.4.4 --- IPython/utils/text.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/IPython/utils/text.py b/IPython/utils/text.py index 07a6f1a614a..6766abba21f 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -540,9 +540,7 @@ class FullEvalFormatter(Formatter): """ # copied from Formatter._vformat with minor changes to allow eval # and replace the format_spec code with slicing - def _vformat(self, format_string, args, kwargs, used_args, recursion_depth): - if recursion_depth < 0: - raise ValueError('Max string recursion exceeded') + def vformat(self, format_string, args, kwargs): result = [] for literal_text, field_name, format_spec, conversion in \ self.parse(format_string): From 4b403b00259b855feb6676ed8dc7620d9d31e95c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20L=C3=A9one?= Date: Sun, 8 Nov 2015 19:09:43 +0100 Subject: [PATCH 0011/4859] Set litteral --- IPython/core/interactiveshell.py | 2 +- IPython/core/tests/test_completerlib.py | 12 ++++++------ IPython/core/tests/test_interactiveshell.py | 14 +++++++------- IPython/core/tests/test_profile.py | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 13b333e9bcf..91b7c9fc70b 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -3178,7 +3178,7 @@ def enable_pylab(self, gui=None, import_all=True, welcome_message=False): ns = {} import_pylab(ns, import_all) # warn about clobbered names - ignored = set(["__builtins__"]) + ignored = {"__builtins__"} both = set(ns).intersection(self.user_ns).difference(ignored) clobbered = [ name for name in both if self.user_ns[name] is not ns[name] ] self.user_ns.update(ns) diff --git a/IPython/core/tests/test_completerlib.py b/IPython/core/tests/test_completerlib.py index 494bdb22b62..9cc46097eaf 100644 --- a/IPython/core/tests/test_completerlib.py +++ b/IPython/core/tests/test_completerlib.py @@ -63,7 +63,7 @@ def test_2(self): event = MockEvent(u"%run aa") mockself = None match = set(magic_run_completer(mockself, event)) - self.assertEqual(match, set([u"aao.py"])) + self.assertEqual(match, {u"aao.py"}) def test_3(self): """Test magic_run_completer with unterminated " """ @@ -109,7 +109,7 @@ def test_1(self): event = MockEvent(u"%run a") mockself = None match = set(magic_run_completer(mockself, event)) - self.assertEqual(match, set([u"a.py", u"aaø.py"])) + self.assertEqual(match, {u"a.py", u"aaø.py"}) @onlyif_unicode_paths def test_2(self): @@ -118,7 +118,7 @@ def test_2(self): event = MockEvent(u"%run aa") mockself = None match = set(magic_run_completer(mockself, event)) - self.assertEqual(match, set([u"aaø.py"])) + self.assertEqual(match, {u"aaø.py"}) @onlyif_unicode_paths def test_3(self): @@ -126,14 +126,14 @@ def test_3(self): event = MockEvent(u'%run "a') mockself = None match = set(magic_run_completer(mockself, event)) - self.assertEqual(match, set([u"a.py", u"aaø.py"])) + self.assertEqual(match, {u"a.py", u"aaø.py"}) # module_completer: def test_import_invalid_module(): """Testing of issue https://github.com/ipython/ipython/issues/1107""" - invalid_module_names = set(['foo-bar', 'foo:bar', '10foo']) - valid_module_names = set(['foobar']) + invalid_module_names = {'foo-bar', 'foo:bar', '10foo'} + valid_module_names = {'foobar'} with TemporaryDirectory() as tmpdir: sys.path.insert( 0, tmpdir ) for name in invalid_module_names | valid_module_names: diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 2f433296c4b..ed2b53f6d0f 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -645,12 +645,12 @@ def f(x): with tt.AssertPrints("best of "): ip.run_line_magic("timeit", "-n1 f(1)") - self.assertEqual(called, set([-1])) + self.assertEqual(called, {-1}) called.clear() with tt.AssertPrints("best of "): ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)") - self.assertEqual(called, set([-2, -3])) + self.assertEqual(called, {-2, -3}) def test_time(self): called = [] @@ -718,12 +718,12 @@ def f(x): with tt.AssertPrints("best of "): ip.run_line_magic("timeit", "-n1 f(1)") - self.assertEqual(called, set([(1,)])) + self.assertEqual(called, {(1,)}) called.clear() with tt.AssertPrints("best of "): ip.run_cell_magic("timeit", "-n1 f(2)", "f(3)") - self.assertEqual(called, set([(2,), (3,)])) + self.assertEqual(called, {(2,), (3,)}) class ErrorTransformer(ast.NodeTransformer): """Throws an error when it sees a number.""" @@ -799,12 +799,12 @@ def test_user_variables(): ip.display_formatter.active_types = ip.display_formatter.format_types ip.user_ns['dummy'] = d = DummyRepr() - keys = set(['dummy', 'doesnotexist']) + keys = {'dummy', 'doesnotexist'} r = ip.user_expressions({ key:key for key in keys}) nt.assert_equal(keys, set(r.keys())) dummy = r['dummy'] - nt.assert_equal(set(['status', 'data', 'metadata']), set(dummy.keys())) + nt.assert_equal({'status', 'data', 'metadata'}, set(dummy.keys())) nt.assert_equal(dummy['status'], 'ok') data = dummy['data'] metadata = dummy['metadata'] @@ -832,7 +832,7 @@ def test_user_expression(): pprint.pprint(r) nt.assert_equal(set(r.keys()), set(query.keys())) a = r['a'] - nt.assert_equal(set(['status', 'data', 'metadata']), set(a.keys())) + nt.assert_equal({'status', 'data', 'metadata'}, set(a.keys())) nt.assert_equal(a['status'], 'ok') data = a['data'] metadata = a['metadata'] diff --git a/IPython/core/tests/test_profile.py b/IPython/core/tests/test_profile.py index b20aa0c4d19..4c938ed2d2f 100644 --- a/IPython/core/tests/test_profile.py +++ b/IPython/core/tests/test_profile.py @@ -144,7 +144,7 @@ def test_list_profiles_in(): break if dec.unicode_paths: nt.assert_true(found_unicode) - nt.assert_equal(set(profiles), set(['foo', 'hello'])) + nt.assert_equal(set(profiles), {'foo', 'hello'}) def test_list_bundled_profiles(): From 62850ab870c76969087fdca7a86629801a22d260 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 Nov 2015 22:21:05 -0800 Subject: [PATCH 0012/4859] Remove unused private method. Artifact of cell magics first implementation. Not used anymore. --- IPython/core/interactiveshell.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 13b333e9bcf..0f9f1d81878 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2773,13 +2773,6 @@ def safe_run_module(self, mod_name, where): self.showtraceback() warn('Unknown failure executing module: <%s>' % mod_name) - def _run_cached_cell_magic(self, magic_name, line): - """Special method to call a cell magic with the data stored in self. - """ - cell = self._current_cell_magic_body - self._current_cell_magic_body = None - return self.run_cell_magic(magic_name, line, cell) - def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=True): """Run a complete IPython cell. From 80b0ce1ea6d844ffa9ea9c4825171b8aa7f45001 Mon Sep 17 00:00:00 2001 From: Christopher Roach Date: Sat, 21 Nov 2015 18:32:09 -0800 Subject: [PATCH 0013/4859] Added a fix for issue #8871 --- IPython/core/pylabtools.py | 4 ++++ IPython/core/tests/test_pylabtools.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index fa6c6f9166d..4bf15cc1c8e 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -123,6 +123,10 @@ def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs): def retina_figure(fig, **kwargs): """format a figure as a pixel-doubled (retina) PNG""" pngdata = print_figure(fig, fmt='retina', **kwargs) + # Make sure that retina_figure acts just like print_figure and returns + # None when the figure is empty. + if pngdata is None: + return w, h = _pngxy(pngdata) metadata = dict(width=w//2, height=h//2) return pngdata, metadata diff --git a/IPython/core/tests/test_pylabtools.py b/IPython/core/tests/test_pylabtools.py index 67c45d2487f..aa9d16b90c9 100644 --- a/IPython/core/tests/test_pylabtools.py +++ b/IPython/core/tests/test_pylabtools.py @@ -66,6 +66,11 @@ def test_figure_to_jpeg(): assert jpeg.startswith(_JPEG) def test_retina_figure(): + # simple empty-figure test + fig = plt.figure() + nt.assert_equal(pt.retina_figure(fig), None) + plt.close('all') + fig = plt.figure() ax = fig.add_subplot(1,1,1) ax.plot([1,2,3]) From 785cac2e160d8ae24e696d4bea20ff41e34204ba Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 12 Oct 2015 09:52:35 -0700 Subject: [PATCH 0014/4859] update install instruction --- docs/source/install/kernel_install.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index a5bfea67645..9e04590f882 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -11,10 +11,15 @@ environments) as a kernel for Jupyter by following these steps: and ipykernel is installed * run once ``ipython kernel install --user``, or ``python -m ipykernel install --user`` to ensure a specific Python installation is used. +* See `ipython kernel install --help` for the list of installation options like + naming the kernel, or non default install location. +* The IPython kernel for Jupyter is provided by the `ipykernel` python package, + see there if you need more flexibility for installation. -The last command installs a :ref:`kernel spec ` file for the current python installation. Kernel spec files are JSON files, which can be viewed and changed with a -normal text editor. +The last command installs a :ref:`kernel spec ` file +for the current python installation. Kernel spec files are JSON files, which +can be viewed and changed with a normal text editor. For example: @@ -30,6 +35,10 @@ or ~/envs/kernel-environment/python -m ipykernel install --user +.. note :: + + The command `ipython kernelspec` is deprecated and will be removed in future versions. + .. _multiple_kernel_install: From e5b01e24467c52e53b242abd136213c81f024bb2 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 22 Nov 2015 21:55:49 +0100 Subject: [PATCH 0015/4859] take comments into account --- docs/source/install/kernel_install.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index 9e04590f882..b4614e6ac87 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -14,13 +14,10 @@ environments) as a kernel for Jupyter by following these steps: * See `ipython kernel install --help` for the list of installation options like naming the kernel, or non default install location. * The IPython kernel for Jupyter is provided by the `ipykernel` python package, - see there if you need more flexibility for installation. + see `ipykernel documentation `_ if you + need more flexibility for installation. -The last command installs a :ref:`kernel spec ` file -for the current python installation. Kernel spec files are JSON files, which -can be viewed and changed with a normal text editor. - For example: .. sourcecode:: bash @@ -35,6 +32,11 @@ or ~/envs/kernel-environment/python -m ipykernel install --user +The last command installs a :ref:`kernel spec ` file +for the current python installation. Kernel spec files are JSON files, which +can be viewed and changed with a normal text editor. + + .. note :: The command `ipython kernelspec` is deprecated and will be removed in future versions. From b96b6b9e54fb27a1d18474f1801b407e8d60857f Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 24 Nov 2015 11:55:08 +0100 Subject: [PATCH 0016/4859] fix explicit Image format override only detect format if it's not been given --- IPython/core/display.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 2934beef1d9..32889500e0d 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -637,7 +637,7 @@ class Image(DisplayObject): _FMT_PNG = u'png' _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG] - def __init__(self, data=None, url=None, filename=None, format=u'png', + def __init__(self, data=None, url=None, filename=None, format=None, embed=None, width=None, height=None, retina=False, unconfined=False, metadata=None): """Create a PNG/JPEG image object given raw data. @@ -714,17 +714,27 @@ def __init__(self, data=None, url=None, filename=None, format=u'png', else: ext = None - if ext is not None: - format = ext.lower() - if ext == u'jpg' or ext == u'jpeg': - format = self._FMT_JPEG - if ext == u'png': - format = self._FMT_PNG - elif isinstance(data, bytes) and format == 'png': - # infer image type from image data header, - # only if format might not have been specified. - if data[:2] == _JPEG: - format = 'jpeg' + if format is None: + if ext is not None: + if ext == u'jpg' or ext == u'jpeg': + format = self._FMT_JPEG + if ext == u'png': + format = self._FMT_PNG + else: + format = ext.lower() + elif isinstance(data, bytes): + # infer image type from image data header, + # only if format has not been specified. + if data[:2] == _JPEG: + format = self._FMT_JPEG + + if format.lower() == 'jpg': + # jpg->jpeg + format = self._FMT_JPEG + + # failed to detect format, default png + if format is None: + format = 'png' self.format = unicode_type(format).lower() self.embed = embed if embed is not None else (url is None) From 1c75e559c3f320b4ad20f3b7cbc50a0d291f2dbe Mon Sep 17 00:00:00 2001 From: Tayfun Sen Date: Tue, 24 Nov 2015 21:45:18 +0000 Subject: [PATCH 0017/4859] Fix color schemes in Linux Object information found by prefixing object with a question mark (like int?) was printing garbled characters. git-bisect found 2b1c969628871300a4779963e8776b5a8e966f34 to be the offending commit. A refactoring in that commit forgot to add one color and also used the wrong object (it used InputTermColors instead of TermColors). --- IPython/utils/PyColorize.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index 0267cfeb3bb..e42c58d8c6d 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -88,11 +88,12 @@ 'in_prompt' : InputTermColors.NoColor, # Input prompt 'in_number' : InputTermColors.NoColor, # Input prompt number 'in_prompt2' : InputTermColors.NoColor, # Continuation prompt + 'in_normal' : InputTermColors.NoColor, # color off (usu. Colors.Normal) - 'out_prompt' : InputTermColors.NoColor, # Output prompt - 'out_number' : InputTermColors.NoColor, # Output prompt number + 'out_prompt' : Colors.NoColor, # Output prompt + 'out_number' : Colors.NoColor, # Output prompt number - 'normal' : InputTermColors.NoColor # color off (usu. Colors.Normal) + 'normal' : Colors.NoColor # color off (usu. Colors.Normal) } ) LinuxColors = ColorScheme( @@ -111,11 +112,12 @@ 'in_prompt' : InputTermColors.Green, 'in_number' : InputTermColors.LightGreen, 'in_prompt2' : InputTermColors.Green, + 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal) - 'out_prompt' : InputTermColors.Red, - 'out_number' : InputTermColors.LightRed, + 'out_prompt' : Colors.Red, + 'out_number' : Colors.LightRed, - 'normal' : InputTermColors.Normal # color off (usu. Colors.Normal) + 'normal' : Colors.Normal # color off (usu. Colors.Normal) } ) LightBGColors = ColorScheme( @@ -134,11 +136,12 @@ 'in_prompt' : InputTermColors.Blue, 'in_number' : InputTermColors.LightBlue, 'in_prompt2' : InputTermColors.Blue, + 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal) - 'out_prompt' : InputTermColors.Red, - 'out_number' : InputTermColors.LightRed, + 'out_prompt' : Colors.Red, + 'out_number' : Colors.LightRed, - 'normal' : InputTermColors.Normal # color off (usu. Colors.Normal) + 'normal' : Colors.Normal # color off (usu. Colors.Normal) } ) # Build table of color schemes (needed by the parser) From e028189779d9d67c2545976321727a1407bc7a97 Mon Sep 17 00:00:00 2001 From: Tayfun Sen Date: Tue, 24 Nov 2015 22:40:25 +0000 Subject: [PATCH 0018/4859] Fixes tests by using in_normal colors for input. --- IPython/core/prompts.py | 58 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index eec8ed6a59a..ffde2a0e2f5 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -55,17 +55,17 @@ def __init__(self, func, *args, **kwargs): self.func = func self.args = args self.kwargs = kwargs - + def __call__(self, **kwargs): self.kwargs.update(kwargs) return self.func(*self.args, **self.kwargs) - + def __str__(self): return str(self()) - + def __unicode__(self): return py3compat.unicode_type(self()) - + def __format__(self, format_spec): return format(self(), format_spec) @@ -114,7 +114,7 @@ def multiple_replace(dict, text): HOSTNAME = py3compat.str_to_unicode(socket.gethostname()) HOSTNAME_SHORT = HOSTNAME.split(".")[0] -# IronPython doesn't currently have os.getuid() even if +# IronPython doesn't currently have os.getuid() even if # os.name == 'posix'; 2/8/2014 ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$" @@ -254,7 +254,7 @@ def get_value(self, key, args, kwargs): class PromptManager(Configurable): """This is the primary interface for producing IPython's prompts.""" shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) - + color_scheme_table = Instance(coloransi.ColorSchemeTable, allow_none=True) color_scheme = Unicode('Linux', config=True) def _color_scheme_changed(self, name, new_value): @@ -262,7 +262,7 @@ def _color_scheme_changed(self, name, new_value): for pname in ['in', 'in2', 'out', 'rewrite']: # We need to recalculate the number of invisible characters self.update_prompt(pname) - + lazy_evaluate_fields = Dict(help=""" This maps field names used in the prompt templates to functions which will be called when the prompt is rendered. This allows us to include @@ -270,39 +270,39 @@ def _color_scheme_changed(self, name, new_value): if they are used in the prompt. """) def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() - + in_template = Unicode('In [\\#]: ', config=True, help="Input prompt. '\\#' will be transformed to the prompt number") in2_template = Unicode(' .\\D.: ', config=True, help="Continuation prompt.") out_template = Unicode('Out[\\#]: ', config=True, help="Output prompt. '\\#' will be transformed to the prompt number") - + justify = Bool(True, config=True, help=""" If True (default), each prompt will be right-aligned with the preceding one. """) - + # We actually store the expanded templates here: templates = Dict() - + # The number of characters in the last prompt rendered, not including # colour characters. width = Int() txtwidth = Int() # Not including right-justification - + # The number of characters in each prompt which don't contribute to width invisible_chars = Dict() def _invisible_chars_default(self): return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0} - + def __init__(self, shell, **kwargs): super(PromptManager, self).__init__(shell=shell, **kwargs) - + # Prepare colour scheme table self.color_scheme_table = coloransi.ColorSchemeTable([NoColor, LinuxColors, LightBGColors], self.color_scheme) - + self._formatter = UserNSFormatter(shell) # Prepare templates & numbers of invisible characters self.update_prompt('in', self.in_template) @@ -311,13 +311,13 @@ def __init__(self, shell, **kwargs): self.update_prompt('rewrite') self.on_trait_change(self._update_prompt_trait, ['in_template', 'in2_template', 'out_template']) - + def update_prompt(self, name, new_template=None): """This is called when a prompt template is updated. It processes abbreviations used in the prompt template (like \#) and calculates how many invisible characters (ANSI colour escapes) the resulting prompt contains. - + It is also called for each prompt on changing the colour scheme. In both cases, traitlets should take care of calling this automatically. """ @@ -327,17 +327,17 @@ def update_prompt(self, name, new_template=None): # prompt, to calculate the width for lining up subsequent prompts. invis_chars = _invisible_characters(self._render(name, color=True)) self.invisible_chars[name] = invis_chars - + def _update_prompt_trait(self, traitname, new_template): name = traitname[:-9] # Cut off '_template' self.update_prompt(name, new_template) - + def _render(self, name, color=True, **kwargs): """Render but don't justify, or update the width or txtwidth attributes. """ if name == 'rewrite': return self._render_rewrite(color=color) - + if color: scheme = self.color_scheme_table.active_colors if name=='out': @@ -347,14 +347,14 @@ def _render(self, name, color=True, **kwargs): else: colors = color_lists['inp'] colors.number, colors.prompt, colors.normal = \ - scheme.in_number, scheme.in_prompt, scheme.normal + scheme.in_number, scheme.in_prompt, scheme.in_normal if name=='in2': colors.prompt = scheme.in_prompt2 else: # No color colors = color_lists['nocolor'] colors.number, colors.prompt, colors.normal = '', '', '' - + count = self.shell.execution_count # Shorthand # Build the dictionary to be passed to string formatting fmtargs = dict(color=colors, count=count, @@ -362,13 +362,13 @@ def _render(self, name, color=True, **kwargs): width=self.width, txtwidth=self.txtwidth) fmtargs.update(self.lazy_evaluate_fields) fmtargs.update(kwargs) - + # Prepare the prompt prompt = colors.prompt + self.templates[name] + colors.normal - + # Fill in required fields return self._formatter.format(prompt, **fmtargs) - + def _render_rewrite(self, color=True): """Render the ---> rewrite prompt.""" if color: @@ -380,11 +380,11 @@ def _render_rewrite(self, color=True): color_prompt, color_normal = '', '' return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal - + def render(self, name, color=True, just=None, **kwargs): """ Render the selected prompt. - + Parameters ---------- name : str @@ -398,13 +398,13 @@ def render(self, name, color=True, just=None, **kwargs): Additional arguments will be passed to the string formatting operation, so they can override the values that would otherwise fill in the template. - + Returns ------- A string containing the rendered prompt. """ res = self._render(name, color=color, **kwargs) - + # Handle justification of prompt invis_chars = self.invisible_chars[name] if color else 0 self.txtwidth = _lenlastline(res) - invis_chars From dc1d1d4e8168715d4948b4e47ad4148eb7884f92 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 27 Nov 2015 00:05:44 +0100 Subject: [PATCH 0019/4859] remove unregister trait-change callback in ExtensionManager.__del__ Due to reference cycles, this can never be called at a time when it would matter, but seems to cause weird crashes sometimes during interpreter teardown on Python 3.5 with traitlets 4.1. --- IPython/core/extensions.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/IPython/core/extensions.py b/IPython/core/extensions.py index f31dd8326fa..cd1dd594a45 100644 --- a/IPython/core/extensions.py +++ b/IPython/core/extensions.py @@ -59,11 +59,6 @@ def __init__(self, shell=None, **kwargs): ) self.loaded = set() - def __del__(self): - self.shell.on_trait_change( - self._on_ipython_dir_changed, 'ipython_dir', remove=True - ) - @property def ipython_extension_dir(self): return os.path.join(self.shell.ipython_dir, u'extensions') From f7c53fd6f64a703e170a6f80315d4f5492ed5692 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 29 Nov 2015 18:09:29 +0100 Subject: [PATCH 0020/4859] Actually warn that `ipython ` is deprecated. remove example, and add a 5 sec wait to have people actually read the warning message. --- IPython/core/application.py | 12 ++++++++++- IPython/terminal/ipapp.py | 42 +++++++++++++++---------------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 3a236769994..78459ea1e83 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -185,7 +185,7 @@ def __init__(self, **kwargs): super(BaseIPythonApplication, self).__init__(**kwargs) # ensure current working directory exists try: - directory = py3compat.getcwd() + py3compat.getcwd() except: # exit if cwd doesn't exist self.log.error("Current working directory doesn't exist.") @@ -195,6 +195,16 @@ def __init__(self, **kwargs): # Various stages of Application creation #------------------------------------------------------------------------- + def initialize_subcommand(self, subc, argv=None): + if subc in self.deprecated_subcommands: + import time + self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " + "in future versions.".format(sub=subc)) + self.log.warning("You likely want to use `jupyter {sub}`... continue " + "in 5 sec".format(sub=subc)) + time.sleep(5) + return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv) + def init_crash_handler(self): """Create a crash handler, typically setting sys.excepthook to it.""" self.crash_handler = self.crash_handler_class(self) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index 3353ba2b845..eb1bd0950d5 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -50,22 +50,11 @@ ipython --log-level=DEBUG # set logging to DEBUG ipython --profile=foo # start with profile foo -ipython qtconsole # start the qtconsole GUI application -ipython help qtconsole # show the help for the qtconsole subcmd - -ipython console # start the terminal-based console application -ipython help console # show the help for the console subcmd - -ipython notebook # start the IPython notebook -ipython help notebook # show the help for the notebook subcmd - ipython profile create foo # create profile foo w/ default config files ipython help profile # show the help for the profile subcmd ipython locate # print the path to the IPython directory ipython locate profile foo # print the path to the directory for profile `foo` - -ipython nbconvert # convert notebooks to/from other formats """ #----------------------------------------------------------------------------- @@ -209,28 +198,16 @@ def _classes_default(self): StoreMagics, ] - subcommands = dict( + deprecated_subcommands = dict( qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp', """DEPRECATD: Launch the Jupyter Qt Console.""" ), notebook=('notebook.notebookapp.NotebookApp', """DEPRECATED: Launch the Jupyter HTML Notebook Server.""" ), - profile = ("IPython.core.profileapp.ProfileApp", - "Create and manage IPython profiles." - ), - kernel = ("ipykernel.kernelapp.IPKernelApp", - "Start a kernel without an attached frontend." - ), console=('jupyter_console.app.ZMQTerminalIPythonApp', """DEPRECATED: Launch the Jupyter terminal-based Console.""" ), - locate=('IPython.terminal.ipapp.LocateIPythonApp', - LocateIPythonApp.description - ), - history=('IPython.core.historyapp.HistoryApp', - "Manage the IPython history database." - ), nbconvert=('nbconvert.nbconvertapp.NbConvertApp', "DEPRECATED: Convert notebooks to/from other formats." ), @@ -241,10 +218,25 @@ def _classes_default(self): "DEPRECATED: Manage Jupyter kernel specifications." ), ) - subcommands['install-nbextension'] = ( + subcommands = dict( + profile = ("IPython.core.profileapp.ProfileApp", + "Create and manage IPython profiles." + ), + kernel = ("ipykernel.kernelapp.IPKernelApp", + "Start a kernel without an attached frontend." + ), + locate=('IPython.terminal.ipapp.LocateIPythonApp', + LocateIPythonApp.description + ), + history=('IPython.core.historyapp.HistoryApp', + "Manage the IPython history database." + ), + ) + deprecated_subcommands['install-nbextension'] = ( "notebook.nbextensions.InstallNBExtensionApp", "DEPRECATED: Install Jupyter notebook extension files" ) + subcommands.update(deprecated_subcommands) # *do* autocreate requested profile, but don't create the config file. auto_create=Bool(True) From d874b00892e6541f0dc280969d96fefce56dd02d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 29 Nov 2015 18:19:31 +0100 Subject: [PATCH 0021/4859] Use sys.executable --- IPython/core/tests/test_magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 70777bf0631..df9cffdced2 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -612,7 +612,7 @@ def test_extension(): _ip.ipython_dir = tmpdir.name nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") url = os.path.join(os.path.dirname(__file__), "daft_extension") - _ip.system("pip install %s" % url) + _ip.system("%s -m pip install %s" % (sys.executable, url)) _ip.user_ns.pop('arq', None) invalidate_caches() # Clear import caches _ip.magic("load_ext daft_extension") From 8179581687444018e6aad211eef9cf9882d8acf1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 29 Nov 2015 18:19:52 +0100 Subject: [PATCH 0022/4859] Remove unused imports --- IPython/core/tests/test_magic.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index df9cffdced2..c4d15e9656d 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -9,7 +9,7 @@ import os import sys import warnings -from unittest import TestCase, skipIf +from unittest import TestCase try: from importlib import invalidate_caches # Required from Python 3.3 @@ -23,9 +23,8 @@ def invalidate_caches(): from IPython.core import magic from IPython.core.error import UsageError from IPython.core.magic import (Magics, magics_class, line_magic, - cell_magic, line_cell_magic, - register_line_magic, register_cell_magic, - register_line_cell_magic) + cell_magic, + register_line_magic, register_cell_magic) from IPython.core.magics import execution, script, code from IPython.testing import decorators as dec from IPython.testing import tools as tt From f72cfeee148294c75365bddb08b7f6d52eae2919 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 1 Dec 2015 10:15:00 +0100 Subject: [PATCH 0023/4859] don't install test extension which may require sudo and will pollute the system, causing subsequent runs to always fail. Instead, make the module installable by putting it on sys.path. --- IPython/core/tests/daft_extension/setup.py | 5 ----- IPython/core/tests/test_magic.py | 12 ++++-------- setupbase.py | 2 +- 3 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 IPython/core/tests/daft_extension/setup.py diff --git a/IPython/core/tests/daft_extension/setup.py b/IPython/core/tests/daft_extension/setup.py deleted file mode 100644 index ed00d79703f..00000000000 --- a/IPython/core/tests/daft_extension/setup.py +++ /dev/null @@ -1,5 +0,0 @@ -from distutils.core import setup -setup(name='daft_extension', - version='1.0', - py_modules=['daft_extension'], - ) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index c4d15e9656d..420895bc849 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -605,13 +605,10 @@ def test_prun_quotes(): nt.assert_equal(_ip.user_ns['x'], '\t') def test_extension(): - tmpdir = TemporaryDirectory() - orig_ipython_dir = _ip.ipython_dir + nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") + daft_path = os.path.join(os.path.dirname(__file__), "daft_extension") + sys.path.insert(0, daft_path) try: - _ip.ipython_dir = tmpdir.name - nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") - url = os.path.join(os.path.dirname(__file__), "daft_extension") - _ip.system("%s -m pip install %s" % (sys.executable, url)) _ip.user_ns.pop('arq', None) invalidate_caches() # Clear import caches _ip.magic("load_ext daft_extension") @@ -619,8 +616,7 @@ def test_extension(): _ip.magic("unload_ext daft_extension") assert 'arq' not in _ip.user_ns finally: - _ip.ipython_dir = orig_ipython_dir - tmpdir.cleanup() + sys.path.remove(daft_path) @dec.skip_without('nbformat') diff --git a/setupbase.py b/setupbase.py index 6ee34cf4fe6..68b51b2ea2f 100644 --- a/setupbase.py +++ b/setupbase.py @@ -126,7 +126,7 @@ def find_package_data(): package_data = { 'IPython.core' : ['profile/README*'], - 'IPython.core.tests' : ['*.png', '*.jpg'], + 'IPython.core.tests' : ['*.png', '*.jpg', 'daft_extension/*.py'], 'IPython.lib.tests' : ['*.wav'], 'IPython.testing.plugin' : ['*.txt'], } From 51ca6ff8b21d12814528e4725a984c1179407c30 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 5 Dec 2015 15:10:34 +0100 Subject: [PATCH 0024/4859] Catch keyboard interrupt and quit --- IPython/core/application.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 78459ea1e83..bf2ab7ef3fd 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -201,8 +201,11 @@ def initialize_subcommand(self, subc, argv=None): self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " "in future versions.".format(sub=subc)) self.log.warning("You likely want to use `jupyter {sub}`... continue " - "in 5 sec".format(sub=subc)) - time.sleep(5) + "in 5 sec. Press Ctrl-C to quit now.".format(sub=subc)) + try: + time.sleep(5) + except KeyboardInterrupt: + sys.exit(1) return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv) def init_crash_handler(self): From 5f82378290041d392e953e2d45c387b0d1b97f9a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 14 Dec 2015 13:43:48 +0000 Subject: [PATCH 0025/4859] Move most readline code from InteractiveShell to terminal subclass This is the first stage of my effort to use prompt_toolkit for the terminal interface. My plan is to create a new subclass of InteractiveShell which deals with the terminal using prompt_toolkit instead of readline. To facilitate this, I am first trying to separate as much of the readline code as possible out of InteractiveShell to the TerminalInteractiveShell subclass (I don't intend the new subclass to inherit from TIS). I haven't moved any of the config options relating to readline yet, because moving them will break some people's existing config files. But if we're switching to prompt_toolkit by default, readline related config is going to be broken anyway. --- IPython/core/interactiveshell.py | 188 +----------------------- IPython/terminal/interactiveshell.py | 211 ++++++++++++++++++++++++--- IPython/utils/contexts.py | 25 ++-- 3 files changed, 205 insertions(+), 219 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3602a790cd5..ea583900ce3 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -62,6 +62,7 @@ from IPython.utils import io from IPython.utils import py3compat from IPython.utils import openpy +from IPython.utils.contexts import NoOpContext from IPython.utils.decorators import undoc from IPython.utils.io import ask_yes_no from IPython.utils.ipstruct import Struct @@ -109,11 +110,6 @@ def softspace(file, newvalue): @undoc def no_op(*a, **kw): pass -@undoc -class NoOpContext(object): - def __enter__(self): pass - def __exit__(self, type, value, traceback): pass -no_op_context = NoOpContext() class SpaceInInput(Exception): pass @@ -142,52 +138,6 @@ def validate(self, obj, value): return super(SeparateUnicode, self).validate(obj, value) -class ReadlineNoRecord(object): - """Context manager to execute some code, then reload readline history - so that interactive input to the code doesn't appear when pressing up.""" - def __init__(self, shell): - self.shell = shell - self._nested_level = 0 - - def __enter__(self): - if self._nested_level == 0: - try: - self.orig_length = self.current_length() - self.readline_tail = self.get_readline_tail() - except (AttributeError, IndexError): # Can fail with pyreadline - self.orig_length, self.readline_tail = 999999, [] - self._nested_level += 1 - - def __exit__(self, type, value, traceback): - self._nested_level -= 1 - if self._nested_level == 0: - # Try clipping the end if it's got longer - try: - e = self.current_length() - self.orig_length - if e > 0: - for _ in range(e): - self.shell.readline.remove_history_item(self.orig_length) - - # If it still doesn't match, just reload readline history. - if self.current_length() != self.orig_length \ - or self.get_readline_tail() != self.readline_tail: - self.shell.refill_readline_hist() - except (AttributeError, IndexError): - pass - # Returning False will cause exceptions to propagate - return False - - def current_length(self): - return self.shell.readline.get_current_history_length() - - def get_readline_tail(self, n=10): - """Get the last n items in readline history.""" - end = self.shell.readline.get_current_history_length() + 1 - start = max(end-n, 1) - ghi = self.shell.readline.get_history_item - return [ghi(x) for x in range(start, end)] - - @undoc class DummyMod(object): """A dummy module used for IPython's interactive module when @@ -1934,120 +1884,17 @@ def showindentationerror(self): #------------------------------------------------------------------------- def init_readline(self): - """Command history completion/saving/reloading.""" - - if self.readline_use: - import IPython.utils.rlineimpl as readline - - self.rl_next_input = None - self.rl_do_indent = False - - if not self.readline_use or not readline.have_readline: - self.has_readline = False - self.readline = None - # Set a number of methods that depend on readline to be no-op - self.readline_no_record = no_op_context - self.set_readline_completer = no_op - self.set_custom_completer = no_op - if self.readline_use: - warn('Readline services not available or not loaded.') - else: - self.has_readline = True - self.readline = readline - sys.modules['readline'] = readline - - # Platform-specific configuration - if os.name == 'nt': - # FIXME - check with Frederick to see if we can harmonize - # naming conventions with pyreadline to avoid this - # platform-dependent check - self.readline_startup_hook = readline.set_pre_input_hook - else: - self.readline_startup_hook = readline.set_startup_hook - - # Readline config order: - # - IPython config (default value) - # - custom inputrc - # - IPython config (user customized) - - # load IPython config before inputrc if default - # skip if libedit because parse_and_bind syntax is different - if not self._custom_readline_config and not readline.uses_libedit: - for rlcommand in self.readline_parse_and_bind: - readline.parse_and_bind(rlcommand) - - # Load user's initrc file (readline config) - # Or if libedit is used, load editrc. - inputrc_name = os.environ.get('INPUTRC') - if inputrc_name is None: - inputrc_name = '.inputrc' - if readline.uses_libedit: - inputrc_name = '.editrc' - inputrc_name = os.path.join(self.home_dir, inputrc_name) - if os.path.isfile(inputrc_name): - try: - readline.read_init_file(inputrc_name) - except: - warn('Problems reading readline initialization file <%s>' - % inputrc_name) - - # load IPython config after inputrc if user has customized - if self._custom_readline_config: - for rlcommand in self.readline_parse_and_bind: - readline.parse_and_bind(rlcommand) - - # Remove some chars from the delimiters list. If we encounter - # unicode chars, discard them. - delims = readline.get_completer_delims() - if not py3compat.PY3: - delims = delims.encode("ascii", "ignore") - for d in self.readline_remove_delims: - delims = delims.replace(d, "") - delims = delims.replace(ESC_MAGIC, '') - readline.set_completer_delims(delims) - # Store these so we can restore them if something like rpy2 modifies - # them. - self.readline_delims = delims - # otherwise we end up with a monster history after a while: - readline.set_history_length(self.history_length) - - self.refill_readline_hist() - self.readline_no_record = ReadlineNoRecord(self) - - # Configure auto-indent for all platforms - self.set_autoindent(self.autoindent) - - def refill_readline_hist(self): - # Load the last 1000 lines from history - self.readline.clear_history() - stdin_encoding = sys.stdin.encoding or "utf-8" - last_cell = u"" - for _, _, cell in self.history_manager.get_tail(self.history_load_length, - include_latest=True): - # Ignore blank lines and consecutive duplicates - cell = cell.rstrip() - if cell and (cell != last_cell): - try: - if self.multiline_history: - self.readline.add_history(py3compat.unicode_to_str(cell, - stdin_encoding)) - else: - for line in cell.splitlines(): - self.readline.add_history(py3compat.unicode_to_str(line, - stdin_encoding)) - last_cell = cell - - except TypeError: - # The history DB can get corrupted so it returns strings - # containing null bytes, which readline objects to. - continue + """Moved to terminal subclass, here only to simplify the init logic.""" + self.readline = None + # Set a number of methods that depend on readline to be no-op + self.readline_no_record = NoOpContext() + self.set_readline_completer = no_op + self.set_custom_completer = no_op @skip_doctest def set_next_input(self, s, replace=False): """ Sets the 'default' input string for the next command line. - Requires readline. - Example:: In [1]: _ip.set_next_input("Hello Word") @@ -2055,18 +1902,6 @@ def set_next_input(self, s, replace=False): """ self.rl_next_input = py3compat.cast_bytes_py2(s) - # Maybe move this to the terminal subclass? - def pre_readline(self): - """readline hook to be used at the start of each line. - - Currently it handles auto-indent only.""" - - if self.rl_do_indent: - self.readline.insert_text(self._indent_current_str()) - if self.rl_next_input is not None: - self.readline.insert_text(self.rl_next_input) - self.rl_next_input = None - def _indent_current_str(self): """return the current level of indentation as a string""" return self.input_splitter.indent_spaces * ' ' @@ -2107,11 +1942,6 @@ def init_completer(self): self.set_hook('complete_command', cd_completer, str_key = '%cd') self.set_hook('complete_command', reset_completer, str_key = '%reset') - # Only configure readline if we truly are using readline. IPython can - # do tab-completion over the network, in GUIs, etc, where readline - # itself may be absent - if self.has_readline: - self.set_readline_completer() def complete(self, text, line=None, cursor_pos=None): """Return the completed text and a list of completions. @@ -2167,10 +1997,6 @@ def set_custom_completer(self, completer, pos=0): newcomp = types.MethodType(completer,self.Completer) self.Completer.matchers.insert(pos,newcomp) - def set_readline_completer(self): - """Reset readline's completer to be our own.""" - self.readline.set_completer(self.Completer.rlcomplete) - def set_completer_frame(self, frame=None): """Set the frame of the completer.""" if frame: diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 326bc864253..226b4b85187 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -1,18 +1,9 @@ # -*- coding: utf-8 -*- """Subclass of InteractiveShell for terminal based frontends.""" -#----------------------------------------------------------------------------- -# Copyright (C) 2001 Janko Hauser -# Copyright (C) 2001-2007 Fernando Perez. -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + from __future__ import print_function import bdb @@ -21,10 +12,12 @@ from IPython.core.error import TryNext, UsageError from IPython.core.usage import interactive_usage -from IPython.core.inputsplitter import IPythonInputSplitter +from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC from IPython.core.magic import Magics, magics_class, line_magic from IPython.lib.clipboard import ClipboardEmpty +from IPython.utils.contexts import NoOpContext +from IPython.utils.decorators import undoc from IPython.utils.encoding import get_stream_enc from IPython.utils import py3compat from IPython.utils.terminal import toggle_set_term_title, set_term_title @@ -33,9 +26,6 @@ from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes from traitlets import Integer, CBool, Unicode -#----------------------------------------------------------------------------- -# Utilities -#----------------------------------------------------------------------------- def get_default_editor(): try: @@ -74,10 +64,55 @@ def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False): print('') return +@undoc +def no_op(*a, **kw): pass + + +class ReadlineNoRecord(object): + """Context manager to execute some code, then reload readline history + so that interactive input to the code doesn't appear when pressing up.""" + def __init__(self, shell): + self.shell = shell + self._nested_level = 0 + + def __enter__(self): + if self._nested_level == 0: + try: + self.orig_length = self.current_length() + self.readline_tail = self.get_readline_tail() + except (AttributeError, IndexError): # Can fail with pyreadline + self.orig_length, self.readline_tail = 999999, [] + self._nested_level += 1 + + def __exit__(self, type, value, traceback): + self._nested_level -= 1 + if self._nested_level == 0: + # Try clipping the end if it's got longer + try: + e = self.current_length() - self.orig_length + if e > 0: + for _ in range(e): + self.shell.readline.remove_history_item(self.orig_length) + + # If it still doesn't match, just reload readline history. + if self.current_length() != self.orig_length \ + or self.get_readline_tail() != self.readline_tail: + self.shell.refill_readline_hist() + except (AttributeError, IndexError): + pass + # Returning False will cause exceptions to propagate + return False + + def current_length(self): + return self.shell.readline.get_current_history_length() + + def get_readline_tail(self, n=10): + """Get the last n items in readline history.""" + end = self.shell.readline.get_current_history_length() + 1 + start = max(end-n, 1) + ghi = self.shell.readline.get_history_item + return [ghi(x) for x in range(start, end)] -#------------------------------------------------------------------------ -# Terminal-specific magics -#------------------------------------------------------------------------ @magics_class class TerminalMagics(Magics): @@ -248,9 +283,6 @@ def cls(self, s): """ os.system("cls") -#----------------------------------------------------------------------------- -# Main class -#----------------------------------------------------------------------------- class TerminalInteractiveShell(InteractiveShell): @@ -319,6 +351,141 @@ def init_display_formatter(self): # terminal only supports plaintext self.display_formatter.active_types = ['text/plain'] + #------------------------------------------------------------------------- + # Things related to readline + #------------------------------------------------------------------------- + + def init_readline(self): + """Command history completion/saving/reloading.""" + + if self.readline_use: + import IPython.utils.rlineimpl as readline + + self.rl_next_input = None + self.rl_do_indent = False + + if not self.readline_use or not readline.have_readline: + self.readline = None + # Set a number of methods that depend on readline to be no-op + self.readline_no_record = NoOpContext() + self.set_readline_completer = no_op + self.set_custom_completer = no_op + if self.readline_use: + warn('Readline services not available or not loaded.') + else: + self.has_readline = True + self.readline = readline + sys.modules['readline'] = readline + + # Platform-specific configuration + if os.name == 'nt': + # FIXME - check with Frederick to see if we can harmonize + # naming conventions with pyreadline to avoid this + # platform-dependent check + self.readline_startup_hook = readline.set_pre_input_hook + else: + self.readline_startup_hook = readline.set_startup_hook + + # Readline config order: + # - IPython config (default value) + # - custom inputrc + # - IPython config (user customized) + + # load IPython config before inputrc if default + # skip if libedit because parse_and_bind syntax is different + if not self._custom_readline_config and not readline.uses_libedit: + for rlcommand in self.readline_parse_and_bind: + readline.parse_and_bind(rlcommand) + + # Load user's initrc file (readline config) + # Or if libedit is used, load editrc. + inputrc_name = os.environ.get('INPUTRC') + if inputrc_name is None: + inputrc_name = '.inputrc' + if readline.uses_libedit: + inputrc_name = '.editrc' + inputrc_name = os.path.join(self.home_dir, inputrc_name) + if os.path.isfile(inputrc_name): + try: + readline.read_init_file(inputrc_name) + except: + warn('Problems reading readline initialization file <%s>' + % inputrc_name) + + # load IPython config after inputrc if user has customized + if self._custom_readline_config: + for rlcommand in self.readline_parse_and_bind: + readline.parse_and_bind(rlcommand) + + # Remove some chars from the delimiters list. If we encounter + # unicode chars, discard them. + delims = readline.get_completer_delims() + if not py3compat.PY3: + delims = delims.encode("ascii", "ignore") + for d in self.readline_remove_delims: + delims = delims.replace(d, "") + delims = delims.replace(ESC_MAGIC, '') + readline.set_completer_delims(delims) + # Store these so we can restore them if something like rpy2 modifies + # them. + self.readline_delims = delims + # otherwise we end up with a monster history after a while: + readline.set_history_length(self.history_length) + + self.refill_readline_hist() + self.readline_no_record = ReadlineNoRecord(self) + + # Configure auto-indent for all platforms + self.set_autoindent(self.autoindent) + + def init_completer(self): + super(TerminalInteractiveShell, self).init_completer() + + # Only configure readline if we truly are using readline. + if self.has_readline: + self.set_readline_completer() + + def set_readline_completer(self): + """Reset readline's completer to be our own.""" + self.readline.set_completer(self.Completer.rlcomplete) + + + def pre_readline(self): + """readline hook to be used at the start of each line. + + It handles auto-indent and text from set_next_input.""" + + if self.rl_do_indent: + self.readline.insert_text(self._indent_current_str()) + if self.rl_next_input is not None: + self.readline.insert_text(self.rl_next_input) + self.rl_next_input = None + + def refill_readline_hist(self): + # Load the last 1000 lines from history + self.readline.clear_history() + stdin_encoding = sys.stdin.encoding or "utf-8" + last_cell = u"" + for _, _, cell in self.history_manager.get_tail(self.history_load_length, + include_latest=True): + # Ignore blank lines and consecutive duplicates + cell = cell.rstrip() + if cell and (cell != last_cell): + try: + if self.multiline_history: + self.readline.add_history(py3compat.unicode_to_str(cell, + stdin_encoding)) + else: + for line in cell.splitlines(): + self.readline.add_history(py3compat.unicode_to_str(line, + stdin_encoding)) + last_cell = cell + + except TypeError: + # The history DB can get corrupted so it returns strings + # containing null bytes, which readline objects to. + continue + #------------------------------------------------------------------------- # Things related to the terminal #------------------------------------------------------------------------- diff --git a/IPython/utils/contexts.py b/IPython/utils/contexts.py index cb4b0841b5f..fcc97d7d933 100644 --- a/IPython/utils/contexts.py +++ b/IPython/utils/contexts.py @@ -1,22 +1,9 @@ # encoding: utf-8 +"""Miscellaneous context managers. """ -Context managers for temporarily updating dictionaries. -Authors: - -* Bradley Froehle -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2012 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. class preserve_keys(object): """Preserve a set of keys in a dictionary. @@ -69,3 +56,9 @@ def __exit__(self, *exc_info): for k in self.to_delete: d.pop(k, None) d.update(self.to_update) + + +class NoOpContext(object): + """Context manager that does nothing.""" + def __enter__(self): pass + def __exit__(self, type, value, traceback): pass From 9ca12ca6cc57bb667171ba70c4a073180e6843d6 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 15 Dec 2015 19:12:38 +0100 Subject: [PATCH 0026/4859] Remove old rtd note specifying that RTD isn't official docs Official docs are on RTD, now --- docs/source/index.rst | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 895c427f160..4423601a2ac 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -7,13 +7,7 @@ IPython Documentation :Release: |release| :Date: |today| -.. only:: not rtd - - Welcome to the official IPython documentation. - -.. only:: rtd - - This is a partial copy of IPython documentation, please visit `IPython official documentation `_. +Welcome to the official IPython documentation. Contents ======== From 1370018ac3f96a5a04d119afa95d482a7504119e Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Wed, 16 Dec 2015 18:37:59 -0800 Subject: [PATCH 0027/4859] Remove mention of Traits (removed in e1ced0b3) --- IPython/utils/dir2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/utils/dir2.py b/IPython/utils/dir2.py index 5fb9fd1cdb9..50c660af321 100644 --- a/IPython/utils/dir2.py +++ b/IPython/utils/dir2.py @@ -34,7 +34,7 @@ def dir2(obj): """dir2(obj) -> list of strings Extended version of the Python builtin dir(), which does a few extra - checks, and handles Traits objects, which can confuse dir(). + checks. This version is guaranteed to return only a list of true strings, whereas dir() returns anything that objects inject into themselves, even if they From 14c3e28572e29029bf3a977c94a13c24d87d0955 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 17 Dec 2015 19:11:53 +0100 Subject: [PATCH 0028/4859] Write tests for ipdb Add test for up, down, list and longlist. --- IPython/core/tests/test_debugger.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index 7b193d5a34e..9e11d932b84 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -100,7 +100,11 @@ def test_ipdb_magics(): >>> with PdbTestInput([ ... 'pdef example_function', ... 'pdoc ExampleClass', + ... 'up', + ... 'down', + ... 'list', ... 'pinfo a', + ... 'll', ... 'continue', ... ]): ... trigger_ipdb() @@ -118,12 +122,35 @@ def test_ipdb_magics(): Docstring for ExampleClass. Init docstring: Docstring for ExampleClass.__init__ + ipdb> up + > (11)() + 9 'continue', + 10 ]): + ---> 11 trigger_ipdb() + + ipdb> down + None + > (3)trigger_ipdb() + 1 def trigger_ipdb(): + 2 a = ExampleClass() + ----> 3 debugger.Pdb().set_trace() + + ipdb> list + 1 def trigger_ipdb(): + 2 a = ExampleClass() + ----> 3 debugger.Pdb().set_trace() + ipdb> pinfo a Type: ExampleClass String form: ExampleClass() Namespace: Local... Docstring: Docstring for ExampleClass. Init docstring: Docstring for ExampleClass.__init__ + ipdb> ll + 1 def trigger_ipdb(): + 2 a = ExampleClass() + ----> 3 debugger.Pdb().set_trace() + ipdb> continue Restore previous trace function, e.g. for coverage.py From 17a695ee0f3b86d29f00dc3a3fc2d756462253ca Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 18 Dec 2015 10:47:43 +0100 Subject: [PATCH 0029/4859] remove useless branch --- IPython/core/magics/basic.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index f8a3ba07c9e..67482425b16 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -3,7 +3,6 @@ from __future__ import print_function import io -import json import sys from pprint import pformat @@ -194,8 +193,6 @@ def magic(self, parameter_s=''): mode = '' try: mode = parameter_s.split()[0][1:] - if mode == 'rest': - rest_docs = [] except IndexError: pass From cd785306103d0d100daf8e96374004129ef68b9c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 18 Dec 2015 15:15:16 +0100 Subject: [PATCH 0030/4859] Remove some useless assignments. --- IPython/core/interactiveshell.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3602a790cd5..be0e9327ff2 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1459,7 +1459,6 @@ def _ofind(self, oname, namespaces=None): not py3compat.isidentifier(oname, dotted=True): return dict(found=False) - alias_ns = None if namespaces is None: # Namespaces to search in: # Put them in a list. The order is important so that we @@ -1470,7 +1469,7 @@ def _ofind(self, oname, namespaces=None): ] # initialize results to 'null' - found = False; obj = None; ospace = None; ds = None + found = False; obj = None; ospace = None; ismagic = False; isalias = False; parent = None # We need to special-case 'print', which as of python2.6 registers as a @@ -2647,7 +2646,7 @@ def safe_execfile(self, fname, *where, **kw): # Make sure we can open the file try: - with open(fname) as thefile: + with open(fname): pass except: warn('Could not open file <%s> for safe execution.' % fname) @@ -2705,7 +2704,7 @@ def safe_execfile_ipy(self, fname, shell_futures=False, raise_exceptions=False): # Make sure we can open the file try: - with open(fname) as thefile: + with open(fname): pass except: warn('Could not open file <%s> for safe execution.' % fname) @@ -2991,8 +2990,6 @@ def run_ast_nodes(self, nodelist, cell_name, interactivity='last_expr', else: raise ValueError("Interactivity was %r" % interactivity) - exec_count = self.execution_count - try: for i, node in enumerate(to_run_exec): mod = ast.Module([node]) From a85099ae323dae1a5e7f0769682dfd405864d860 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Fri, 18 Dec 2015 11:52:59 -0500 Subject: [PATCH 0031/4859] fix docstring typo --- IPython/utils/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/utils/frame.py b/IPython/utils/frame.py index 348cbcc4d42..76ccc71c446 100644 --- a/IPython/utils/frame.py +++ b/IPython/utils/frame.py @@ -90,7 +90,7 @@ def debugx(expr,pre_msg=''): #def debugx(expr,pre_msg=''): pass def extract_module_locals(depth=0): - """Returns (module, locals) of the funciton `depth` frames away from the caller""" + """Returns (module, locals) of the function `depth` frames away from the caller""" f = sys._getframe(depth + 1) global_ns = f.f_globals module = sys.modules[global_ns['__name__']] From af40089bfa6a3c4b9363af4f03571f7bd98cb8d1 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Fri, 18 Dec 2015 20:21:42 -0500 Subject: [PATCH 0032/4859] fix typos in comments --- IPython/core/interactiveshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 56aea6df6a2..b13c58acb0a 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1054,7 +1054,7 @@ def init_create_namespaces(self, user_module=None, user_ns=None): # Now that FakeModule produces a real module, we've run into a nasty # problem: after script execution (via %run), the module where the user # code ran is deleted. Now that this object is a true module (needed - # so docetst and other tools work correctly), the Python module + # so doctest and other tools work correctly), the Python module # teardown mechanism runs over it, and sets to None every variable # present in that module. Top-level references to objects from the # script survive, because the user_ns is updated with them. However, @@ -1168,7 +1168,7 @@ def init_user_ns(self): # user_ns, and we sync that contents into user_ns_hidden so that these # initial variables aren't shown by %who. After the sync, we add the # rest of what we *do* want the user to see with %who even on a new - # session (probably nothing, so theye really only see their own stuff) + # session (probably nothing, so they really only see their own stuff) # The user dict must *always* have a __builtin__ reference to the # Python standard __builtin__ namespace, which must be imported. From 5bd7642ecfc0b4e16c1787fd467a37ebf9f4a942 Mon Sep 17 00:00:00 2001 From: Thomas Ballinger Date: Fri, 18 Dec 2015 20:22:27 -0500 Subject: [PATCH 0033/4859] fix typos in docstrings --- IPython/core/interactiveshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index b13c58acb0a..48908cb5a18 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2022,7 +2022,7 @@ def init_completer(self): This creates completion machinery that can be used by client code, either interactively in-process (typically triggered by the readline - library), programatically (such as in test suites) or out-of-prcess + library), programmatically (such as in test suites) or out-of-process (typically over the network by remote frontends). """ from IPython.core.completer import IPCompleter @@ -3165,7 +3165,7 @@ def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=T A string specifying code to retrieve. This will be tried respectively as: ranges of input history (see %history for syntax), url, - correspnding .py file, filename, or an expression evaluating to a + corresponding .py file, filename, or an expression evaluating to a string or Macro in the user namespace. raw : bool From beb2d24f8019b7eee4851fa7adf6f6455a521696 Mon Sep 17 00:00:00 2001 From: Ben Kasel Date: Sun, 20 Dec 2015 22:20:08 +0100 Subject: [PATCH 0034/4859] ENH added _repr_jpeg_ method for YouTubeVideo object to allow conversion to latex and pdf. --- IPython/lib/display.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index f65ee4107e1..c50f5fa7e5a 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -255,8 +255,12 @@ class YouTubeVideo(IFrame): """ def __init__(self, id, width=400, height=300, **kwargs): + self.id=id src = "https://www.youtube.com/embed/{0}".format(id) super(YouTubeVideo, self).__init__(src, width, height, **kwargs) + def _repr_jpeg_(self): + from urllib import urlopen + return urlopen("https://img.youtube.com/vi/{id}/0.jpg".format(id=self.id)).read() class VimeoVideo(IFrame): """ From 2247f3474cc92ffc18b84a4d326be30aa9f55275 Mon Sep 17 00:00:00 2001 From: Ben Kasel Date: Mon, 21 Dec 2015 11:53:08 +0100 Subject: [PATCH 0035/4859] - changed to default jpeg image for YouTubeVideo representation - added blank line - added small note to the docstring --- IPython/lib/display.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index c50f5fa7e5a..e46e254470c 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -252,15 +252,19 @@ class YouTubeVideo(IFrame): Other parameters can be provided as documented at https://developers.google.com/youtube/player_parameters#parameter-subheader + + When converting the notebook using nbconvert, a jpeg representation of the video + will be inserted in the document. """ def __init__(self, id, width=400, height=300, **kwargs): self.id=id src = "https://www.youtube.com/embed/{0}".format(id) super(YouTubeVideo, self).__init__(src, width, height, **kwargs) + def _repr_jpeg_(self): from urllib import urlopen - return urlopen("https://img.youtube.com/vi/{id}/0.jpg".format(id=self.id)).read() + return urlopen("https://img.youtube.com/vi/{id}/default.jpg".format(id=self.id)).read() class VimeoVideo(IFrame): """ From d095aa8941d3c2cb2e0f0ce8145d1952ac5a0aee Mon Sep 17 00:00:00 2001 From: Ben Kasel Date: Mon, 21 Dec 2015 12:02:29 +0100 Subject: [PATCH 0036/4859] - Changed the YouTubeVideo jpeg picture to high quality --- IPython/lib/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index e46e254470c..4cdedc4ff72 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -264,7 +264,7 @@ def __init__(self, id, width=400, height=300, **kwargs): def _repr_jpeg_(self): from urllib import urlopen - return urlopen("https://img.youtube.com/vi/{id}/default.jpg".format(id=self.id)).read() + return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() class VimeoVideo(IFrame): """ From 0b860b23d49c16dc486be118d6d99adf4c892fd1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 21 Dec 2015 12:37:15 +0100 Subject: [PATCH 0037/4859] Show some warnings during testing. It's a good habit, that will push us to cleanup some things, I hope. Silence a few annoying warnings for a couple of years. --- IPython/testing/iptest.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 2dc6eef3053..cd987a4ca32 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -34,6 +34,7 @@ from nose.plugins import Plugin from nose.util import safe_str +from IPython import version_info from IPython.utils.py3compat import bytes_to_str from IPython.utils.importstring import import_item from IPython.testing.plugin.ipdoctest import IPythonDoctest @@ -58,6 +59,24 @@ warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch', UserWarning) +# Enable printing all warnings raise by IPython's modules +warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') + + +if version_info < (6,): + # ignore some warnings from traitlets until 6.0 + warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*') + warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*') +else : + warnings.warn('iptest has been filtering out for Traitlets warnings messages, for 2 major versions (since 4.x), please consider updating to use new API') + +if version_info < (6,): + # nose.tools renames all things from `camelCase` to `snake_case` which raise an + # warning with the runner they also import from standard import library. (as of Dec 2015) + # Ignore, let's revisit that in a couple of years for IPython 6. + warnings.filterwarnings('ignore', message='.*Please use assertEqual instead', category=Warning, module='IPython.*') + + # ------------------------------------------------------------------------------ # Monkeypatch Xunit to count known failures as skipped. # ------------------------------------------------------------------------------ From a48716ad007352d7e79511e91450569811107910 Mon Sep 17 00:00:00 2001 From: Ben Kasel Date: Mon, 21 Dec 2015 13:13:53 +0100 Subject: [PATCH 0038/4859] - Added a fallback to urllib2 for python2 - included urlopen call in a try/except block to avoid crash when no internet connection is available --- IPython/lib/display.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index 4cdedc4ff72..b0176ff47c0 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -263,8 +263,14 @@ def __init__(self, id, width=400, height=300, **kwargs): super(YouTubeVideo, self).__init__(src, width, height, **kwargs) def _repr_jpeg_(self): - from urllib import urlopen - return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() + try: + from urllib.request import urlopen # Py3 + except ImportError: + from urllib2 import urlopen + try: + return urlopen("https://img.youtube.com/vi/{id}/hqdefault.jpg".format(id=self.id)).read() + except IOError: + return None class VimeoVideo(IFrame): """ From 431b7bddb6d7339c97181ab84837bd4145744bc0 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 21 Dec 2015 13:26:04 +0100 Subject: [PATCH 0039/4859] Decrease version limit to 5 for warning filter. --- IPython/testing/iptest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index cd987a4ca32..61339e04ff6 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -63,7 +63,7 @@ warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') -if version_info < (6,): +if version_info < (5,): # ignore some warnings from traitlets until 6.0 warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*') warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*') From 8472f0dd9d801c2732a55ee27f1cf6ab16cc6b99 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 21 Dec 2015 13:29:34 +0100 Subject: [PATCH 0040/4859] Decrease minor version warning to 4.2 --- IPython/testing/iptest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 61339e04ff6..b2d338d237c 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -63,7 +63,7 @@ warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') -if version_info < (5,): +if version_info < (4,2): # ignore some warnings from traitlets until 6.0 warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*') warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*') From 9d793c5db4eba8f06ce163aea3be2f4122a0b3ec Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 21 Dec 2015 14:40:57 +0100 Subject: [PATCH 0041/4859] Remove deprecated encodestring infavor of encodebytes --- IPython/lib/latextools.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index 4e08c01fc84..446efdfce5e 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -5,7 +5,6 @@ # Distributed under the terms of the Modified BSD License. from io import BytesIO, open -from base64 import encodestring import os import tempfile import shutil @@ -15,7 +14,12 @@ from traitlets.config import get_config from traitlets.config.configurable import SingletonConfigurable from traitlets import List, Bool, Unicode -from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u +from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u, PY3 + +if PY3: + from base64 import encodebytes +else : + from base64 import encodestring as encodebytes class LaTeXTool(SingletonConfigurable): @@ -86,7 +90,7 @@ def latex_to_png(s, encode=False, backend=None, wrap=False): raise ValueError('No such backend {0}'.format(backend)) bin_data = f(s, wrap) if encode and bin_data: - bin_data = encodestring(bin_data) + bin_data = encodebytes(bin_data) return bin_data From f682059bde4346b8949cad647ce17a2a349348cb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 21 Dec 2015 15:45:31 +0100 Subject: [PATCH 0042/4859] Switch to try/except ImportError. --- IPython/lib/latextools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index 446efdfce5e..159b8228e2d 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -16,9 +16,9 @@ from traitlets import List, Bool, Unicode from IPython.utils.py3compat import cast_unicode, cast_unicode_py2 as u, PY3 -if PY3: +try: # Py3 from base64 import encodebytes -else : +except ImportError: # Py2 from base64 import encodestring as encodebytes From 7d05f26957a155ecc7f6e567125c13b9269fb3ef Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 22 Dec 2015 17:28:20 +0000 Subject: [PATCH 0043/4859] Print debugging info from test_extension I want this to debug a test failure on Jenkins. Merging immediately. --- IPython/core/tests/test_magic.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 420895bc849..a507ab9861d 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -605,6 +605,12 @@ def test_prun_quotes(): nt.assert_equal(_ip.user_ns['x'], '\t') def test_extension(): + # Debugging information for failures of this test + print('sys.path:') + for p in sys.path: + print(' ', p) + print('CWD', os.getcwd()) + nt.assert_raises(ImportError, _ip.magic, "load_ext daft_extension") daft_path = os.path.join(os.path.dirname(__file__), "daft_extension") sys.path.insert(0, daft_path) From 3ffdf6f927afe3be9cff685bebb1a5ad1ff9a5bd Mon Sep 17 00:00:00 2001 From: Michael Droettboom Date: Tue, 22 Dec 2015 16:37:51 -0500 Subject: [PATCH 0044/4859] Support parallel sphinx building --- IPython/sphinxext/ipython_console_highlighting.py | 3 ++- IPython/sphinxext/ipython_directive.py | 3 +++ docs/sphinxext/github.py | 6 ++++-- docs/sphinxext/magics.py | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/IPython/sphinxext/ipython_console_highlighting.py b/IPython/sphinxext/ipython_console_highlighting.py index 3b00b6e2c71..b93a151fb3c 100644 --- a/IPython/sphinxext/ipython_console_highlighting.py +++ b/IPython/sphinxext/ipython_console_highlighting.py @@ -13,7 +13,8 @@ def setup(app): # But if somebody knows what the right API usage should be to do that via # sphinx, by all means fix it here. At least having this setup.py # suppresses the sphinx warning we'd get without it. - pass + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata # Register the extension as a valid pygments lexer. # Alternatively, we could register the lexer with pygments instead. This would diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index d6054490adf..cde36cf4829 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -1008,6 +1008,9 @@ def setup(app): app.add_config_value('ipython_holdcount', True, 'env') + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata + # Simple smoke test, needs to be converted to a proper automatic test. def test(): diff --git a/docs/sphinxext/github.py b/docs/sphinxext/github.py index 519e146d198..8f0ffc0d978 100644 --- a/docs/sphinxext/github.py +++ b/docs/sphinxext/github.py @@ -143,7 +143,7 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): def setup(app): """Install the plugin. - + :param app: Sphinx application context. """ app.info('Initializing GitHub plugin') @@ -152,4 +152,6 @@ def setup(app): app.add_role('ghuser', ghuser_role) app.add_role('ghcommit', ghcommit_role) app.add_config_value('github_project_url', None, 'env') - return + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata diff --git a/docs/sphinxext/magics.py b/docs/sphinxext/magics.py index c8da2d36deb..913a0c51beb 100644 --- a/docs/sphinxext/magics.py +++ b/docs/sphinxext/magics.py @@ -40,3 +40,6 @@ def setup(app): StandardDomain.roles['magic'] = LineMagicRole() app.add_object_type('cellmagic', 'cellmagic', 'pair: %s; cell magic', parse_cell_magic) StandardDomain.roles['cellmagic'] = CellMagicRole() + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata From ef9aecb737893cd6eeaca7e38b8af9318d0cde31 Mon Sep 17 00:00:00 2001 From: JamshedVesuna Date: Tue, 22 Dec 2015 13:16:43 -0800 Subject: [PATCH 0045/4859] Added user defined context for Pdb --- IPython/core/debugger.py | 64 +++++++++++++++++++++++++++++++++------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index f3a619bb921..a1ba878d875 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -29,7 +29,6 @@ import bdb import functools import inspect -import linecache import sys from IPython import get_ipython @@ -54,7 +53,6 @@ if has_pydb: from pydb import Pdb as OldPdb - #print "Using pydb for %run -d and post-mortem" #dbg prompt = 'ipydb> ' else: from pdb import Pdb as OldPdb @@ -94,7 +92,7 @@ class Tracer(object): """ @skip_doctest - def __init__(self,colors=None): + def __init__(self, colors=None): """Create a local debugger instance. Parameters @@ -202,9 +200,16 @@ class Pdb(OldPdb): """Modified Pdb class, does not load readline.""" def __init__(self,color_scheme='NoColor',completekey=None, - stdin=None, stdout=None): + stdin=None, stdout=None, context=5): # Parent constructor: + try: + self.context=int(context) + if self.context <= 0: + raise ValueError("Context must be a positive integer") + except (TypeError, ValueError): + raise ValueError("Context must be a positive integer") + if has_pydb and completekey is None: OldPdb.__init__(self,stdin=stdin,stdout=io.stdout) else: @@ -324,16 +329,31 @@ def new_do_restart(self, arg): def postloop(self): self.shell.set_completer_frame(None) - def print_stack_trace(self): + def print_stack_trace(self, context=None): + if context is None: + context = self.context + try: + context=int(context) + if context <= 0: + raise ValueError("Context must be a positive integer") + except (TypeError, ValueError): + raise ValueError("Context must be a positive integer") try: for frame_lineno in self.stack: - self.print_stack_entry(frame_lineno, context = 5) + self.print_stack_entry(frame_lineno, context=context) except KeyboardInterrupt: pass def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ', - context = 3): - #frame, lineno = frame_lineno + context=None): + if context is None: + context = self.context + try: + context=int(context) + if context <= 0: + raise ValueError("Context must be a positive integer") + except (TypeError, ValueError): + raise ValueError("Context must be a positive integer") print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout) # vds: >> @@ -342,7 +362,15 @@ def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ', self.shell.hooks.synchronize_with_editor(filename, lineno, 0) # vds: << - def format_stack_entry(self, frame_lineno, lprefix=': ', context = 3): + def format_stack_entry(self, frame_lineno, lprefix=': ', context=None): + if context is None: + context = self.context + try: + context=int(context) + if context <= 0: + print("Context must be a positive integer") + except (TypeError, ValueError): + print("Context must be a positive integer") try: import reprlib # Py 3 except ImportError: @@ -530,7 +558,6 @@ def getsourcelines(self, obj): def do_longlist(self, arg): self.lastcmd = 'longlist' filename = self.curframe.f_code.co_filename - breaklist = self.get_file_breaks(filename) try: lines, lineno = self.getsourcelines(self.curframe) except OSError as err: @@ -586,3 +613,20 @@ def do_psource(self, arg): namespaces = [('Locals', self.curframe.f_locals), ('Globals', self.curframe.f_globals)] self.shell.find_line_magic('psource')(arg, namespaces=namespaces) + + if sys.version_info > (3, ): + def do_where(self, arg): + """w(here) + Print a stack trace, with the most recent frame at the bottom. + An arrow indicates the "current frame", which determines the + context of most commands. 'bt' is an alias for this command. + + Take a number as argument as an (optional) number of context line to + print""" + if arg: + context = int(arg) + self.print_stack_trace(context) + else: + self.print_stack_trace() + + do_w = do_where From 7af3c64e34056ba4e107b0ba0a2280ce4253216b Mon Sep 17 00:00:00 2001 From: jferrara Date: Thu, 24 Dec 2015 15:16:14 -0500 Subject: [PATCH 0046/4859] Undo Testing Deprecation Warning for onlyif_cmds_exist --- IPython/testing/decorators.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index 33394badb52..e0ca498040e 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -361,7 +361,6 @@ def onlyif_cmds_exist(*commands): """ Decorator to skip test when at least one of `commands` is not found. """ - warnings.warn("The function `onlyif_cmds_exist` is deprecated and might be removed in next major version of IPython", DeprecationWarning) for cmd in commands: if not which(cmd): return skip("This test runs only if command '{0}' " From adef11536410eed5b5a067bea41a9203fb980dc1 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 26 Dec 2015 17:36:33 +0000 Subject: [PATCH 0047/4859] Improve kernel installation docs I hope this makes it clearer and more concise how to install the IPython kernelspec, and when you'd want to. --- docs/source/install/kernel_install.rst | 43 ++++++-------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index b4614e6ac87..7655b213f82 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -3,49 +3,26 @@ Installing the IPython kernel ============================= -IPython can be installed (different python versions, virtualenv or conda -environments) as a kernel for Jupyter by following these steps: +The Jupyter Notebook and other frontends automatically ensure that the IPython kernel is available. +However, if you want to use a kernel with a different version of Python, or in a virtualenv or conda environment, +you'll need to install that manually. -* make sure that the desired python installation is active - (e.g. activate the environment, or use absolute paths) - and ipykernel is installed -* run once ``ipython kernel install --user``, - or ``python -m ipykernel install --user`` to ensure a specific Python installation is used. -* See `ipython kernel install --help` for the list of installation options like - naming the kernel, or non default install location. -* The IPython kernel for Jupyter is provided by the `ipykernel` python package, - see `ipykernel documentation `_ if you - need more flexibility for installation. +Using the Python version or environment for which you want to set up the kernel, run:: - -For example: - -.. sourcecode:: bash - - source activate kernel-environment - ipython kernel install --user - source deactivate kernel-environment - -or - -.. sourcecode:: bash - - ~/envs/kernel-environment/python -m ipykernel install --user + pip install ipykernel # or: conda install ipykernel + python -m ipykernel install --user The last command installs a :ref:`kernel spec ` file for the current python installation. Kernel spec files are JSON files, which can be viewed and changed with a normal text editor. - -.. note :: - - The command `ipython kernelspec` is deprecated and will be removed in future versions. - +See `python -m ipykernel install --help` for the list of installation options like +naming the kernel, or non default install location. .. _multiple_kernel_install: -Multiple IPython installs -========================= +Multiple IPython installations +============================== If you want to have multiple IPython kernels for different environments, you will need to specify unique names for the kernelspecs, From 6cf65baf7120e1c0248a6cff21a82a9c18afc646 Mon Sep 17 00:00:00 2001 From: Jan-Philip Gehrcke Date: Mon, 28 Dec 2015 02:39:17 +0100 Subject: [PATCH 0048/4859] external/qt_loaders: list required Qt modules in import error message --- IPython/external/qt_loaders.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/external/qt_loaders.py b/IPython/external/qt_loaders.py index a5cb3e97c0b..fd695661a9e 100644 --- a/IPython/external/qt_loaders.py +++ b/IPython/external/qt_loaders.py @@ -284,11 +284,11 @@ def load_qt(api_options): PyQt4 >= 4.7, PyQt5 or PySide >= 1.0.3 is available, and only one is imported per session. - Currently-imported Qt library: %r - PyQt4 installed: %s - PyQt5 installed: %s - PySide >= 1.0.3 installed: %s - Tried to load: %r + Currently-imported Qt library: %r + PyQt4 available (requires QtCore, QtGui, QtSvg): %s + PyQt5 available (requires QtCore, QtGui, QtSvg, QtWidgets): %s + PySide >= 1.0.3 installed: %s + Tried to load: %r """ % (loaded_api(), has_binding(QT_API_PYQT), has_binding(QT_API_PYQT5), From 13fbe3ad29d29a8256f6b70527b3cbd5205ed5c3 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Tue, 5 Jan 2016 16:26:24 +0100 Subject: [PATCH 0049/4859] minor bug --- IPython/core/oinspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index e7be78b6541..f819990fc26 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -832,7 +832,7 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): else: callable_obj = None - if callable_obj: + if callable_obj is not None: try: argspec = getargspec(callable_obj) except (TypeError, AttributeError): From 9a7ea611c359f98095dd99aaf3c2a20db9b57220 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Tue, 5 Jan 2016 16:30:21 +0100 Subject: [PATCH 0050/4859] Tests thanks @carreau --- IPython/core/tests/test_oinspect.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index 0c71f0091d9..e868730b23f 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -172,6 +172,19 @@ class Awkward(object): def __getattr__(self, name): raise Exception(name) +class NoBoolCall: + """ + callable with `__bool__` raising should still be inspect-able. + """ + + def __call__(self): + """does nothing""" + pass + + def __bool__(self): + """just raise NotImplemented""" + raise NotImplementedError('Must be implemented') + def check_calltip(obj, name, call, docstring): """Generic check pattern all calltip tests will use""" @@ -281,6 +294,9 @@ def test_info_awkward(): # Just test that this doesn't throw an error. i = inspector.info(Awkward()) +def test_bool_raise(): + inspector.info(NoBoolCall()) + def test_calldef_none(): # We should ignore __call__ for all of these. for obj in [f, SimpleClass().method, any, str.upper]: From 5fa2eb281c741bd2c6f190d3fdbaf10f4217f54f Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Tue, 5 Jan 2016 16:47:05 +0100 Subject: [PATCH 0051/4859] log.warn -> log.warning in application.py --- IPython/core/application.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index bf2ab7ef3fd..07a393a6045 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -289,7 +289,7 @@ def load_config_file(self, suppress_errors=True): except ConfigFileNotFound: # Only warn if the default config file was NOT being used. if config_file_name in self.config_file_specified: - msg = self.log.warn + msg = self.log.warning else: msg = self.log.debug msg("Config file not found, skipping: %s", config_file_name) @@ -297,7 +297,7 @@ def load_config_file(self, suppress_errors=True): # For testing purposes. if not suppress_errors: raise - self.log.warn("Error loading config file: %s" % + self.log.warning("Error loading config file: %s" % self.config_file_name, exc_info=True) def init_profile_dir(self): @@ -364,7 +364,7 @@ def init_config_files(self): cfg = self.config_file_name if path and os.path.exists(os.path.join(path, cfg)): - self.log.warn("Staging %r from %s into %r [overwrite=%s]"%( + self.log.warning("Staging %r from %s into %r [overwrite=%s]"%( cfg, src, self.profile_dir.location, self.overwrite) ) self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite) @@ -379,7 +379,7 @@ def init_config_files(self): cfg = os.path.basename(fullpath) if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False): # file was copied - self.log.warn("Staging bundled %s from %s into %r"%( + self.log.warning("Staging bundled %s from %s into %r"%( cfg, self.profile, self.profile_dir.location) ) @@ -389,7 +389,7 @@ def stage_default_config_file(self): s = self.generate_config_file() fname = os.path.join(self.profile_dir.location, self.config_file_name) if self.overwrite or not os.path.exists(fname): - self.log.warn("Generating default config file: %r"%(fname)) + self.log.warning("Generating default config file: %r"%(fname)) with open(fname, 'w') as f: f.write(s) @@ -407,4 +407,3 @@ def initialize(self, argv=None): self.load_config_file() # enforce cl-opts override configfile opts: self.update_config(cl_config) - From e149c2e43d89bf2054bf7ea17f0e0a4939ff20de Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Tue, 5 Jan 2016 16:50:15 +0100 Subject: [PATCH 0052/4859] Same in profileapp.py , profiledir.py, shellapp.py --- IPython/core/profileapp.py | 2 +- IPython/core/profiledir.py | 2 +- IPython/core/shellapp.py | 22 +++++++++++----------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index c8a33dc0b6c..fecdc0d5681 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -252,7 +252,7 @@ def _import_app(self, app_path): except ImportError: self.log.info("Couldn't import %s, config file will be excluded", name) except Exception: - self.log.warn('Unexpected error importing %s', name, exc_info=True) + self.log.warning('Unexpected error importing %s', name, exc_info=True) return app def init_config_files(self): diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py index 75bed35fd5b..7818f4ed551 100644 --- a/IPython/core/profiledir.py +++ b/IPython/core/profiledir.py @@ -87,7 +87,7 @@ def _mkdir(self, path, mode=None): try: os.chmod(path, mode) except OSError: - self.log.warn( + self.log.warning( "Could not set permissions on %s", path ) diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 1afbcb01796..f923337034e 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -231,11 +231,11 @@ def init_gui_pylab(self): try: r = enable(key) except ImportError: - self.log.warn("Eventloop or matplotlib integration failed. Is matplotlib installed?") + self.log.warning("Eventloop or matplotlib integration failed. Is matplotlib installed?") self.shell.showtraceback() return except Exception: - self.log.warn("GUI event loop or pylab initialization failed") + self.log.warning("GUI event loop or pylab initialization failed") self.shell.showtraceback() return @@ -273,11 +273,11 @@ def init_extensions(self): ext=ext, location=self.profile_dir.location )) - self.log.warn(msg, exc_info=True) + self.log.warning(msg, exc_info=True) except: if self.reraise_ipython_extension_failures: raise - self.log.warn("Unknown error in loading extensions:", exc_info=True) + self.log.warning("Unknown error in loading extensions:", exc_info=True) def init_code(self): """run the pre-flight code, specified via exec_lines""" @@ -310,18 +310,18 @@ def _run_exec_lines(self): line) self.shell.run_cell(line, store_history=False) except: - self.log.warn("Error in executing line in user " + self.log.warning("Error in executing line in user " "namespace: %s" % line) self.shell.showtraceback() except: - self.log.warn("Unknown error in handling IPythonApp.exec_lines:") + self.log.warning("Unknown error in handling IPythonApp.exec_lines:") self.shell.showtraceback() def _exec_file(self, fname, shell_futures=False): try: full_filename = filefind(fname, [u'.', self.ipython_dir]) except IOError as e: - self.log.warn("File not found: %r"%fname) + self.log.warning("File not found: %r"%fname) return # Make sure that the running script gets a proper sys.argv as if it # were run from a system shell. @@ -362,7 +362,7 @@ def _run_startup_files(self): try: self._exec_file(python_startup) except: - self.log.warn("Unknown error in handling PYTHONSTARTUP file %s:", python_startup) + self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup) self.shell.showtraceback() finally: # Many PYTHONSTARTUP files set up the readline completions, @@ -381,7 +381,7 @@ def _run_startup_files(self): for fname in sorted(startup_files): self._exec_file(fname) except: - self.log.warn("Unknown error in handling startup files:") + self.log.warning("Unknown error in handling startup files:") self.shell.showtraceback() def _run_exec_files(self): @@ -394,7 +394,7 @@ def _run_exec_files(self): for fname in self.exec_files: self._exec_file(fname) except: - self.log.warn("Unknown error in handling IPythonApp.exec_files:") + self.log.warning("Unknown error in handling IPythonApp.exec_files:") self.shell.showtraceback() def _run_cmd_line_code(self): @@ -406,7 +406,7 @@ def _run_cmd_line_code(self): line) self.shell.run_cell(line, store_history=False) except: - self.log.warn("Error in executing line in user namespace: %s" % + self.log.warning("Error in executing line in user namespace: %s" % line) self.shell.showtraceback() From 0cb1da813d92c3153f4760a58b9f47ff1b67b569 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 18 Dec 2015 16:05:25 +0100 Subject: [PATCH 0053/4859] Explicits deprecation warnings removal versions. Otherwise we never know when a feature will be removed. Nothing prevent us to keep longer, but at least giving a version number instead of "Next Major release" give a hint to users. And also when we want to cleanup later, we don't have to wonder when the deprecation was added. --- IPython/core/builtin_trap.py | 2 +- IPython/core/excolors.py | 2 +- IPython/core/formatters.py | 2 ++ IPython/core/interactiveshell.py | 10 ++++++---- IPython/core/magic.py | 2 ++ IPython/core/magics/deprecated.py | 5 +++-- IPython/core/shellapp.py | 4 +++- IPython/core/tests/test_interactiveshell.py | 1 - IPython/lib/deepreload.py | 3 ++- IPython/lib/kernel.py | 3 ++- IPython/terminal/embed.py | 4 ++-- IPython/terminal/ipapp.py | 14 +++++++------- IPython/testing/decorators.py | 10 +++++----- IPython/testing/iptest.py | 16 ---------------- 14 files changed, 36 insertions(+), 42 deletions(-) diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py index 403f7b4f687..95c9ca4bf18 100644 --- a/IPython/core/builtin_trap.py +++ b/IPython/core/builtin_trap.py @@ -57,7 +57,7 @@ def __init__(self, shell=None): from IPython.lib import deepreload if self.shell.deep_reload: from warnings import warn - warn("Automatically replacing builtin `reload` by `deepreload.reload` is deprecated, please import `reload` explicitly from `IPython.lib.deeprelaod", DeprecationWarning) + warn("Automatically replacing builtin `reload` by `deepreload.reload` is deprecated and will be removed in IPython 6.0, please import `reload` explicitly from `IPython.lib.deeprelaod", DeprecationWarning) self.auto_builtins['reload'] = deepreload._dreload else: self.auto_builtins['dreload']= deepreload._dreload diff --git a/IPython/core/excolors.py b/IPython/core/excolors.py index 9508c15f8d9..9d5725890bd 100644 --- a/IPython/core/excolors.py +++ b/IPython/core/excolors.py @@ -136,7 +136,7 @@ def __init__(self, wrapped_obj): def __getattr__(self, name): val = getattr(self.wrapped, name) - warnings.warn("Using ExceptionColors global is deprecated", DeprecationWarning) + warnings.warn("Using ExceptionColors global is deprecated and will be removed in IPython 6.0", DeprecationWarning) # using getattr after warnings break ipydoctest in weird way for 3.5 return val diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 3a7d598f54f..aa0567929b8 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -62,6 +62,8 @@ class DisplayFormatter(Configurable): def _plain_text_only_changed(self, name, old, new): warnings.warn("""DisplayFormatter.plain_text_only is deprecated. + It will be removed in IPython 5.0 + Use DisplayFormatter.active_types = ['text/plain'] for the same effect. """, DeprecationWarning) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 02855c92080..cf357eabaf2 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -294,6 +294,8 @@ class InteractiveShell(SingletonConfigurable): """ **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 @@ -365,13 +367,13 @@ def _exiter_default(self): # deprecated prompt traits: prompt_in1 = Unicode('In [\\#]: ', config=True, - help="Deprecated, use PromptManager.in_template") + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template") prompt_in2 = Unicode(' .\\D.: ', config=True, - help="Deprecated, use PromptManager.in2_template") + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template") prompt_out = Unicode('Out[\\#]: ', config=True, - help="Deprecated, use PromptManager.out_template") + help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template") prompts_pad_left = CBool(True, config=True, - help="Deprecated, use PromptManager.justify") + help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify") def _prompt_trait_changed(self, name, old, new): table = { diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 3ac4b1ccad9..0566fa9329f 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -433,6 +433,8 @@ def register_function(self, func, magic_kind='line', magic_name=None): def define_magic(self, name, func): """[Deprecated] Expose own function as magic function for IPython. + Will be removed in IPython 5.0 + Example:: def foo_impl(self, parameter_s=''): diff --git a/IPython/core/magics/deprecated.py b/IPython/core/magics/deprecated.py index 04da49883e7..df5b74ac5fd 100644 --- a/IPython/core/magics/deprecated.py +++ b/IPython/core/magics/deprecated.py @@ -15,6 +15,7 @@ # Our own packages from IPython.core.magic import Magics, magics_class, line_magic +import warnings #----------------------------------------------------------------------------- # Magic implementation classes @@ -28,7 +29,7 @@ class DeprecatedMagics(Magics): def install_profiles(self, parameter_s=''): """%install_profiles has been deprecated.""" print('\n'.join([ - "%install_profiles has been deprecated.", + "%install_profiles has been deprecated and will be removed in IPython 5.0.", "Use `ipython profile list` to view available profiles.", "Requesting a profile with `ipython profile create `", "or `ipython --profile=` will start with the bundled", @@ -37,7 +38,7 @@ def install_profiles(self, parameter_s=''): @line_magic def install_default_config(self, parameter_s=''): - """%install_default_config has been deprecated.""" + """%install_default_config has been deprecate and will be removed in IPython 5.0.""" print('\n'.join([ "%install_default_config has been deprecated.", "Use `ipython profile create ` to initialize a profile", diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 1afbcb01796..0bc2a3bd197 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -71,7 +71,9 @@ "Disable using colors for info related things." ) addflag('deep-reload', 'InteractiveShell.deep_reload', - """ **Deprecated** Enable deep (recursive) reloading by default. IPython can use the + """ **Deprecated** and will be removed in IPython 5.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 diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index ed2b53f6d0f..adc9cf05609 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -30,7 +30,6 @@ skipif, skip_win32, onlyif_unicode_paths, onlyif_cmds_exist, ) from IPython.testing import tools as tt -from IPython.utils import io from IPython.utils.process import find_cmd from IPython.utils import py3compat from IPython.utils.py3compat import unicode_type, PY3 diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index 5a98e8395f1..af226d9c94e 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -351,7 +351,8 @@ def _dreload(module, **kwargs): """ warn(""" -injecting `dreload` in interactive namespace is deprecated, please import `reload` explicitly from `IPython.lib.deepreload` +injecting `dreload` in interactive namespace is deprecated, and will be removed in IPython 5.0. +Please import `reload` explicitly from `IPython.lib.deepreload`. """, DeprecationWarning, stacklevel=2) reload(module, **kwargs) diff --git a/IPython/lib/kernel.py b/IPython/lib/kernel.py index d48c43baa96..e5d5efdd172 100644 --- a/IPython/lib/kernel.py +++ b/IPython/lib/kernel.py @@ -4,7 +4,8 @@ """ import warnings -warnings.warn("IPython.lib.kernel moved to IPython.kernel.connect in IPython 1.0", +warnings.warn("IPython.lib.kernel moved to IPython.kernel.connect in IPython 1.0," + "and will be removed in IPython 6.0.", DeprecationWarning ) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 140458e0479..9b81fc8639f 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -63,7 +63,7 @@ def __init__(self, **kw): if kw.get('user_global_ns', None) is not None: warnings.warn("user_global_ns has been replaced by user_module. The\ - parameter will be ignored.", DeprecationWarning) + parameter will be ignored, and removed in IPython 5.0", DeprecationWarning) super(InteractiveShellEmbed,self).__init__(**kw) @@ -158,7 +158,7 @@ def mainloop(self, local_ns=None, module=None, stack_depth=0, """ if (global_ns is not None) and (module is None): - warnings.warn("global_ns is deprecated, use module instead.", DeprecationWarning) + warnings.warn("global_ns is deprecated, and will be removed in IPython 5.0 use module instead.", DeprecationWarning) module = DummyMod() module.__dict__ = global_ns diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index eb1bd0950d5..fe3d0083269 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -200,22 +200,22 @@ def _classes_default(self): deprecated_subcommands = dict( qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp', - """DEPRECATD: Launch the Jupyter Qt Console.""" + """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console.""" ), notebook=('notebook.notebookapp.NotebookApp', - """DEPRECATED: Launch the Jupyter HTML Notebook Server.""" + """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server.""" ), console=('jupyter_console.app.ZMQTerminalIPythonApp', - """DEPRECATED: Launch the Jupyter terminal-based Console.""" + """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console.""" ), nbconvert=('nbconvert.nbconvertapp.NbConvertApp', - "DEPRECATED: Convert notebooks to/from other formats." + "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats." ), trust=('nbformat.sign.TrustNotebookApp', - "DEPRECATED: Sign notebooks to trust their potentially unsafe contents at load." + "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load." ), kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp', - "DEPRECATED: Manage Jupyter kernel specifications." + "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications." ), ) subcommands = dict( @@ -234,7 +234,7 @@ def _classes_default(self): ) deprecated_subcommands['install-nbextension'] = ( "notebook.nbextensions.InstallNBExtensionApp", - "DEPRECATED: Install Jupyter notebook extension files" + "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files" ) subcommands.update(deprecated_subcommands) diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index e0ca498040e..a337254ca23 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -76,7 +76,7 @@ def apply_wrapper(wrapper,func): This will ensure that wrapped functions can still be well introspected via IPython, for example. """ - warnings.warn("The function `apply_wrapper` is deprecated and might be removed in next major version of IPython", DeprecationWarning) + warnings.warn("The function `apply_wrapper` is deprecated and might be removed in IPython 5.0", DeprecationWarning) import nose.tools @@ -128,7 +128,7 @@ def make_label_dec(label,ds=None): True """ - warnings.warn("The function `make_label_dec` is deprecated and might be removed in next major version of IPython", DeprecationWarning) + warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning) if isinstance(label, string_types): labels = [label] else: @@ -284,7 +284,7 @@ def decorated_dummy(dec, name): import IPython.testing.decorators as dec setup = dec.decorated_dummy(dec.skip_if_no_x11, __name__) """ - warnings.warn("The function `make_label_dec` is deprecated and might be removed in next major version of IPython", DeprecationWarning) + warnings.warn("The function `make_label_dec` is deprecated and might be removed in IPython 5.0", DeprecationWarning) dummy = lambda: None dummy.__name__ = name return dec(dummy) @@ -317,7 +317,7 @@ def decorated_dummy(dec, name): # not a decorator itself, returns a dummy function to be used as setup def skip_file_no_x11(name): - warnings.warn("The function `skip_file_no_x11` is deprecated and might be removed in next major version of IPython", DeprecationWarning) + warnings.warn("The function `skip_file_no_x11` is deprecated and might be removed in IPython 5.0", DeprecationWarning) return decorated_dummy(skip_if_no_x11, name) if _x11_skip_cond else None # Other skip decorators @@ -371,7 +371,7 @@ def onlyif_any_cmd_exists(*commands): """ Decorator to skip test unless at least one of `commands` is found. """ - warnings.warn("The function `onlyif_any_cmd_exists` is deprecated and might be removed in next major version of IPython", DeprecationWarning) + warnings.warn("The function `onlyif_any_cmd_exists` is deprecated and might be removed in IPython 5.0", DeprecationWarning) for cmd in commands: if which(cmd): return null_deco diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index b2d338d237c..7950b8c68b8 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -42,22 +42,6 @@ pjoin = path.join -#----------------------------------------------------------------------------- -# Warnings control -#----------------------------------------------------------------------------- - -# Twisted generates annoying warnings with Python 2.6, as will do other code -# that imports 'sets' as of today -warnings.filterwarnings('ignore', 'the sets module is deprecated', - DeprecationWarning ) - -# This one also comes from Twisted -warnings.filterwarnings('ignore', 'the sha module is deprecated', - DeprecationWarning) - -# Wx on Fedora11 spits these out -warnings.filterwarnings('ignore', 'wxPython/wxWidgets release number mismatch', - UserWarning) # Enable printing all warnings raise by IPython's modules warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') From abd031405fd7db3f19db0641232b94f936ca729d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Jan 2016 17:29:24 +0100 Subject: [PATCH 0054/4859] Add missing space --- IPython/lib/kernel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/lib/kernel.py b/IPython/lib/kernel.py index e5d5efdd172..af9827667fb 100644 --- a/IPython/lib/kernel.py +++ b/IPython/lib/kernel.py @@ -5,7 +5,7 @@ import warnings warnings.warn("IPython.lib.kernel moved to IPython.kernel.connect in IPython 1.0," - "and will be removed in IPython 6.0.", + " and will be removed in IPython 6.0.", DeprecationWarning ) From bd4fcf7960d341430c782bbb046f51cb41c3ba76 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 5 Jan 2016 17:36:36 +0100 Subject: [PATCH 0055/4859] ensure deprecated_subcommands is defined on the base Application class cased AttributeError on subclasses other than TerminalIPythonApp --- IPython/core/application.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 07a393a6045..86cfdcd3306 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -194,7 +194,9 @@ def __init__(self, **kwargs): #------------------------------------------------------------------------- # Various stages of Application creation #------------------------------------------------------------------------- - + + deprecated_subcommands = {} + def initialize_subcommand(self, subc, argv=None): if subc in self.deprecated_subcommands: import time From 3c45efca15c0d447a4cfd78239e6347a4a1a9da0 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 7 Jan 2016 12:01:25 +0100 Subject: [PATCH 0056/4859] add deprecated shim for IPython.Config it was accidentally removed altogether in 4.0 --- IPython/__init__.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/IPython/__init__.py b/IPython/__init__.py index 6179b2c77f0..cd7d1e9b672 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -22,6 +22,7 @@ import os import sys +import warnings #----------------------------------------------------------------------------- # Setup everything @@ -143,3 +144,14 @@ def start_kernel(argv=None, **kwargs): from IPython.kernel.zmq.kernelapp import launch_new_instance return launch_new_instance(argv=argv, **kwargs) +# deprecated shim for IPython.Config +import traitlets.config +class Config(traitlets.config.Config): + def __init__(self, *args, **kwargs): + warnings.warn( + "IPython.Config is deprecated and will be removed in IPython 5." + " Use traitlets.config.Config.", + DeprecationWarning, stacklevel=2, + ) + super(Config, self).__init__(*args, **kwargs) + From c3f3e5fa533bc7f89cd64d946625fbe1c38c9207 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 8 Jan 2016 14:14:03 +0100 Subject: [PATCH 0057/4859] document existing events --- docs/source/config/callbacks.rst | 55 +++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/docs/source/config/callbacks.rst b/docs/source/config/callbacks.rst index 11f7db62c7c..ad99a6f3b85 100644 --- a/docs/source/config/callbacks.rst +++ b/docs/source/config/callbacks.rst @@ -1,6 +1,9 @@ -===================== -Registering callbacks -===================== +.. _events: +.. _callbacks: + +============== +IPython Events +============== Extension code can register callbacks functions which will be called on specific events within the IPython code. You can see the current list of available @@ -27,9 +30,51 @@ For example:: ip.events.register('pre_execute', vw.pre_execute) ip.events.register('post_execute', vw.post_execute) -.. note:: - This API is experimental in IPython 2.0, and may be revised in future versions. +Events +====== + +These are the events IPython will emit. Callbacks will be passed no arguments, unless otherwise specified. + +shell_initialized +----------------- + +.. code-block:: python + + def shell_initialized(ipython): + ... + +This event is triggered only once, at the end of setting up IPython. +Extensions registered to load by default as part of configuration can use this to execute code to finalize setup. +Callbacks will be passed the InteractiveShell instance. + +pre_run_cell +------------ + +``pre_run_cell`` fires prior to interactive execution (e.g. a cell in a notebook). +It can be used to note the state prior to execution, and keep track of changes. + +pre_execute +----------- + +``pre_execute`` is like ``pre_run_cell``, but is triggered prior to *any* execution. +Sometimes code can be executed by libraries, etc. which +skipping the history/display mechanisms, in which cases ``pre_run_cell`` will not fire. + +post_run_cell +------------- + +``post_run_cell`` runs after interactive execution (e.g. a cell in a notebook). +It can be used to cleanup or notify or perform operations on any side effects produced during execution. +For instance, the inline matplotlib backend uses this event to display any figures created but not explicitly displayed during the course of the cell. + + +post_execute +------------ + +The same as ``pre_execute``, ``post_execute`` is like ``post_run_cell``, +but fires for *all* executions, not just interactive ones. + .. seealso:: From 53d80d4c0420ffb72c32ef567c7bb48527714c3b Mon Sep 17 00:00:00 2001 From: Guillaume DOUMENC Date: Sun, 10 Jan 2016 11:50:35 +0100 Subject: [PATCH 0058/4859] Update ultratb.py --- IPython/core/ultratb.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index e8e1d2ec297..d870e34728e 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1094,12 +1094,14 @@ def structured_traceback(self, etype, evalue, etb, tb_offset=None, etype, evalue, etb = exception else: evalue = None + chained_exc_ids = set() while evalue: formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context, chained_exceptions_tb_offset) exception = self.get_parts_of_chained_exception(evalue) - if exception: + if exception and not id(exception[1]) in chained_exc_ids: + chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__) etype, evalue, etb = exception else: From de68bf5d79f4df17dd8989e0b1a85ed3af6ef330 Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Sun, 10 Jan 2016 13:42:18 -0700 Subject: [PATCH 0059/4859] Fix max_seq_length input to RepresentationPrinter max_seq_length is passed to RepresentationPrinter as a positional argument but the order is not correct for RepresentationPrinter's __init__. Pass max_seq_length as a keyword argument instead. --- IPython/lib/pretty.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 028c3b2318d..1465a6adb96 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -124,7 +124,7 @@ def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SE Pretty print the object's representation. """ stream = CUnicodeIO() - printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length) + printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length) printer.pretty(obj) printer.flush() return stream.getvalue() @@ -134,7 +134,7 @@ def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SE """ Like `pretty` but print to stdout. """ - printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length) + printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length) printer.pretty(obj) printer.flush() sys.stdout.write(newline) From 6addf4a763148174820f15f1fb3d289c4b4279d1 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 10 Jan 2016 17:01:28 +0000 Subject: [PATCH 0060/4859] Limit unwrapping __wrapped__ attributes to prevent infinite loops Closes gh-9122 Some objects lie. Some objects lie again and again and again. Don't trust the objects. --- IPython/core/oinspect.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index f819990fc26..216f5e78e6d 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -280,9 +280,21 @@ def call_tip(oinfo, format_call=True): def _get_wrapped(obj): - """Get the original object if wrapped in one or more @decorators""" + """Get the original object if wrapped in one or more @decorators + + Some objects automatically construct similar objects on any unrecognised + attribute access (e.g. unittest.mock.call). To protect against infinite loops, + this will arbitrarily cut off after 100 levels of obj.__wrapped__ + attribute access. --TK, Jan 2016 + """ + orig_obj = obj + i = 0 while safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ + i += 1 + if i > 100: + # __wrapped__ is probably a lie, so return the thing we started with + return orig_obj return obj def find_file(obj): From e8feaa8d3a82da14cfb54a0000d3cfa1c1958ea4 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 11 Jan 2016 11:41:37 +0000 Subject: [PATCH 0061/4859] Add test for infinite looping on attribute access --- IPython/core/tests/test_oinspect.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index e868730b23f..c625a745779 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -186,6 +186,23 @@ def __bool__(self): raise NotImplementedError('Must be implemented') +class SerialLiar(object): + """Attribute accesses always get another copy of the same class. + + unittest.mock.call does something similar, but it's not ideal for testing + as the failure mode is to eat all your RAM. This gives up after 10k levels. + """ + def __init__(self, max_fibbing_twig, lies_told=0): + if lies_told > 10000: + raise RuntimeError('Nose too long, honesty is the best policy') + self.max_fibbing_twig = max_fibbing_twig + self.lies_told = lies_told + max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told) + + def __getattr__(self, item): + return SerialLiar(self.max_fibbing_twig, self.lies_told + 1) + + def check_calltip(obj, name, call, docstring): """Generic check pattern all calltip tests will use""" info = inspector.info(obj, name) @@ -297,6 +314,14 @@ def test_info_awkward(): def test_bool_raise(): inspector.info(NoBoolCall()) +def test_info_serialliar(): + fib_tracker = [0] + i = 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 + nt.assert_less(fib_tracker[0], 9000) + def test_calldef_none(): # We should ignore __call__ for all of these. for obj in [f, SimpleClass().method, any, str.upper]: From 85bfacfd2213705f64c57a06d36ab9759b710c34 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 22 Dec 2015 17:30:58 +0000 Subject: [PATCH 0062/4859] Initial code for new InteractiveShell subclass using prompt_toolkit --- IPython/terminal/ptshell.py | 64 +++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 IPython/terminal/ptshell.py diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py new file mode 100644 index 00000000000..f059f7055ff --- /dev/null +++ b/IPython/terminal/ptshell.py @@ -0,0 +1,64 @@ +from IPython.core.interactiveshell import InteractiveShell + +from prompt_toolkit.buffer import Buffer +from prompt_toolkit.shortcuts import create_prompt_layout +from prompt_toolkit.filters import Condition +from prompt_toolkit.interface import AcceptAction, Application, CommandLineInterface +from prompt_toolkit.layout.lexers import PygmentsLexer + +from pygments.lexers import Python3Lexer +from pygments.token import Token + + +class PTInteractiveShell(InteractiveShell): + def _multiline(self, cli): + doc = cli.current_buffer.document + if not doc.on_last_line: + cli.run_in_terminal(lambda: print('Not on last line')) + return False + status, indent = self.input_splitter.check_complete(doc.text) + return status == 'incomplete' + + def _multiline2(self): + return self._multiline(self.pt_cli) + + pt_cli = None + + def get_prompt_tokens(self, cli): + return [ + (Token.Prompt, 'In ['), + (Token.Prompt, str(self.execution_count)), + (Token.Prompt, ']: '), + ] + + + def init_prompt_toolkit_cli(self): + layout = create_prompt_layout( + get_prompt_tokens=self.get_prompt_tokens, + lexer=PygmentsLexer(Python3Lexer), + multiline=Condition(self._multiline), + ) + buffer = Buffer( + is_multiline=Condition(self._multiline2), + accept_action=AcceptAction.RETURN_DOCUMENT, + ) + app = Application(layout=layout, buffer=buffer) + self.pt_cli = CommandLineInterface(app) + + def __init__(self, *args, **kwargs): + super(PTInteractiveShell, self).__init__(*args, **kwargs) + self.init_prompt_toolkit_cli() + self.keep_running = True + + def ask_exit(self): + self.keep_running = False + + def interact(self): + while self.keep_running: + document = self.pt_cli.run() + if document: + self.run_cell(document.text) + + +if __name__ == '__main__': + PTInteractiveShell().interact() From a9b0c6ca598179c4c07291f3cc4111a021d92078 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 23 Dec 2015 16:44:43 +0000 Subject: [PATCH 0063/4859] Refine multiline behaviour --- IPython/terminal/ptshell.py | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index f059f7055ff..bf1c6ed2730 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,9 +1,9 @@ from IPython.core.interactiveshell import InteractiveShell -from prompt_toolkit.buffer import Buffer -from prompt_toolkit.shortcuts import create_prompt_layout -from prompt_toolkit.filters import Condition -from prompt_toolkit.interface import AcceptAction, Application, CommandLineInterface +from prompt_toolkit.shortcuts import create_prompt_application +from prompt_toolkit.interface import CommandLineInterface +from prompt_toolkit.key_binding.manager import KeyBindingManager +from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import PygmentsLexer from pygments.lexers import Python3Lexer @@ -11,17 +11,6 @@ class PTInteractiveShell(InteractiveShell): - def _multiline(self, cli): - doc = cli.current_buffer.document - if not doc.on_last_line: - cli.run_in_terminal(lambda: print('Not on last line')) - return False - status, indent = self.input_splitter.check_complete(doc.text) - return status == 'incomplete' - - def _multiline2(self): - return self._multiline(self.pt_cli) - pt_cli = None def get_prompt_tokens(self, cli): @@ -33,16 +22,27 @@ def get_prompt_tokens(self, cli): def init_prompt_toolkit_cli(self): - layout = create_prompt_layout( - get_prompt_tokens=self.get_prompt_tokens, - lexer=PygmentsLexer(Python3Lexer), - multiline=Condition(self._multiline), - ) - buffer = Buffer( - is_multiline=Condition(self._multiline2), - accept_action=AcceptAction.RETURN_DOCUMENT, + kbmanager = KeyBindingManager.for_prompt() + @kbmanager.registry.add_binding(Keys.ControlJ) # Ctrl+J == Enter, seemingly + def _(event): + b = event.current_buffer + if not b.document.on_last_line: + b.newline() + return + + status, indent = self.input_splitter.check_complete(b.document.text) + + if (status != 'incomplete') and b.accept_action.is_returnable: + b.accept_action.validate_and_handle(event.cli, b) + else: + b.insert_text('\n' + (' ' * indent)) + + app = create_prompt_application(multiline=True, + lexer=PygmentsLexer(Python3Lexer), + get_prompt_tokens=self.get_prompt_tokens, + key_bindings_registry=kbmanager.registry, ) - app = Application(layout=layout, buffer=buffer) + self.pt_cli = CommandLineInterface(app) def __init__(self, *args, **kwargs): From f52460428307785b7c5440cb62100f85fd022269 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 23 Dec 2015 16:46:01 +0000 Subject: [PATCH 0064/4859] Store history so prompt number increases --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index bf1c6ed2730..cfbb8c5f273 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -57,7 +57,7 @@ def interact(self): while self.keep_running: document = self.pt_cli.run() if document: - self.run_cell(document.text) + self.run_cell(document.text, store_history=True) if __name__ == '__main__': From 239389ae8394bc72f4ee3131880d8318729b343c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Jan 2016 13:05:38 +0000 Subject: [PATCH 0065/4859] Hook up command history and populate it from IPython's history DB --- IPython/terminal/ptshell.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index cfbb8c5f273..d78cea338f1 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,5 +1,6 @@ from IPython.core.interactiveshell import InteractiveShell +from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager @@ -35,12 +36,23 @@ def _(event): if (status != 'incomplete') and b.accept_action.is_returnable: b.accept_action.validate_and_handle(event.cli, b) else: - b.insert_text('\n' + (' ' * indent)) + b.insert_text('\n' + (' ' * (indent or 0))) + + # Pre-populate history from IPython's history database + history = InMemoryHistory() + last_cell = u"" + for _, _, cell in self.history_manager.get_tail(self.history_load_length, + include_latest=True): + # Ignore blank lines and consecutive duplicates + cell = cell.rstrip() + if cell and (cell != last_cell): + history.append(cell) app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer), get_prompt_tokens=self.get_prompt_tokens, key_bindings_registry=kbmanager.registry, + history=history, ) self.pt_cli = CommandLineInterface(app) From e870f74a0ccace04051f0687767c3758b3274b39 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Jan 2016 13:18:39 +0000 Subject: [PATCH 0066/4859] Do sensible things on Ctrl-C and Ctrl-D --- IPython/terminal/ptshell.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index d78cea338f1..49884951f74 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -38,6 +38,10 @@ def _(event): else: b.insert_text('\n' + (' ' * (indent or 0))) + @kbmanager.registry.add_binding(Keys.ControlC) + def _(event): + event.current_buffer.reset() + # Pre-populate history from IPython's history database history = InMemoryHistory() last_cell = u"" @@ -67,9 +71,15 @@ def ask_exit(self): def interact(self): while self.keep_running: - document = self.pt_cli.run() - if document: - self.run_cell(document.text, store_history=True) + try: + document = self.pt_cli.run() + except EOFError: + if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): + self.ask_exit() + + else: + if document: + self.run_cell(document.text, store_history=True) if __name__ == '__main__': From db2ff6f587b9d7ee1036832c68205df20c7ff9cc Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Jan 2016 14:08:17 +0000 Subject: [PATCH 0067/4859] Add completion support --- IPython/terminal/ptshell.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 49884951f74..734b5c9f6d5 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,5 +1,6 @@ from IPython.core.interactiveshell import InteractiveShell +from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application from prompt_toolkit.interface import CommandLineInterface @@ -11,6 +12,21 @@ from pygments.token import Token +class IPythonPTCompleter(Completer): + """Adaptor to provide IPython completions to prompt_toolkit""" + def __init__(self, ipy_completer): + self.ipy_completer = ipy_completer + + def get_completions(self, document, complete_event): + used, matches = self.ipy_completer.complete( + line_buffer=document.current_line, + cursor_pos=document.cursor_position_col + ) + start_pos = -len(used) + for m in matches: + yield Completion(m, start_position=start_pos) + + class PTInteractiveShell(InteractiveShell): pt_cli = None @@ -57,6 +73,7 @@ def _(event): get_prompt_tokens=self.get_prompt_tokens, key_bindings_registry=kbmanager.registry, history=history, + completer=IPythonPTCompleter(self.Completer), ) self.pt_cli = CommandLineInterface(app) @@ -83,4 +100,4 @@ def interact(self): if __name__ == '__main__': - PTInteractiveShell().interact() + PTInteractiveShell.instance().interact() From ba5734e80ca6c629ee5a6b90f275acaf04edd59d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Jan 2016 14:20:34 +0000 Subject: [PATCH 0068/4859] Improve order of completions --- IPython/core/completer.py | 56 ++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 4c793b43c17..7953dbb065a 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -170,41 +170,38 @@ def compress_user(path, tilde_expand, tilde_val): -def penalize_magics_key(word): - """key for sorting that penalizes magic commands in the ordering +def completions_sorting_key(word): + """key for sorting completions - Normal words are left alone. - - Magic commands have the initial % moved to the end, e.g. - %matplotlib is transformed as follows: - - %matplotlib -> matplotlib% - - [The choice of the final % is arbitrary.] - - Since "matplotlib" < "matplotlib%" as strings, - "timeit" will appear before the magic "%timeit" in the ordering - - For consistency, move "%%" to the end, so cell magics appear *after* - line magics with the same name. - - A check is performed that there are no other "%" in the string; - if there are, then the string is not a magic command and is left unchanged. + This does several things: + - Lowercase all completions, so they are sorted alphabetically with + upper and lower case words mingled + - Demote any completions starting with underscores to the end + - Insert any %magic and %%cellmagic completions in the alphabetical order + by their name """ + # Case insensitive sort + word = word.lower() - # Move any % signs from start to end of the key - # provided there are no others elsewhere in the string + prio1, prio2 = 0, 0 - if word[:2] == "%%": - if not "%" in word[2:]: - return word[2:] + "%%" + if word.startswith('__'): + prio1 = 2 + elif word.startswith('_'): + prio1 = 1 - if word[:1] == "%": + if word.startswith('%%'): + # If there's another % in there, this is something else, so leave it alone + if not "%" in word[2:]: + word = word[2:] + prio2 = 2 + elif word.startswith('%'): if not "%" in word[1:]: - return word[1:] + "%" - - return word + word = word[1:] + prio2 = 1 + + return prio1, word, prio2 @undoc @@ -1206,8 +1203,7 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): # simply collapse the dict into a list for readline, but we'd have # richer completion semantics in other evironments. - # use penalize_magics_key to put magics after variables with same name - self.matches = sorted(set(self.matches), key=penalize_magics_key) + self.matches = sorted(set(self.matches), key=completions_sorting_key) #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg return text, self.matches From fbb4e634fed001b43a71d76d38012def5ee1a1c7 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Jan 2016 14:54:50 +0000 Subject: [PATCH 0069/4859] Nicer default colours --- IPython/terminal/ptshell.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 734b5c9f6d5..4dee5d19257 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -7,6 +7,7 @@ from prompt_toolkit.key_binding.manager import KeyBindingManager from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import PygmentsLexer +from prompt_toolkit.styles import PygmentsStyle from pygments.lexers import Python3Lexer from pygments.token import Token @@ -33,7 +34,7 @@ class PTInteractiveShell(InteractiveShell): def get_prompt_tokens(self, cli): return [ (Token.Prompt, 'In ['), - (Token.Prompt, str(self.execution_count)), + (Token.PromptNum, str(self.execution_count)), (Token.Prompt, ']: '), ] @@ -68,12 +69,20 @@ def _(event): if cell and (cell != last_cell): history.append(cell) + style = PygmentsStyle.from_defaults({ + Token.Prompt: '#009900', + Token.PromptNum: '#00ff00 bold', + Token.Number: '#007700', + Token.Operator: '#bbbbbb', + }) + app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer), get_prompt_tokens=self.get_prompt_tokens, key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), + style=style, ) self.pt_cli = CommandLineInterface(app) From 342b17513a11fe906ff0a25b39ce7dee8beb0c64 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 11 Jan 2016 14:08:58 +0000 Subject: [PATCH 0070/4859] Add blank line before input prompt --- IPython/terminal/ptshell.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4dee5d19257..c846638b701 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -106,6 +106,7 @@ def interact(self): else: if document: self.run_cell(document.text, store_history=True) + print(self.separate_in, end='') if __name__ == '__main__': From e778cbacc703f6204637c45748340a5ce093e7f8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 13:59:39 +0000 Subject: [PATCH 0071/4859] Turn out prompt & traceback colours on when using prompt_toolkit --- IPython/terminal/ptshell.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c846638b701..881d76c426e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -29,6 +29,8 @@ def get_completions(self, document, complete_event): class PTInteractiveShell(InteractiveShell): + colors_force = True + pt_cli = None def get_prompt_tokens(self, cli): From 55845333e1d253107321299801fc055b9a46e885 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 14:06:33 +0000 Subject: [PATCH 0072/4859] Move printing blank line to before each input prompt --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 881d76c426e..65d82de0e9b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -99,6 +99,7 @@ def ask_exit(self): def interact(self): while self.keep_running: + print(self.separate_in, end='') try: document = self.pt_cli.run() except EOFError: @@ -108,7 +109,6 @@ def interact(self): else: if document: self.run_cell(document.text, store_history=True) - print(self.separate_in, end='') if __name__ == '__main__': From 4a9dcfdc275f54b18cb0a361857117f7b8a5e09c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 14:26:09 +0000 Subject: [PATCH 0073/4859] Don't try to complete on an empty line --- IPython/terminal/ptshell.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 65d82de0e9b..364ec7b1ebd 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -19,6 +19,9 @@ def __init__(self, ipy_completer): self.ipy_completer = ipy_completer def get_completions(self, document, complete_event): + if not document.current_line.strip(): + return + used, matches = self.ipy_completer.complete( line_buffer=document.current_line, cursor_pos=document.cursor_position_col From 535e24011597ff5c9c15cc423415bf259d759fbd Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 15:45:53 +0000 Subject: [PATCH 0074/4859] Only use our Enter handling when the default buffer is active Fixes Ctrl-R search --- IPython/terminal/ptshell.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 364ec7b1ebd..3b5e436f28e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,6 +1,8 @@ from IPython.core.interactiveshell import InteractiveShell from prompt_toolkit.completion import Completer, Completion +from prompt_toolkit.enums import DEFAULT_BUFFER +from prompt_toolkit.filters import HasFocus, HasSelection from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application from prompt_toolkit.interface import CommandLineInterface @@ -46,7 +48,9 @@ def get_prompt_tokens(self, cli): def init_prompt_toolkit_cli(self): kbmanager = KeyBindingManager.for_prompt() - @kbmanager.registry.add_binding(Keys.ControlJ) # Ctrl+J == Enter, seemingly + # Ctrl+J == Enter, seemingly + @kbmanager.registry.add_binding(Keys.ControlJ, + filter=HasFocus(DEFAULT_BUFFER) & ~HasSelection()) def _(event): b = event.current_buffer if not b.document.on_last_line: From 904d56ef88ea9d98dff4bc43149527792f5a3b8b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 15:52:14 +0000 Subject: [PATCH 0075/4859] Enable history search with up arrow --- IPython/terminal/ptshell.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3b5e436f28e..b63c0fe448e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -91,6 +91,7 @@ def _(event): key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), + enable_history_search=True, style=style, ) From 3d5a073dae0e0976c49131d0d51ce28900b1e3d5 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jan 2016 16:30:21 +0000 Subject: [PATCH 0076/4859] Improve default colours for light & dark terminal backgrounds --- IPython/terminal/ptshell.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index b63c0fe448e..9cf1da8c795 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -82,7 +82,8 @@ def _(event): Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', Token.Number: '#007700', - Token.Operator: '#bbbbbb', + Token.Operator: 'noinherit', + Token.String: '#BB6622', }) app = create_prompt_application(multiline=True, From e9ee3ec0000a5331a264337a30e5f02cea9c2723 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 14 Jan 2016 17:56:07 +0000 Subject: [PATCH 0077/4859] Add config option for vi mode --- IPython/terminal/ptshell.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 9cf1da8c795..36f6c3cb7f6 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,4 +1,5 @@ from IPython.core.interactiveshell import InteractiveShell +from traitlets import Bool from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER @@ -7,6 +8,8 @@ from prompt_toolkit.shortcuts import create_prompt_application from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager +from prompt_toolkit.key_binding.vi_state import InputMode +from prompt_toolkit.key_binding.bindings.vi import ViStateFilter from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import PygmentsLexer from prompt_toolkit.styles import PygmentsStyle @@ -38,6 +41,10 @@ class PTInteractiveShell(InteractiveShell): pt_cli = None + vi_mode = Bool(False, config=True, + help="Use vi style keybindings at the prompt", + ) + def get_prompt_tokens(self, cli): return [ (Token.Prompt, 'In ['), @@ -47,10 +54,14 @@ def get_prompt_tokens(self, cli): def init_prompt_toolkit_cli(self): - kbmanager = KeyBindingManager.for_prompt() + kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode) + insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT) # Ctrl+J == Enter, seemingly @kbmanager.registry.add_binding(Keys.ControlJ, - filter=HasFocus(DEFAULT_BUFFER) & ~HasSelection()) + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + )) def _(event): b = event.current_buffer if not b.document.on_last_line: From cde57a32a66a50637361122a0e190d7c65544058 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 14 Jan 2016 18:17:43 +0000 Subject: [PATCH 0078/4859] Config options for syntax higlighting style --- IPython/terminal/ptshell.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 36f6c3cb7f6..64e6659a9ab 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,5 +1,5 @@ from IPython.core.interactiveshell import InteractiveShell -from traitlets import Bool +from traitlets import Bool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER @@ -14,6 +14,7 @@ from prompt_toolkit.layout.lexers import PygmentsLexer from prompt_toolkit.styles import PygmentsStyle +from pygments.styles import get_style_by_name from pygments.lexers import Python3Lexer from pygments.token import Token @@ -45,6 +46,14 @@ class PTInteractiveShell(InteractiveShell): help="Use vi style keybindings at the prompt", ) + highlighting_style = Unicode('', config=True, + help="The name of a Pygments style to use for syntax highlighting" + ) + + highlighting_style_overrides = Dict(config=True, + help="Override highlighting format for specific tokens" + ) + def get_prompt_tokens(self, cli): return [ (Token.Prompt, 'In ['), @@ -89,13 +98,22 @@ def _(event): if cell and (cell != last_cell): history.append(cell) - style = PygmentsStyle.from_defaults({ + style_overrides = { Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', - Token.Number: '#007700', - Token.Operator: 'noinherit', - Token.String: '#BB6622', - }) + } + if self.highlighting_style: + style_cls = get_style_by_name(self.highlighting_style) + else: + style_cls = get_style_by_name('default') + style_overrides.update({ + Token.Number: '#007700', + Token.Operator: 'noinherit', + Token.String: '#BB6622', + }) + style_overrides.update(self.highlighting_style_overrides) + style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, + style_dict=style_overrides) app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer), From 0cb9e90494c27bb2aee1ff046348a0f2eeeb44c3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 14 Jan 2016 18:26:19 +0000 Subject: [PATCH 0079/4859] Python 2.7 support & highlighting in prompt_toolkit interface --- IPython/terminal/ptshell.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 64e6659a9ab..94a073f67f6 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,4 +1,8 @@ +"""IPython terminal interface using prompt_toolkit in place of readline""" +from __future__ import print_function + from IPython.core.interactiveshell import InteractiveShell +from IPython.utils.py3compat import PY3 from traitlets import Bool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion @@ -15,7 +19,7 @@ from prompt_toolkit.styles import PygmentsStyle from pygments.styles import get_style_by_name -from pygments.lexers import Python3Lexer +from pygments.lexers import Python3Lexer, PythonLexer from pygments.token import Token @@ -116,7 +120,7 @@ def _(event): style_dict=style_overrides) app = create_prompt_application(multiline=True, - lexer=PygmentsLexer(Python3Lexer), + lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer), get_prompt_tokens=self.get_prompt_tokens, key_bindings_registry=kbmanager.registry, history=history, From 10a6c79fcec6274be607599f9fe4cc7e4642d257 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 15 Jan 2016 11:33:07 +0100 Subject: [PATCH 0080/4859] remove unneeded requirements.txt --- .travis.yml | 2 +- requirements.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 requirements.txt diff --git a/.travis.yml b/.travis.yml index d9d32ae9255..096bce0df2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ before_install: - git clone --quiet --depth 1 https://github.com/minrk/travis-wheels travis-wheels - 'if [[ $GROUP != js* ]]; then COVERAGE=""; fi' install: - - pip install -f travis-wheels/wheelhouse -r requirements.txt -e file://$PWD#egg=ipython[test] + - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] - pip install codecov script: - cd /tmp && iptest --coverage xml && cd - diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 32ea2ce2cc6..00000000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ --e git+https://github.com/ipython/traitlets.git#egg=traitlets From 995b7940fcf75078804b44fdd9feef5c44abac6a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 16 Jan 2016 10:55:39 +0000 Subject: [PATCH 0081/4859] Add continuation prompts --- IPython/terminal/ptshell.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 94a073f67f6..5742ddbe552 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -65,6 +65,11 @@ def get_prompt_tokens(self, cli): (Token.Prompt, ']: '), ] + def get_continuation_tokens(self, cli, width): + return [ + (Token.Prompt, (' ' * (width - 2)) + ': '), + ] + def init_prompt_toolkit_cli(self): kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode) @@ -122,6 +127,7 @@ def _(event): app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer), get_prompt_tokens=self.get_prompt_tokens, + get_continuation_tokens=self.get_continuation_tokens, key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), From c0fffd17e4392b1d2434182406d5245a7dc65c99 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 16 Jan 2016 17:28:14 +0000 Subject: [PATCH 0082/4859] Write & borrow some inputhooks for prompt_toolkit --- IPython/terminal/pt_inputhooks/__init__.py | 16 ++++ IPython/terminal/pt_inputhooks/gtk.py | 55 +++++++++++++ IPython/terminal/pt_inputhooks/gtk3.py | 12 +++ IPython/terminal/pt_inputhooks/qt.py | 11 +++ IPython/terminal/pt_inputhooks/tk.py | 93 ++++++++++++++++++++++ IPython/terminal/ptshell.py | 19 ++++- 6 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 IPython/terminal/pt_inputhooks/__init__.py create mode 100644 IPython/terminal/pt_inputhooks/gtk.py create mode 100644 IPython/terminal/pt_inputhooks/gtk3.py create mode 100644 IPython/terminal/pt_inputhooks/qt.py create mode 100644 IPython/terminal/pt_inputhooks/tk.py diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py new file mode 100644 index 00000000000..6ad691905cd --- /dev/null +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -0,0 +1,16 @@ +import importlib +import os + +aliases = { + 'qt4': 'qt' +} + +def get_inputhook_func(gui): + if gui in aliases: + return get_inputhook_func(aliases[gui]) + + if gui == 'qt5': + os.environ['QT_API'] = 'pyqt5' + + mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui) + return mod.inputhook diff --git a/IPython/terminal/pt_inputhooks/gtk.py b/IPython/terminal/pt_inputhooks/gtk.py new file mode 100644 index 00000000000..49bfeb3ce2b --- /dev/null +++ b/IPython/terminal/pt_inputhooks/gtk.py @@ -0,0 +1,55 @@ +# Code borrowed from python-prompt-toolkit examples +# https://github.com/jonathanslenders/python-prompt-toolkit/blob/77cdcfbc7f4b4c34a9d2f9a34d422d7152f16209/examples/inputhook.py + +# Copyright (c) 2014, Jonathan Slenders +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# * Neither the name of the {organization} nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +PyGTK input hook for prompt_toolkit. + +Listens on the pipe prompt_toolkit sets up for a notification that it should +return control to the terminal event loop. +""" + +import gtk, gobject + +def inputhook(context): + """ + When the eventloop of prompt-toolkit is idle, call this inputhook. + + This will run the GTK main loop until the file descriptor + `context.fileno()` becomes ready. + + :param context: An `InputHookContext` instance. + """ + def _main_quit(*a, **kw): + gtk.main_quit() + return False + + gobject.io_add_watch(context.fileno(), gobject.IO_IN, _main_quit) + gtk.main() diff --git a/IPython/terminal/pt_inputhooks/gtk3.py b/IPython/terminal/pt_inputhooks/gtk3.py new file mode 100644 index 00000000000..5c6c545457b --- /dev/null +++ b/IPython/terminal/pt_inputhooks/gtk3.py @@ -0,0 +1,12 @@ +"""prompt_toolkit input hook for GTK 3 +""" + +from gi.repository import Gtk, GLib + +def _main_quit(*args, **kwargs): + Gtk.main_quit() + return False + +def inputhook(context): + GLib.io_add_watch(context.fileno(), GLib.IO_IN, _main_quit) + Gtk.main() diff --git a/IPython/terminal/pt_inputhooks/qt.py b/IPython/terminal/pt_inputhooks/qt.py new file mode 100644 index 00000000000..1fd4e9290f3 --- /dev/null +++ b/IPython/terminal/pt_inputhooks/qt.py @@ -0,0 +1,11 @@ +from IPython.external.qt_for_kernel import QtCore, QtGui + +def inputhook(context): + app = QtCore.QCoreApplication.instance() + if not app: + return + event_loop = QtCore.QEventLoop(app) + notifier = QtCore.QSocketNotifier(context.fileno(), QtCore.QSocketNotifier.Read) + notifier.setEnabled(True) + notifier.activated.connect(event_loop.exit) + event_loop.exec_() diff --git a/IPython/terminal/pt_inputhooks/tk.py b/IPython/terminal/pt_inputhooks/tk.py new file mode 100644 index 00000000000..24313a8396a --- /dev/null +++ b/IPython/terminal/pt_inputhooks/tk.py @@ -0,0 +1,93 @@ +# Code borrowed from ptpython +# https://github.com/jonathanslenders/ptpython/blob/86b71a89626114b18898a0af463978bdb32eeb70/ptpython/eventloop.py + +# Copyright (c) 2015, Jonathan Slenders +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, this +# list of conditions and the following disclaimer in the documentation and/or +# other materials provided with the distribution. +# +# * Neither the name of the {organization} nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +""" +Wrapper around the eventloop that gives some time to the Tkinter GUI to process +events when it's loaded and while we are waiting for input at the REPL. This +way we don't block the UI of for instance ``turtle`` and other Tk libraries. + +(Normally Tkinter registeres it's callbacks in ``PyOS_InputHook`` to integrate +in readline. ``prompt-toolkit`` doesn't understand that input hook, but this +will fix it for Tk.) +""" +import time + +import _tkinter +try: + import tkinter +except ImportError: + import Tkinter as tkinter # Python 2 + +def inputhook(inputhook_context): + """ + Inputhook for Tk. + Run the Tk eventloop until prompt-toolkit needs to process the next input. + """ + # Get the current TK application. + root = tkinter._default_root + + def wait_using_filehandler(): + """ + Run the TK eventloop until the file handler that we got from the + inputhook becomes readable. + """ + # Add a handler that sets the stop flag when `prompt-toolkit` has input + # to process. + stop = [False] + def done(*a): + stop[0] = True + + root.createfilehandler(inputhook_context.fileno(), _tkinter.READABLE, done) + + # Run the TK event loop as long as we don't receive input. + while root.dooneevent(_tkinter.ALL_EVENTS): + if stop[0]: + break + + root.deletefilehandler(inputhook_context.fileno()) + + def wait_using_polling(): + """ + Windows TK doesn't support 'createfilehandler'. + So, run the TK eventloop and poll until input is ready. + """ + while not inputhook_context.input_is_ready(): + while root.dooneevent(_tkinter.ALL_EVENTS | _tkinter.DONT_WAIT): + pass + # Sleep to make the CPU idle, but not too long, so that the UI + # stays responsive. + time.sleep(.01) + + if root is not None: + if hasattr(root, 'createfilehandler'): + wait_using_filehandler() + else: + wait_using_polling() diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 5742ddbe552..babaa0756dc 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -9,7 +9,7 @@ from prompt_toolkit.enums import DEFAULT_BUFFER from prompt_toolkit.filters import HasFocus, HasSelection from prompt_toolkit.history import InMemoryHistory -from prompt_toolkit.shortcuts import create_prompt_application +from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager from prompt_toolkit.key_binding.vi_state import InputMode @@ -22,6 +22,8 @@ from pygments.lexers import Python3Lexer, PythonLexer from pygments.token import Token +from .pt_inputhooks import get_inputhook_func + class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" @@ -40,7 +42,6 @@ def get_completions(self, document, complete_event): for m in matches: yield Completion(m, start_position=start_pos) - class PTInteractiveShell(InteractiveShell): colors_force = True @@ -70,7 +71,6 @@ def get_continuation_tokens(self, cli, width): (Token.Prompt, (' ' * (width - 2)) + ': '), ] - def init_prompt_toolkit_cli(self): kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode) insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT) @@ -135,7 +135,8 @@ def _(event): style=style, ) - self.pt_cli = CommandLineInterface(app) + self.pt_cli = CommandLineInterface(app, + eventloop=create_eventloop(self.inputhook)) def __init__(self, *args, **kwargs): super(PTInteractiveShell, self).__init__(*args, **kwargs) @@ -158,6 +159,16 @@ def interact(self): if document: self.run_cell(document.text, store_history=True) + _inputhook = None + def inputhook(self, context): + if self._inputhook is not None: + self._inputhook(context) + + def enable_gui(self, gui=None): + if gui: + self._inputhook = get_inputhook_func(gui) + else: + self._inputhook = None if __name__ == '__main__': PTInteractiveShell.instance().interact() From 826a334fb097552d0114fa5d865f0bdffca3ac47 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 16 Jan 2016 20:39:51 +0000 Subject: [PATCH 0083/4859] Avoid loading readline in the kernel This bit of code was loading readline even when there was no need for it. In a Qt console or notebook, try: 'readline' in sys.modules 'gnureadline' in sys.modules I plan to rework this code more extensively once we've switched to prompt_toolkit, but for now, this little fix should make the kernel start slightly faster. --- IPython/core/magics/basic.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 67482425b16..7cf7898597a 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -334,23 +334,25 @@ def color_switch_err(name): # local shortcut shell = self.shell - import IPython.utils.rlineimpl as readline - if not shell.colors_force and \ - not readline.have_readline and \ - (sys.platform == "win32" or sys.platform == "cli"): - msg = """\ + + if not shell.colors_force: + if sys.platform in {'win32', 'cli'}: + import IPython.utils.rlineimpl as readline + if not readline.have_readline: + msg = """\ Proper color support under MS Windows requires the pyreadline library. You can find it at: http://ipython.org/pyreadline.html Defaulting color scheme to 'NoColor'""" - new_scheme = 'NoColor' - warn(msg) + new_scheme = 'NoColor' + warn(msg) - # readline option is 0 - if not shell.colors_force and not shell.has_readline: - new_scheme = 'NoColor' + elif not shell.has_readline: + # Coloured prompts get messed up without readline + # Will remove this check after switching to prompt_toolkit + new_scheme = 'NoColor' # Set prompt colors try: From c83a80eaa6215b5508bd9bbd605b8736cd760e8b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 17 Jan 2016 16:34:44 -0800 Subject: [PATCH 0084/4859] log.war deprecated --- IPython/core/profiledir.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py index 7818f4ed551..d8559309038 100644 --- a/IPython/core/profiledir.py +++ b/IPython/core/profiledir.py @@ -118,7 +118,7 @@ def check_startup_dir(self): src = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'README_STARTUP') if not os.path.exists(src): - self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src) + self.log.warning("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src) if os.path.exists(src) and not os.path.exists(readme): shutil.copy(src, readme) From a9ca5b1b43881bbdc1d4cb4686f66617667cee9e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 11:06:57 +0000 Subject: [PATCH 0085/4859] More tweaks to highlighting colours --- IPython/terminal/ptshell.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index babaa0756dc..4e04bcdf755 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -115,10 +115,16 @@ def _(event): style_cls = get_style_by_name(self.highlighting_style) else: style_cls = get_style_by_name('default') + # The default theme needs to be visible on both a dark background + # and a light background, because we can't tell what the terminal + # looks like. These tweaks to the default theme help with that. style_overrides.update({ Token.Number: '#007700', Token.Operator: 'noinherit', Token.String: '#BB6622', + Token.Name.Function: '#2080D0', + Token.Name.Class: 'bold #2080D0', + Token.Name.Namespace: 'bold #2080D0', }) style_overrides.update(self.highlighting_style_overrides) style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, From 48013ca5e8b0f7cf853e2b76b74b448169834f97 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 14:24:28 +0000 Subject: [PATCH 0086/4859] Add prompt_toolkit input hooks for wx --- IPython/terminal/pt_inputhooks/__init__.py | 2 +- IPython/terminal/pt_inputhooks/gtk.py | 1 + IPython/terminal/pt_inputhooks/wx.py | 148 +++++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 IPython/terminal/pt_inputhooks/wx.py diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index 6ad691905cd..94709ec1986 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -2,7 +2,7 @@ import os aliases = { - 'qt4': 'qt' + 'qt4': 'qt', } def get_inputhook_func(gui): diff --git a/IPython/terminal/pt_inputhooks/gtk.py b/IPython/terminal/pt_inputhooks/gtk.py index 49bfeb3ce2b..33600488bc1 100644 --- a/IPython/terminal/pt_inputhooks/gtk.py +++ b/IPython/terminal/pt_inputhooks/gtk.py @@ -35,6 +35,7 @@ Listens on the pipe prompt_toolkit sets up for a notification that it should return control to the terminal event loop. """ +from __future__ import absolute_import import gtk, gobject diff --git a/IPython/terminal/pt_inputhooks/wx.py b/IPython/terminal/pt_inputhooks/wx.py new file mode 100644 index 00000000000..4371b21cb47 --- /dev/null +++ b/IPython/terminal/pt_inputhooks/wx.py @@ -0,0 +1,148 @@ +"""Enable wxPython to be used interacively in prompt_toolkit +""" +from __future__ import absolute_import + +import sys +import signal +import time +from timeit import default_timer as clock +import wx + + +def inputhook_wx1(context): + """Run the wx event loop by processing pending events only. + + This approach seems to work, but its performance is not great as it + relies on having PyOS_InputHook called regularly. + """ + try: + app = wx.GetApp() + if app is not None: + assert wx.Thread_IsMain() + + # Make a temporary event loop and process system events until + # there are no more waiting, then allow idle events (which + # will also deal with pending or posted wx events.) + evtloop = wx.EventLoop() + ea = wx.EventLoopActivator(evtloop) + while evtloop.Pending(): + evtloop.Dispatch() + app.ProcessIdle() + del ea + except KeyboardInterrupt: + pass + return 0 + +class EventLoopTimer(wx.Timer): + + def __init__(self, func): + self.func = func + wx.Timer.__init__(self) + + def Notify(self): + self.func() + +class EventLoopRunner(object): + + def Run(self, time, input_is_ready): + self.input_is_ready = input_is_ready + self.evtloop = wx.EventLoop() + self.timer = EventLoopTimer(self.check_stdin) + self.timer.Start(time) + self.evtloop.Run() + + def check_stdin(self): + if self.input_is_ready(): + self.timer.Stop() + self.evtloop.Exit() + +def inputhook_wx2(context): + """Run the wx event loop, polling for stdin. + + This version runs the wx eventloop for an undetermined amount of time, + during which it periodically checks to see if anything is ready on + stdin. If anything is ready on stdin, the event loop exits. + + The argument to elr.Run controls how often the event loop looks at stdin. + This determines the responsiveness at the keyboard. A setting of 1000 + enables a user to type at most 1 char per second. I have found that a + setting of 10 gives good keyboard response. We can shorten it further, + but eventually performance would suffer from calling select/kbhit too + often. + """ + try: + app = wx.GetApp() + if app is not None: + assert wx.Thread_IsMain() + elr = EventLoopRunner() + # As this time is made shorter, keyboard response improves, but idle + # CPU load goes up. 10 ms seems like a good compromise. + elr.Run(time=10, # CHANGE time here to control polling interval + input_is_ready=context.input_is_ready) + except KeyboardInterrupt: + pass + return 0 + +def inputhook_wx3(context): + """Run the wx event loop by processing pending events only. + + This is like inputhook_wx1, but it keeps processing pending events + until stdin is ready. After processing all pending events, a call to + time.sleep is inserted. This is needed, otherwise, CPU usage is at 100%. + This sleep time should be tuned though for best performance. + """ + # We need to protect against a user pressing Control-C when IPython is + # idle and this is running. We trap KeyboardInterrupt and pass. + try: + app = wx.GetApp() + if app is not None: + assert wx.Thread_IsMain() + + # The import of wx on Linux sets the handler for signal.SIGINT + # to 0. This is a bug in wx or gtk. We fix by just setting it + # back to the Python default. + if not callable(signal.getsignal(signal.SIGINT)): + signal.signal(signal.SIGINT, signal.default_int_handler) + + evtloop = wx.EventLoop() + ea = wx.EventLoopActivator(evtloop) + t = clock() + while not context.input_is_ready(): + while evtloop.Pending(): + t = clock() + evtloop.Dispatch() + app.ProcessIdle() + # We need to sleep at this point to keep the idle CPU load + # low. However, if sleep to long, GUI response is poor. As + # a compromise, we watch how often GUI events are being processed + # and switch between a short and long sleep time. Here are some + # stats useful in helping to tune this. + # time CPU load + # 0.001 13% + # 0.005 3% + # 0.01 1.5% + # 0.05 0.5% + used_time = clock() - t + if used_time > 10.0: + # print 'Sleep for 1 s' # dbg + time.sleep(1.0) + elif used_time > 0.1: + # Few GUI events coming in, so we can sleep longer + # print 'Sleep for 0.05 s' # dbg + time.sleep(0.05) + else: + # Many GUI events coming in, so sleep only very little + time.sleep(0.001) + del ea + except KeyboardInterrupt: + pass + return 0 + +if sys.platform == 'darwin': + # On OSX, evtloop.Pending() always returns True, regardless of there being + # any events pending. As such we can't use implementations 1 or 3 of the + # inputhook as those depend on a pending/dispatch loop. + inputhook = inputhook_wx2 +else: + # This is our default implementation + inputhook = inputhook_wx3 From 1f47f59a7d4518e750009aedce596a150ad0a865 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 14:32:38 +0000 Subject: [PATCH 0087/4859] Add inputhook for pyglet --- IPython/terminal/pt_inputhooks/pyglet.py | 68 ++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 IPython/terminal/pt_inputhooks/pyglet.py diff --git a/IPython/terminal/pt_inputhooks/pyglet.py b/IPython/terminal/pt_inputhooks/pyglet.py new file mode 100644 index 00000000000..1c5ec442504 --- /dev/null +++ b/IPython/terminal/pt_inputhooks/pyglet.py @@ -0,0 +1,68 @@ +"""Enable pyglet to be used interacively with prompt_toolkit +""" +from __future__ import absolute_import + +import os +import sys +import time +from timeit import default_timer as clock +import pyglet + +# On linux only, window.flip() has a bug that causes an AttributeError on +# window close. For details, see: +# http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e + +if sys.platform.startswith('linux'): + def flip(window): + try: + window.flip() + except AttributeError: + pass +else: + def flip(window): + window.flip() + + +def inputhook(context): + """Run the pyglet event loop by processing pending events only. + + This keeps processing pending events until stdin is ready. After + processing all pending events, a call to time.sleep is inserted. This is + needed, otherwise, CPU usage is at 100%. This sleep time should be tuned + though for best performance. + """ + # We need to protect against a user pressing Control-C when IPython is + # idle and this is running. We trap KeyboardInterrupt and pass. + try: + t = clock() + while not context.input_is_ready(): + pyglet.clock.tick() + for window in pyglet.app.windows: + window.switch_to() + window.dispatch_events() + window.dispatch_event('on_draw') + flip(window) + + # We need to sleep at this point to keep the idle CPU load + # low. However, if sleep to long, GUI response is poor. As + # a compromise, we watch how often GUI events are being processed + # and switch between a short and long sleep time. Here are some + # stats useful in helping to tune this. + # time CPU load + # 0.001 13% + # 0.005 3% + # 0.01 1.5% + # 0.05 0.5% + used_time = clock() - t + if used_time > 10.0: + # print 'Sleep for 1 s' # dbg + time.sleep(1.0) + elif used_time > 0.1: + # Few GUI events coming in, so we can sleep longer + # print 'Sleep for 0.05 s' # dbg + time.sleep(0.05) + else: + # Many GUI events coming in, so sleep only very little + time.sleep(0.001) + except KeyboardInterrupt: + pass From 24fa5b78c0f9e963a899c2e0c94f8f61be6428f8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 14:47:22 +0000 Subject: [PATCH 0088/4859] Add GLUT input hook --- IPython/terminal/pt_inputhooks/glut.py | 141 ++++++++++++++++++++++++ examples/IPython Kernel/gui/gui-glut.py | 2 +- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 IPython/terminal/pt_inputhooks/glut.py diff --git a/IPython/terminal/pt_inputhooks/glut.py b/IPython/terminal/pt_inputhooks/glut.py new file mode 100644 index 00000000000..f336e6830f5 --- /dev/null +++ b/IPython/terminal/pt_inputhooks/glut.py @@ -0,0 +1,141 @@ +"""GLUT Input hook for interactive use with prompt_toolkit +""" +from __future__ import print_function + + +# GLUT is quite an old library and it is difficult to ensure proper +# integration within IPython since original GLUT does not allow to handle +# events one by one. Instead, it requires for the mainloop to be entered +# and never returned (there is not even a function to exit he +# mainloop). Fortunately, there are alternatives such as freeglut +# (available for linux and windows) and the OSX implementation gives +# access to a glutCheckLoop() function that blocks itself until a new +# event is received. This means we have to setup the idle callback to +# ensure we got at least one event that will unblock the function. +# +# Furthermore, it is not possible to install these handlers without a window +# being first created. We choose to make this window invisible. This means that +# display mode options are set at this level and user won't be able to change +# them later without modifying the code. This should probably be made available +# via IPython options system. + +import sys +import time +import signal +import OpenGL.GLUT as glut +import OpenGL.platform as platform +from timeit import default_timer as clock + +# Frame per second : 60 +# Should probably be an IPython option +glut_fps = 60 + +# Display mode : double buffeed + rgba + depth +# Should probably be an IPython option +glut_display_mode = (glut.GLUT_DOUBLE | + glut.GLUT_RGBA | + glut.GLUT_DEPTH) + +glutMainLoopEvent = None +if sys.platform == 'darwin': + try: + glutCheckLoop = platform.createBaseFunction( + 'glutCheckLoop', dll=platform.GLUT, resultType=None, + argTypes=[], + doc='glutCheckLoop( ) -> None', + argNames=(), + ) + except AttributeError: + raise RuntimeError( + '''Your glut implementation does not allow interactive sessions''' + '''Consider installing freeglut.''') + glutMainLoopEvent = glutCheckLoop +elif glut.HAVE_FREEGLUT: + glutMainLoopEvent = glut.glutMainLoopEvent +else: + raise RuntimeError( + '''Your glut implementation does not allow interactive sessions. ''' + '''Consider installing freeglut.''') + + +def glut_display(): + # Dummy display function + pass + +def glut_idle(): + # Dummy idle function + pass + +def glut_close(): + # Close function only hides the current window + glut.glutHideWindow() + glutMainLoopEvent() + +def glut_int_handler(signum, frame): + # Catch sigint and print the defaultipyt message + signal.signal(signal.SIGINT, signal.default_int_handler) + print('\nKeyboardInterrupt') + # Need to reprint the prompt at this stage + +# Initialisation code +glut.glutInit( sys.argv ) +glut.glutInitDisplayMode( glut_display_mode ) +# This is specific to freeglut +if bool(glut.glutSetOption): + glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE, + glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS ) +glut.glutCreateWindow( b'ipython' ) +glut.glutReshapeWindow( 1, 1 ) +glut.glutHideWindow( ) +glut.glutWMCloseFunc( glut_close ) +glut.glutDisplayFunc( glut_display ) +glut.glutIdleFunc( glut_idle ) + + +def inputhook(context): + """Run the pyglet event loop by processing pending events only. + + This keeps processing pending events until stdin is ready. After + processing all pending events, a call to time.sleep is inserted. This is + needed, otherwise, CPU usage is at 100%. This sleep time should be tuned + though for best performance. + """ + # We need to protect against a user pressing Control-C when IPython is + # idle and this is running. We trap KeyboardInterrupt and pass. + + signal.signal(signal.SIGINT, glut_int_handler) + + try: + t = clock() + + # Make sure the default window is set after a window has been closed + if glut.glutGetWindow() == 0: + glut.glutSetWindow( 1 ) + glutMainLoopEvent() + return 0 + + while not context.input_is_ready(): + glutMainLoopEvent() + # We need to sleep at this point to keep the idle CPU load + # low. However, if sleep to long, GUI response is poor. As + # a compromise, we watch how often GUI events are being processed + # and switch between a short and long sleep time. Here are some + # stats useful in helping to tune this. + # time CPU load + # 0.001 13% + # 0.005 3% + # 0.01 1.5% + # 0.05 0.5% + used_time = clock() - t + if used_time > 10.0: + # print 'Sleep for 1 s' # dbg + time.sleep(1.0) + elif used_time > 0.1: + # Few GUI events coming in, so we can sleep longer + # print 'Sleep for 0.05 s' # dbg + time.sleep(0.05) + else: + # Many GUI events coming in, so sleep only very little + time.sleep(0.001) + except KeyboardInterrupt: + pass diff --git a/examples/IPython Kernel/gui/gui-glut.py b/examples/IPython Kernel/gui/gui-glut.py index 2643b3e6d85..573690b48d1 100755 --- a/examples/IPython Kernel/gui/gui-glut.py +++ b/examples/IPython Kernel/gui/gui-glut.py @@ -38,7 +38,7 @@ def resize(width,height): else: interactive = False -glut.glutCreateWindow('gui-glut') +glut.glutCreateWindow(b'gui-glut') glut.glutDisplayFunc(display) glut.glutReshapeFunc(resize) # This is necessary on osx to be able to close the window From f34eb22e490f0876aeb269ca823b81e7cfee85ad Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 14:54:03 +0000 Subject: [PATCH 0089/4859] Fix some deprecation warnings in GTK3 example --- examples/IPython Kernel/gui/gui-gtk3.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/IPython Kernel/gui/gui-gtk3.py b/examples/IPython Kernel/gui/gui-gtk3.py index 1ee7c98d642..935c026d5e3 100644 --- a/examples/IPython Kernel/gui/gui-gtk3.py +++ b/examples/IPython Kernel/gui/gui-gtk3.py @@ -20,10 +20,10 @@ def delete_event(widget, event, data=None): def destroy(widget, data=None): Gtk.main_quit() -window = Gtk.Window(Gtk.WindowType.TOPLEVEL) +window = Gtk.Window(type=Gtk.WindowType.TOPLEVEL) window.connect("delete_event", delete_event) window.connect("destroy", destroy) -button = Gtk.Button("Hello World") +button = Gtk.Button(label="Hello World") button.connect("clicked", hello_world, None) window.add(button) From cbc0479504a73b15a48641c9a8d254f614b8c777 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 15:19:28 +0000 Subject: [PATCH 0090/4859] Fix debugger doctest to match atual output --- IPython/core/tests/test_debugger.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index 9e11d932b84..75b3d41e77c 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -124,6 +124,8 @@ def test_ipdb_magics(): Docstring for ExampleClass.__init__ ipdb> up > (11)() + 7 'pinfo a', + 8 'll', 9 'continue', 10 ]): ---> 11 trigger_ipdb() From ae59e6e44bfde48d33dd37d46f093a93788a903e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 15:24:53 +0000 Subject: [PATCH 0091/4859] Initialise threads for pygtk input hook --- IPython/terminal/pt_inputhooks/gtk.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/terminal/pt_inputhooks/gtk.py b/IPython/terminal/pt_inputhooks/gtk.py index 33600488bc1..8f27e12c46d 100644 --- a/IPython/terminal/pt_inputhooks/gtk.py +++ b/IPython/terminal/pt_inputhooks/gtk.py @@ -39,6 +39,9 @@ import gtk, gobject +# Enable threading in GTK. (Otherwise, GTK will keep the GIL.) +gtk.gdk.threads_init() + def inputhook(context): """ When the eventloop of prompt-toolkit is idle, call this inputhook. From 7da2783b15a56a229ebe76d0edf874ca5c95494f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 18 Jan 2016 15:37:51 +0000 Subject: [PATCH 0092/4859] Implement pre-filling prompt from set_next_input() --- IPython/terminal/ptshell.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4e04bcdf755..40df8bd3165 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -152,11 +152,19 @@ def __init__(self, *args, **kwargs): def ask_exit(self): self.keep_running = False + rl_next_input = None + + def pre_prompt(self): + if self.rl_next_input: + self.pt_cli.application.buffer.text = self.rl_next_input + self.rl_next_input = None + def interact(self): while self.keep_running: print(self.separate_in, end='') + try: - document = self.pt_cli.run() + document = self.pt_cli.run(pre_run=self.pre_prompt) except EOFError: if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): self.ask_exit() From 0a16e9d0e624a99578587eaa288ab1b6a3836a98 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jan 2016 14:00:47 +0000 Subject: [PATCH 0093/4859] Integrate colorama for coloured output on Windows --- IPython/terminal/ptshell.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 40df8bd3165..4da49b4845e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,6 +1,8 @@ """IPython terminal interface using prompt_toolkit in place of readline""" from __future__ import print_function +import sys + from IPython.core.interactiveshell import InteractiveShell from IPython.utils.py3compat import PY3 from traitlets import Bool, Unicode, Dict @@ -144,6 +146,20 @@ def _(event): self.pt_cli = CommandLineInterface(app, eventloop=create_eventloop(self.inputhook)) + def init_io(self): + if sys.platform not in {'win32', 'cli'}: + return + + import colorama + colorama.init() + + # For some reason we make these wrappers around stdout/stderr. + # For now, we need to reset them so all output gets coloured. + # https://github.com/ipython/ipython/issues/8669 + from IPython.utils import io + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) + def __init__(self, *args, **kwargs): super(PTInteractiveShell, self).__init__(*args, **kwargs) self.init_prompt_toolkit_cli() From 091b646deb992f37462a9da3d47d8ab07d129135 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 10:42:12 -0800 Subject: [PATCH 0094/4859] Remove mention to rehash Fix part of #8875, the import mpl_ not working still need to be resolved, but can be postponed. --- IPython/core/magics/osm.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 08019db2dce..be69d1f4aad 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -97,9 +97,9 @@ def alias(self, parameter_s=''): In [9]: show $$PATH /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... - You can use the alias facility to acess all of $PATH. See the %rehash - and %rehashx functions, which automatically create aliases for the - contents of your $PATH. + You can use the alias facility to acess all of $PATH. See the %rehashx + function, which automatically create aliases for the contents of your + $PATH. If called with no parameters, %alias prints the current alias table.""" @@ -148,8 +148,8 @@ def unalias(self, parameter_s=''): def rehashx(self, parameter_s=''): """Update the alias table with all executable files in $PATH. - This version explicitly checks that every entry in $PATH is a file - with execute access (os.X_OK), so it is much slower than %rehash. + rehashx explicitly checks that every entry in $PATH is a file + with execute access (os.X_OK). Under Windows, it checks executability as a match against a '|'-separated string of extensions, stored in the IPython config From edb71aab9a9786c31c8785069ee239a38a7dfc7f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 12:43:17 -0800 Subject: [PATCH 0095/4859] Change to `Creates` as function is now singular. --- IPython/core/magics/osm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index be69d1f4aad..5c3db3eb567 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -98,7 +98,7 @@ def alias(self, parameter_s=''): /usr/local/lf9560/bin:/usr/local/intel/compiler70/ia32/bin:... You can use the alias facility to acess all of $PATH. See the %rehashx - function, which automatically create aliases for the contents of your + function, which automatically creates aliases for the contents of your $PATH. If called with no parameters, %alias prints the current alias table.""" From 8cb3dd9709c154c9669b72dee93379872d3fc477 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jan 2016 20:48:23 +0000 Subject: [PATCH 0096/4859] Deactivate prompt transformers if the first line matches certain patterns Deactivate the >>> prompt stripper if the first line starts with % or !, because those are obviously IPython syntax. Disable the IPython 'In [1]:' prompt stripper if the first line starts with %%, because we don't want to interfere with the copy of a cell magic. This is all 'what did the user mean' guesswork, but I think this makes our guesses slightly smarter. We actually had one test that checked that this wasn't happening; I've adjusted it. Closes gh-8791 --- IPython/core/inputtransformer.py | 28 +++++++++++++++++---- IPython/core/tests/test_inputsplitter.py | 2 +- IPython/core/tests/test_inputtransformer.py | 13 ++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/IPython/core/inputtransformer.py b/IPython/core/inputtransformer.py index daf40b06dc2..987c555b33b 100644 --- a/IPython/core/inputtransformer.py +++ b/IPython/core/inputtransformer.py @@ -400,7 +400,7 @@ def cellmagic(end_on_blank_line=False): line = tpl % (magic_name, first, u'\n'.join(body)) -def _strip_prompts(prompt_re, initial_re=None): +def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None): """Remove matching input prompts from a block of input. Parameters @@ -418,6 +418,12 @@ def _strip_prompts(prompt_re, initial_re=None): If any prompt is found on the first two lines, prompts will be stripped from the rest of the block. """ + def pass_thru(line1): + "Pass lines through unaltered until the end of the cell" + line = line1 + while line is not None: + line = (yield line) + if initial_re is None: initial_re = prompt_re line = '' @@ -428,6 +434,14 @@ def _strip_prompts(prompt_re, initial_re=None): if line is None: continue out, n1 = initial_re.subn('', line, count=1) + if turnoff_re and not n1: + if turnoff_re.match(line): + # We're in e.g. a cell magic; disable this transformer for + # the rest of the cell. + yield from pass_thru(line) + line = None + continue + line = (yield out) if line is None: @@ -446,8 +460,8 @@ def _strip_prompts(prompt_re, initial_re=None): else: # Prompts not in input - wait for reset - while line is not None: - line = (yield line) + yield from pass_thru(line) + line = None @CoroutineInputTransformer.wrap def classic_prompt(): @@ -455,14 +469,18 @@ def classic_prompt(): # FIXME: non-capturing version (?:...) usable? prompt_re = re.compile(r'^(>>>|\.\.\.)( |$)') initial_re = re.compile(r'^>>>( |$)') - return _strip_prompts(prompt_re, initial_re) + # Any %magic/!system is IPython syntax, so we needn't look for >>> prompts + turnoff_re = re.compile(r'^[%!]') + return _strip_prompts(prompt_re, initial_re, turnoff_re) @CoroutineInputTransformer.wrap def ipy_prompt(): """Strip IPython's In [1]:/...: prompts.""" # FIXME: non-capturing version (?:...) usable? prompt_re = re.compile(r'^(In \[\d+\]: |\s*\.{3,}: ?)') - return _strip_prompts(prompt_re) + # Disable prompt stripping inside cell magics + turnoff_re = re.compile(r'^%%') + return _strip_prompts(prompt_re, turnoff_re=turnoff_re) @CoroutineInputTransformer.wrap diff --git a/IPython/core/tests/test_inputsplitter.py b/IPython/core/tests/test_inputsplitter.py index 8ee7ba1cb8e..511003298a5 100644 --- a/IPython/core/tests/test_inputsplitter.py +++ b/IPython/core/tests/test_inputsplitter.py @@ -452,7 +452,7 @@ def test_cellmagic_preempt(self): ("%%cellm a\nIn[1]:", u'cellm', u'a', u'In[1]:'), ("%%cellm \nline\n>>> hi", u'cellm', u'', u'line\n>>> hi'), (">>> %%cellm \nline\n>>> hi", u'cellm', u'', u'line\nhi'), - ("%%cellm \n>>> hi", u'cellm', u'', u'hi'), + ("%%cellm \n>>> hi", u'cellm', u'', u'>>> hi'), ("%%cellm \nline1\nline2", u'cellm', u'', u'line1\nline2'), ("%%cellm \nline1\\\\\nline2", u'cellm', u'', u'line1\\\\\nline2'), ]: diff --git a/IPython/core/tests/test_inputtransformer.py b/IPython/core/tests/test_inputtransformer.py index 4f04032555d..ebad8ab6d36 100644 --- a/IPython/core/tests/test_inputtransformer.py +++ b/IPython/core/tests/test_inputtransformer.py @@ -360,12 +360,25 @@ def test_classic_prompt(): for example in syntax_ml['multiline_datastructure_prompt']: transform_checker(example, ipt.classic_prompt) + # Check that we don't transform the second line if the first is obviously + # IPython syntax + transform_checker([ + (u'%foo', '%foo'), + (u'>>> bar', '>>> bar'), + ], ipt.classic_prompt) + def test_ipy_prompt(): tt.check_pairs(transform_and_reset(ipt.ipy_prompt), syntax['ipy_prompt']) for example in syntax_ml['ipy_prompt']: transform_checker(example, ipt.ipy_prompt) + # Check that we don't transform the second line if we're inside a cell magic + transform_checker([ + (u'%%foo', '%%foo'), + (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']: From 8b766e65c15d3f07e05ee6228d60256a5451df0d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jan 2016 21:02:17 +0000 Subject: [PATCH 0097/4859] No yield from for us One day we'll use it --- IPython/core/inputtransformer.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/IPython/core/inputtransformer.py b/IPython/core/inputtransformer.py index 987c555b33b..cd8519b22c9 100644 --- a/IPython/core/inputtransformer.py +++ b/IPython/core/inputtransformer.py @@ -418,12 +418,6 @@ def _strip_prompts(prompt_re, initial_re=None, turnoff_re=None): If any prompt is found on the first two lines, prompts will be stripped from the rest of the block. """ - def pass_thru(line1): - "Pass lines through unaltered until the end of the cell" - line = line1 - while line is not None: - line = (yield line) - if initial_re is None: initial_re = prompt_re line = '' @@ -438,8 +432,8 @@ def pass_thru(line1): if turnoff_re.match(line): # We're in e.g. a cell magic; disable this transformer for # the rest of the cell. - yield from pass_thru(line) - line = None + while line is not None: + line = (yield line) continue line = (yield out) @@ -460,8 +454,8 @@ def pass_thru(line1): else: # Prompts not in input - wait for reset - yield from pass_thru(line) - line = None + while line is not None: + line = (yield line) @CoroutineInputTransformer.wrap def classic_prompt(): From 3aa20a32a79a57c645db34b8a3afab191f86267a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 13:33:41 -0800 Subject: [PATCH 0098/4859] Add filter warnings for Traitlets 4.1 now that it's out. --- IPython/testing/iptest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 7950b8c68b8..eb7ef8f27b8 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -51,8 +51,9 @@ # ignore some warnings from traitlets until 6.0 warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*') warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*') + warnings.filterwarnings('ignore', message='.*use the instance .help string directly, like x.help.*', category=DeprecationWarning, module='IPython.*') else : - warnings.warn('iptest has been filtering out for Traitlets warnings messages, for 2 major versions (since 4.x), please consider updating to use new API') + warnings.warn('iptest has been filtering out for Traitlets warnings messages, for 2 minor versions (since 4.x), please consider updating to use new API') if version_info < (6,): # nose.tools renames all things from `camelCase` to `snake_case` which raise an From 120de1c9b0ae2b5e94f976adcba4764d064d9af3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 14:33:02 -0800 Subject: [PATCH 0099/4859] Respect Pep 479: Do not raise StopIteration --- IPython/lib/pretty.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 1465a6adb96..49ee2cef377 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -273,7 +273,7 @@ def _enumerate(self, seq): self.text(',') self.breakable() self.text('...') - raise StopIteration + return yield idx, x def end_group(self, dedent=0, close=''): From b78738c3bfc4ada2c46dad559e8c35bd3e0b1887 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 16:57:47 -0800 Subject: [PATCH 0100/4859] Allow Embeded instances to raise on exit. This is use full in case where an IPython embed instance is created in a loop: from IPython import embed while True: embed(header="You will be stuck there") Now using `%raise_on_exist True` in an embeded shell allows the embeded instannce to raise on exit. Potential improvement would be flags to pass a custom exception type as well as a custom message to raise. Closes #9149 --- IPython/terminal/embed.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 9b81fc8639f..5109da1effb 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -21,6 +21,7 @@ from traitlets import Bool, CBool, Unicode from IPython.utils.io import ask_yes_no +class KillEmbeded(Exception):pass # This is an additional magic that is exposed in embedded shells. @magics_class @@ -45,6 +46,39 @@ def kill_embedded(self, parameter_s=''): print ("This embedded IPython will not reactivate anymore " "once you exit.") + @line_magic + def raise_on_exit(self, parameter_s=''): + """%raise_on_exit [True|False]: Make the current embeded kernel to raise an exception on exit. + + You can change that again during current session by calling `%raise_on_exit` with `True`/`False` as parameter + + This function (after asking for confirmation) sets an internal flag so + that an embedded IPython will raise a `KillEmbeded` Exception on exit. This is useful to + permanently exit a loop that create IPython embed instance. + """ + parameter_s = parameter_s.strip().lower() + + should_raise = None + if parameter_s in {'yes', 'raise', 'true', '1'}: + should_raise = True + elif parameter_s in {'no', 'false', '0', 'None'}: + should_raise = False + else: + if self.shell.should_raise : + print("The current embed instance will raise on exit, use `%raise_on_exit False` to disable") + return + else: + print("The current embed instance will not raise on exit, use `%raise_on_exit True` to enable") + return + + if should_raise: + self.shell.should_raise = True + print ("This embedded IPython will raise while exiting.") + else : + self.shell.should_raise = False + print ("This embedded IPython will not raise while exiting.") + + class InteractiveShellEmbed(TerminalInteractiveShell): @@ -52,6 +86,7 @@ class InteractiveShellEmbed(TerminalInteractiveShell): exit_msg = Unicode('') embedded = CBool(True) embedded_active = CBool(True) + should_raise = CBool(False) # Like the base class display_banner is not configurable, but here it # is True by default. display_banner = CBool(True) @@ -130,6 +165,10 @@ def __call__(self, header='', local_ns=None, module=None, dummy=None, if self.exit_msg is not None: print(self.exit_msg) + if self.should_raise: + raise KillEmbeded('This instance has been marked as must raise on exit.') + + def mainloop(self, local_ns=None, module=None, stack_depth=0, display_banner=None, global_ns=None, compile_flags=None): """Embeds IPython into a running python program. From 05b80920ea3c603c24ecbe92b6c1ae409cdc34e7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 17:02:34 -0800 Subject: [PATCH 0101/4859] Make the previous new feature Python 3 only. Just because. --- IPython/terminal/embed.py | 58 +++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 5109da1effb..ddb10291b90 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -46,37 +46,41 @@ def kill_embedded(self, parameter_s=''): print ("This embedded IPython will not reactivate anymore " "once you exit.") - @line_magic - def raise_on_exit(self, parameter_s=''): - """%raise_on_exit [True|False]: Make the current embeded kernel to raise an exception on exit. + if sys.version_info > (3,): - You can change that again during current session by calling `%raise_on_exit` with `True`/`False` as parameter + @line_magic + def raise_on_exit(self, parameter_s=''): + """%raise_on_exit [True|False]: Make the current embeded kernel to raise an exception on exit. - This function (after asking for confirmation) sets an internal flag so - that an embedded IPython will raise a `KillEmbeded` Exception on exit. This is useful to - permanently exit a loop that create IPython embed instance. - """ - parameter_s = parameter_s.strip().lower() + You can change that again during current session by calling `%raise_on_exit` with `True`/`False` as parameter - should_raise = None - if parameter_s in {'yes', 'raise', 'true', '1'}: - should_raise = True - elif parameter_s in {'no', 'false', '0', 'None'}: - should_raise = False - else: - if self.shell.should_raise : - print("The current embed instance will raise on exit, use `%raise_on_exit False` to disable") - return + This function (after asking for confirmation) sets an internal flag so + that an embedded IPython will raise a `KillEmbeded` Exception on exit. This is useful to + permanently exit a loop that create IPython embed instance. + + Available only for Python 3. + """ + parameter_s = parameter_s.strip().lower() + + should_raise = None + if parameter_s in {'yes', 'raise', 'true', '1'}: + should_raise = True + elif parameter_s in {'no', 'false', '0', 'None'}: + should_raise = False else: - print("The current embed instance will not raise on exit, use `%raise_on_exit True` to enable") - return - - if should_raise: - self.shell.should_raise = True - print ("This embedded IPython will raise while exiting.") - else : - self.shell.should_raise = False - print ("This embedded IPython will not raise while exiting.") + if self.shell.should_raise : + print("The current embed instance will raise on exit, use `%raise_on_exit False` to disable") + return + else: + print("The current embed instance will not raise on exit, use `%raise_on_exit True` to enable") + return + + if should_raise: + self.shell.should_raise = True + print ("This embedded IPython will raise while exiting.") + else : + self.shell.should_raise = False + print ("This embedded IPython will not raise while exiting.") From 65fc22562f511c9daf8d6c379a80b6134947294f Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 9 Jul 2015 23:40:39 -0500 Subject: [PATCH 0102/4859] reshow nbagg figures on display instead of inline images --- IPython/core/pylabtools.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 4bf15cc1c8e..65281787666 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -173,6 +173,16 @@ def mpl_execfile(fname,*where,**kw): return mpl_execfile +def _reshow_nbagg_figure(fig): + """reshow an nbagg figure""" + try: + reshow = fig.canvas.manager.reshow + except AttributeError: + raise NotImplementedError() + else: + reshow() + + def select_figure_formats(shell, formats, **kwargs): """Select figure formats for the inline backend. @@ -185,6 +195,7 @@ def select_figure_formats(shell, formats, **kwargs): **kwargs : any Extra keyword arguments to be passed to fig.canvas.print_figure. """ + import matplotlib from matplotlib.figure import Figure from ipykernel.pylab import backend_inline @@ -199,7 +210,11 @@ def select_figure_formats(shell, formats, **kwargs): formats = set(formats) [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ] - + + if matplotlib.backends.backend.lower() == 'nbagg': + formatter = shell.display_formatter.ipython_display_formatter + formatter.for_type(Figure, _reshow_nbagg_figure) + supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'} bad = formats.difference(supported) if bad: From 57baac0b9f636ad5b0d5814b9972bcc81dc72cd8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 19 Jan 2016 09:50:34 -0800 Subject: [PATCH 0103/4859] Remember list of tempfile for %edit Should fix #9002, still need tests. There might be a better fix which would be to "mark" the %edit-ed file code as interactively defined in `In[x]`, though it would likely conflict with the fact that `In[x]` actually contain `%edit ` --- IPython/core/magics/code.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index 08d8a35aec8..75fd6e59c2d 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -147,6 +147,10 @@ def __init__(self, index): class CodeMagics(Magics): """Magics related to code management (loading, saving, editing, ...).""" + def __init__(self, *args, **kwargs): + self._knowntemps = set() + super(CodeMagics, self).__init__(*args, **kwargs) + @line_magic def save(self, parameter_s=''): """Save a set of lines or a macro to a given filename. @@ -661,6 +665,12 @@ def edit(self, parameter_s='',last_call=['','']): # just give up. return + if is_temp: + self._knowntemps.add(filename) + elif (filename in self._knowntemps): + is_temp = True + + # do actual editing here print('Editing...', end=' ') sys.stdout.flush() From e9155c4362ae280c8c1b5622caa6f1af00e2c9c3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 21 Jan 2016 12:12:18 +0000 Subject: [PATCH 0104/4859] Clarify kernel installation instructions Alternative to gh-9154 --- docs/source/conf.py | 1 + docs/source/install/kernel_install.rst | 42 +++++++++++++++++--------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0e701bc47db..cdf39f95921 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -206,6 +206,7 @@ 'traitlets': ('http://traitlets.readthedocs.org/en/latest/', None), 'jupyterclient': ('http://jupyter-client.readthedocs.org/en/latest/', None), 'ipyparallel': ('http://ipyparallel.readthedocs.org/en/latest/', None), + 'jupyter': ('http://jupyter.readthedocs.org/en/latest/', None), } # Options for LaTeX output diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index 7655b213f82..d3425b4ba60 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -3,37 +3,51 @@ Installing the IPython kernel ============================= +.. seealso:: + + :ref:`Installing Jupyter ` + The IPython kernel is the Python execution backend for Jupyter. + The Jupyter Notebook and other frontends automatically ensure that the IPython kernel is available. However, if you want to use a kernel with a different version of Python, or in a virtualenv or conda environment, you'll need to install that manually. -Using the Python version or environment for which you want to set up the kernel, run:: +Kernels for Python 2 and 3 +-------------------------- + +If you're running Jupyter on Python 3, you can set up a Python 2 kernel like this:: + + python2 -m pip install ipykernel + python2 -m ipykernel install --user - pip install ipykernel # or: conda install ipykernel +Or using conda, create a Python 2 environment:: + + conda create -n ipykernel_py2 python=2 ipykernel + source activate ipykernel_py2 # On Windows, remove the word 'source' python -m ipykernel install --user +If you're running Jupyter on Python 2 and want to set up a Python 3 kernel, +follow the same steps, replacing ``2`` with ``3``. + The last command installs a :ref:`kernel spec ` file for the current python installation. Kernel spec files are JSON files, which can be viewed and changed with a normal text editor. -See `python -m ipykernel install --help` for the list of installation options like -naming the kernel, or non default install location. - .. _multiple_kernel_install: -Multiple IPython installations -============================== +Kernels for different environments +---------------------------------- -If you want to have multiple IPython kernels for different environments, -you will need to specify unique names for the kernelspecs, -and you may also want to specify the display name of those kernels, -so that you can clearly see which is which in the notebook menus: +If you want to have multiple IPython kernels for different virtualenvs or conda environments, +you will need to specify unique names for the kernelspecs: .. sourcecode:: bash source activate myenv - ipython kernel install --user --name myenv --display-name "Python (myenv)" + python -m ipykernel install --user --name myenv --display-name "Python (myenv)" source activate other-env - ipython kernel install --user --name other-env --display-name "Python (other-env)" - source deactivate + python -m ipykernel install --user --name other-env --display-name "Python (other-env)" +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. From 730093369725dbc19112e01c909bde40620aa999 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 21 Jan 2016 12:52:27 +0000 Subject: [PATCH 0105/4859] Fix %edit - editor attribute was missing --- IPython/terminal/ptshell.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4da49b4845e..895c9ac27b4 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -25,6 +25,7 @@ from pygments.token import Token from .pt_inputhooks import get_inputhook_func +from .interactiveshell import get_default_editor class IPythonPTCompleter(Completer): @@ -61,6 +62,10 @@ class PTInteractiveShell(InteractiveShell): help="Override highlighting format for specific tokens" ) + editor = Unicode(get_default_editor(), config=True, + help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." + ) + def get_prompt_tokens(self, cli): return [ (Token.Prompt, 'In ['), From 06f7830ca3a06056d10bec2347811ea317568294 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 21 Jan 2016 10:19:24 -0800 Subject: [PATCH 0106/4859] add do_where --- docs/source/whatsnew/development.rst | 2 +- docs/source/whatsnew/pr/do_where.rst | 47 ++++++++++++++++++++++++++++ tools/update_whatsnew.py | 19 ++++++----- 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 docs/source/whatsnew/pr/do_where.rst diff --git a/docs/source/whatsnew/development.rst b/docs/source/whatsnew/development.rst index 8097c05a336..edc6a93774e 100644 --- a/docs/source/whatsnew/development.rst +++ b/docs/source/whatsnew/development.rst @@ -10,6 +10,7 @@ This document describes in-flight development work. conflicts for other Pull Requests). Instead, create a new file in the `docs/source/whatsnew/pr` folder + .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. @@ -18,4 +19,3 @@ Backwards incompatible changes .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. - diff --git a/docs/source/whatsnew/pr/do_where.rst b/docs/source/whatsnew/pr/do_where.rst new file mode 100644 index 00000000000..847fa6d1b62 --- /dev/null +++ b/docs/source/whatsnew/pr/do_where.rst @@ -0,0 +1,47 @@ +IPython debugger (IPdb) now supports the number of context lines for the +``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. + +.. code:: + + In [2]: def foo(): + ...: 1 + ...: 2 + ...: 3 + ...: 4 + ...: 5 + ...: raise ValueError('6 is not acceptable') + ...: 7 + ...: 8 + ...: 9 + ...: 10 + ...: + + In [3]: foo() + ---------------------------------------------------- + ValueError Traceback (most recent call last) + in () + ----> 1 foo() + + in foo() + 5 4 + 6 5 + ----> 7 raise ValueError('6 is not acceptable') + 8 7 + 9 8 + + ValueError: 6 is not acceptable + + In [4]: debug + > (7)foo() + 5 4 + 6 5 + ----> 7 raise ValueError('6 is not acceptable') + 8 7 + 9 8 + + ipdb> where 1 + (1)() + ----> 1 foo() + + > (7)foo() + ----> 7 raise ValueError('6 is not acceptable') diff --git a/tools/update_whatsnew.py b/tools/update_whatsnew.py index 97646e33e49..1dcc5fda2d7 100755 --- a/tools/update_whatsnew.py +++ b/tools/update_whatsnew.py @@ -7,6 +7,7 @@ import io import os +from glob import glob from os.path import dirname, basename, abspath, join as pjoin from subprocess import check_call, check_output @@ -20,15 +21,15 @@ # 1. Collect the whatsnew snippet files --------------------------------------- -files = set(os.listdir(pr_dir)) +files = set() +for f in glob(pjoin(pr_dir, '*.rst')): + files.add(f) # Ignore explanatory and example files -files.difference_update({'README.md', +files.difference_update({pjoin(pr_dir, f) for f in {'README.md', 'incompat-switching-to-perl.rst', 'antigravity-feature.rst'} - ) + }) -# Absolute paths -files = {pjoin(pr_dir, f) for f in files} def getmtime(f): return check_output(['git', 'log', '-1', '--format="%ai"', '--', f]) @@ -38,7 +39,11 @@ def getmtime(f): features, incompats = [], [] for path in files: with io.open(path, encoding='utf-8') as f: - content = f.read().rstrip() + try: + content = f.read().rstrip() + except Exception as e: + raise Exception('Error reading "{}"'.format(f)) + if basename(path).startswith('incompat-'): incompats.append(content) else: @@ -72,4 +77,4 @@ def getmtime(f): check_call(['git', 'add', target]) -print("Merged what's new changes. Check the diff and commit the change.") \ No newline at end of file +print("Merged what's new changes. Check the diff and commit the change.") From a5a04fd442ebd1ad72664bc690568c8cd18c5dda Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 21 Jan 2016 20:42:03 +0000 Subject: [PATCH 0107/4859] Clarify that example is for conda envs --- docs/source/install/kernel_install.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/install/kernel_install.rst b/docs/source/install/kernel_install.rst index d3425b4ba60..c34287d9d12 100644 --- a/docs/source/install/kernel_install.rst +++ b/docs/source/install/kernel_install.rst @@ -39,7 +39,9 @@ Kernels for different environments ---------------------------------- If you want to have multiple IPython kernels for different virtualenvs or conda environments, -you will need to specify unique names for the kernelspecs: +you will need to specify unique names for the kernelspecs. + +For example, using conda environments: .. sourcecode:: bash From ac12edc46480a6e3ddaf7587815903509edbda3e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 21 Jan 2016 15:15:01 -0800 Subject: [PATCH 0108/4859] Document do_where --- docs/source/interactive/reference.rst | 63 +++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index bedebd3fa8d..3ef89a7ee65 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -724,6 +724,69 @@ how to control where pdb will stop execution first. For more information on the use of the pdb debugger, see :ref:`debugger-commands` in the Python documentation. +IPython extends the debugger with a few useful additions, like coloring of +tracebacks. The debugger will adopt the color scheme selected for IPython. + +The ``where`` command has also been extended to take as argument the number of +context line to show. This allows to a many line of context on shallow stack trace: + +.. code:: + In [5]: def foo(x): + ...: 1 + ...: 2 + ...: 3 + ...: return 1/x+foo(x-1) + ...: 5 + ...: 6 + ...: 7 + ...: + + In[6]: foo(1) + # ... + ipdb> where 8 + (1)() + ----> 1 foo(1) + + (5)foo() + 1 def foo(x): + 2 1 + 3 2 + 4 3 + ----> 5 return 1/x+foo(x-1) + 6 5 + 7 6 + 8 7 + + > (5)foo() + 1 def foo(x): + 2 1 + 3 2 + 4 3 + ----> 5 return 1/x+foo(x-1) + 6 5 + 7 6 + 8 7 + + +And less context on shallower Stack Trace: + +.. code:: + ipdb> where 1 + (1)() + ----> 1 foo(7) + + (5)foo() + ----> 5 return 1/x+foo(x-1) + + (5)foo() + ----> 5 return 1/x+foo(x-1) + + (5)foo() + ----> 5 return 1/x+foo(x-1) + + (5)foo() + ----> 5 return 1/x+foo(x-1) + Post-mortem debugging --------------------- From 72b8d6c438087e065cd00b344ffc1b5478c1526d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 21 Jan 2016 15:16:46 -0800 Subject: [PATCH 0109/4859] Remove longer explanation from whats new --- docs/source/whatsnew/pr/do_where.rst | 45 ---------------------------- 1 file changed, 45 deletions(-) diff --git a/docs/source/whatsnew/pr/do_where.rst b/docs/source/whatsnew/pr/do_where.rst index 847fa6d1b62..d05ace3ab0c 100644 --- a/docs/source/whatsnew/pr/do_where.rst +++ b/docs/source/whatsnew/pr/do_where.rst @@ -1,47 +1,2 @@ IPython debugger (IPdb) now supports the number of context lines for the ``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. - -.. code:: - - In [2]: def foo(): - ...: 1 - ...: 2 - ...: 3 - ...: 4 - ...: 5 - ...: raise ValueError('6 is not acceptable') - ...: 7 - ...: 8 - ...: 9 - ...: 10 - ...: - - In [3]: foo() - ---------------------------------------------------- - ValueError Traceback (most recent call last) - in () - ----> 1 foo() - - in foo() - 5 4 - 6 5 - ----> 7 raise ValueError('6 is not acceptable') - 8 7 - 9 8 - - ValueError: 6 is not acceptable - - In [4]: debug - > (7)foo() - 5 4 - 6 5 - ----> 7 raise ValueError('6 is not acceptable') - 8 7 - 9 8 - - ipdb> where 1 - (1)() - ----> 1 foo() - - > (7)foo() - ----> 7 raise ValueError('6 is not acceptable') From c6f33a6704165c3380029753756ad6e8dead855c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 21 Jan 2016 15:21:20 -0800 Subject: [PATCH 0110/4859] Take Thomas comments into account --- docs/source/whatsnew/pr/do_where.rst | 1 + tools/update_whatsnew.py | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/source/whatsnew/pr/do_where.rst b/docs/source/whatsnew/pr/do_where.rst index d05ace3ab0c..c616fd5244e 100644 --- a/docs/source/whatsnew/pr/do_where.rst +++ b/docs/source/whatsnew/pr/do_where.rst @@ -1,2 +1,3 @@ IPython debugger (IPdb) now supports the number of context lines for the ``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. +See PR #9097 diff --git a/tools/update_whatsnew.py b/tools/update_whatsnew.py index 1dcc5fda2d7..d960bb08062 100755 --- a/tools/update_whatsnew.py +++ b/tools/update_whatsnew.py @@ -21,11 +21,9 @@ # 1. Collect the whatsnew snippet files --------------------------------------- -files = set() -for f in glob(pjoin(pr_dir, '*.rst')): - files.add(f) +files = set(glob(pjoin(pr_dir, '*.rst'))) # Ignore explanatory and example files -files.difference_update({pjoin(pr_dir, f) for f in {'README.md', +files.difference_update({pjoin(pr_dir, f) for f in { 'incompat-switching-to-perl.rst', 'antigravity-feature.rst'} }) @@ -42,7 +40,7 @@ def getmtime(f): try: content = f.read().rstrip() except Exception as e: - raise Exception('Error reading "{}"'.format(f)) + raise Exception('Error reading "{}"'.format(f)) from e if basename(path).startswith('incompat-'): incompats.append(content) From 0b54a6ac0457e06c650b36f50147036bcdb13c81 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jan 2016 11:00:42 -0800 Subject: [PATCH 0111/4859] Add some what's new --- docs/source/whatsnew/pr/newfeat.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/source/whatsnew/pr/newfeat.rst diff --git a/docs/source/whatsnew/pr/newfeat.rst b/docs/source/whatsnew/pr/newfeat.rst new file mode 100644 index 00000000000..48d9c034f0b --- /dev/null +++ b/docs/source/whatsnew/pr/newfeat.rst @@ -0,0 +1,14 @@ +YouTube video will now show thumbnail when exported to a media that do not support video. (PR #9086) + +Add warning when running `ipython ` when subcommand is deprecated. `jupyter` should now be used. + +Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`#8947`) + +`%aimport` now support module completion. (:ghpull:`#8884`) + +`ipdb` output is now colored ! (:ghpull:`#8842`) + +Add ability to transpose columns for completion: (:ghpull:`#8748`) + +Many many docs improvements and bug fixes, you can see the list of changes [add link to GitHub diff] + From ab39d9ba7e082d248e832032f9ee01e1524effe8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jan 2016 11:02:54 -0800 Subject: [PATCH 0112/4859] link to PR with :ghpull: role --- docs/source/whatsnew/pr/do_where.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whatsnew/pr/do_where.rst b/docs/source/whatsnew/pr/do_where.rst index c616fd5244e..36889d90f2d 100644 --- a/docs/source/whatsnew/pr/do_where.rst +++ b/docs/source/whatsnew/pr/do_where.rst @@ -1,3 +1,3 @@ IPython debugger (IPdb) now supports the number of context lines for the ``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. -See PR #9097 +See PR :ghpull:`9097` From 2884a0aa6855e4cb342c693f6dd357e08e448e56 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jan 2016 13:45:07 -0800 Subject: [PATCH 0113/4859] Fix :ghpull: in a few places. --- docs/source/whatsnew/pr/newfeat.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/whatsnew/pr/newfeat.rst b/docs/source/whatsnew/pr/newfeat.rst index 48d9c034f0b..7a3e345e249 100644 --- a/docs/source/whatsnew/pr/newfeat.rst +++ b/docs/source/whatsnew/pr/newfeat.rst @@ -1,14 +1,14 @@ -YouTube video will now show thumbnail when exported to a media that do not support video. (PR #9086) +YouTube video will now show thumbnail when exported to a media that do not support video. (:ghpull:`9086`) Add warning when running `ipython ` when subcommand is deprecated. `jupyter` should now be used. -Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`#8947`) +Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`8947`) -`%aimport` now support module completion. (:ghpull:`#8884`) +`%aimport` now support module completion. (:ghpull:`8884`) -`ipdb` output is now colored ! (:ghpull:`#8842`) +`ipdb` output is now colored ! (:ghpull:`8842`) -Add ability to transpose columns for completion: (:ghpull:`#8748`) +Add ability to transpose columns for completion: (:ghpull:`8748`) Many many docs improvements and bug fixes, you can see the list of changes [add link to GitHub diff] From 160d347208f90432f9ac928132186e010328da87 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 23 Jan 2016 11:51:18 -0800 Subject: [PATCH 0114/4859] Check setuptools version in setup.py Allow better error message when trying to build with old version of setuptools. Closes #9159 --- .travis.yml | 1 + setup.py | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 096bce0df2b..291473c99ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ 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" - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] - pip install codecov script: diff --git a/setup.py b/setup.py index c16bd1d1ed4..132ab3d0319 100755 --- a/setup.py +++ b/setup.py @@ -172,6 +172,9 @@ def run(self): if len(needs_setuptools.intersection(sys.argv)) > 0: import setuptools + v = tuple(int(x) for x in setuptools.__version__.split('.')) + if v < (18,5): + raise ValueError('Setuptools version >=18.5 is required, found: %s'%setuptools.__version__) # This dict is used for passing extra arguments that are setuptools # specific to setup @@ -191,6 +194,7 @@ def run(self): nbconvert = ['nbconvert'], ) install_requires = [ + 'setuptools>=18.5' 'decorator', 'pickleshare', 'simplegeneric>0.8', From 2db2f3778c02083efe89979711e926cfa296019e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 25 Jan 2016 17:00:23 +0000 Subject: [PATCH 0115/4859] Truncate tracebacks on recursion error Identify repeated frames in a recursion error traceback and only show them once. Closes gh-7833 --- IPython/core/tests/test_ultratb.py | 71 +++++- IPython/core/ultratb.py | 357 +++++++++++++++++------------ 2 files changed, 283 insertions(+), 145 deletions(-) diff --git a/IPython/core/tests/test_ultratb.py b/IPython/core/tests/test_ultratb.py index 39ae1717eac..9d1f26a1fcb 100644 --- a/IPython/core/tests/test_ultratb.py +++ b/IPython/core/tests/test_ultratb.py @@ -8,7 +8,12 @@ import traceback import unittest -from ..ultratb import ColorTB, VerboseTB +try: + from unittest import mock +except ImportError: + import mock # Python 2 + +from ..ultratb import ColorTB, VerboseTB, find_recursion from IPython.testing import tools as tt @@ -226,6 +231,70 @@ def test_suppress_exception_chaining(self): ip.run_cell(self.SUPPRESS_CHAINING_CODE) +class RecursionTest(unittest.TestCase): + DEFINITIONS = """ +def non_recurs(): + 1/0 + +def r1(): + r1() + +def r3a(): + r3b() + +def r3b(): + r3c() + +def r3c(): + r3a() + +def r3o1(): + r3a() + +def r3o2(): + r3o1() +""" + def setUp(self): + ip.run_cell(self.DEFINITIONS) + + def test_no_recursion(self): + with tt.AssertNotPrints("frames repeated"): + ip.run_cell("non_recurs()") + + def test_recursion_one_frame(self): + with tt.AssertPrints("1 frames repeated"): + ip.run_cell("r1()") + + def test_recursion_three_frames(self): + with tt.AssertPrints("3 frames repeated"): + ip.run_cell("r3o2()") + + def test_find_recursion(self): + captured = [] + def capture_exc(*args, **kwargs): + captured.append(sys.exc_info()) + with mock.patch.object(ip, 'showtraceback', capture_exc): + ip.run_cell("r3o2()") + + self.assertEqual(len(captured), 1) + etype, evalue, tb = captured[0] + self.assertIn("recursion", str(evalue)) + + records = ip.InteractiveTB.get_records(tb, 3, ip.InteractiveTB.tb_offset) + for r in records[:10]: + print(r[1:4]) + + # The outermost frames should be: + # 0: the 'cell' that was running when the exception came up + # 1: r3o2() + # 2: r3o1() + # 3: r3a() + # Then repeating r3b, r3c, r3a + last_unique, repeat_length = find_recursion(etype, evalue, records) + self.assertEqual(last_unique, 2) + self.assertEqual(repeat_length, 3) + + #---------------------------------------------------------------------------- # module testing (minimal) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index d870e34728e..04470370f27 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -422,6 +422,57 @@ def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None) i = i + 1 return res +def is_recursion_error(etype, value, records): + try: + # RecursionError is new in Python 3.5 + recursion_error_type = RecursionError + except NameError: + recursion_error_type = RuntimeError + + # The default recursion limit is 1000, but some of that will be taken up + # by stack frames in IPython itself. >500 frames probably indicates + # a recursion error. + return (etype is recursion_error_type) \ + and "recursion" in str(value).lower() \ + and len(records) > 500 + +def find_recursion(etype, value, records): + """Identify the repeating stack frames from a RecursionError traceback + + 'records' is a list as returned by VerboseTB.get_records() + + Returns (last_unique, repeat_length) + """ + # This involves a bit of guesswork - we want to show enough of the traceback + # to indicate where the recursion is occurring. We guess that the innermost + # quarter of the traceback (250 frames by default) is repeats, and find the + # first frame (from in to out) that looks different. + if not is_recursion_error(etype, value, records): + return len(records), 0 + + # Select filename, lineno, func_name to track frames with + records = [r[1:4] for r in records] + inner_frames = records[-(len(records)//4):] + frames_repeated = set(inner_frames) + + last_seen_at = {} + longest_repeat = 0 + i = len(records) + for frame in reversed(records): + i -= 1 + if frame not in frames_repeated: + last_unique = i + break + + if frame in last_seen_at: + distance = last_seen_at[frame] - i + longest_repeat = max(longest_repeat, distance) + + last_seen_at[frame] = i + else: + last_unique = 0 # The whole traceback was recursion + + return last_unique, longest_repeat #--------------------------------------------------------------------------- # Module classes @@ -775,15 +826,27 @@ def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None, check_cache = linecache.checkcache self.check_cache = check_cache - def format_records(self, records): + def format_records(self, records, last_unique, recursion_repeat): + """Format the stack frames of the traceback""" + frames = [] + for r in records[:last_unique+recursion_repeat+1]: + #print '*** record:',file,lnum,func,lines,index # dbg + frames.append(self.format_record(*r)) + + if recursion_repeat: + frames.append('Last %d frames repeated, from:\n' % recursion_repeat) + frames.append(self.format_record(*records[last_unique+recursion_repeat+1])) + + return frames + + def format_record(self, frame, file, lnum, func, lines, index): + """Format a single stack frame""" Colors = self.Colors # just a shorthand + quicker name lookup ColorsNormal = Colors.Normal # used a lot col_scheme = self.color_scheme_table.active_scheme_name indent = ' ' * INDENT_SIZE em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal) undefined = '%sundefined%s' % (Colors.em, ColorsNormal) - frames = [] - # build some color string templates outside these nested loops tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal) tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm, ColorsNormal) @@ -799,156 +862,154 @@ def format_records(self, records): ColorsNormal) abspath = os.path.abspath - for frame, file, lnum, func, lines, index in records: - #print '*** record:',file,lnum,func,lines,index # dbg - if not file: - file = '?' - elif file.startswith(str("<")) and file.endswith(str(">")): - # Not a real filename, no problem... - pass - elif not os.path.isabs(file): - # Try to make the filename absolute by trying all - # sys.path entries (which is also what linecache does) - for dirname in sys.path: - try: - fullname = os.path.join(dirname, file) - if os.path.isfile(fullname): - file = os.path.abspath(fullname) - break - except Exception: - # Just in case that sys.path contains very - # strange entries... - pass - file = py3compat.cast_unicode(file, util_path.fs_encoding) - link = tpl_link % file - args, varargs, varkw, locals = fixed_getargvalues(frame) - if func == '?': - call = '' - else: - # Decide whether to include variable details or not - var_repr = self.include_vars and eqrepr or nullrepr + if not file: + file = '?' + elif file.startswith(str("<")) and file.endswith(str(">")): + # Not a real filename, no problem... + pass + elif not os.path.isabs(file): + # Try to make the filename absolute by trying all + # sys.path entries (which is also what linecache does) + for dirname in sys.path: try: - call = tpl_call % (func, inspect.formatargvalues(args, - varargs, varkw, - locals, formatvalue=var_repr)) - except KeyError: - # This happens in situations like errors inside generator - # expressions, where local variables are listed in the - # line, but can't be extracted from the frame. I'm not - # 100% sure this isn't actually a bug in inspect itself, - # but since there's no info for us to compute with, the - # best we can do is report the failure and move on. Here - # we must *not* call any traceback construction again, - # because that would mess up use of %debug later on. So we - # simply report the failure and move on. The only - # limitation will be that this frame won't have locals - # listed in the call signature. Quite subtle problem... - # I can't think of a good way to validate this in a unit - # test, but running a script consisting of: - # dict( (k,v.strip()) for (k,v) in range(10) ) - # will illustrate the error, if this exception catch is - # disabled. - call = tpl_call_fail % func - - # Don't attempt to tokenize binary files. - if file.endswith(('.so', '.pyd', '.dll')): - frames.append('%s %s\n' % (link, call)) - continue - elif file.endswith(('.pyc', '.pyo')): - # Look up the corresponding source file. - file = openpy.source_from_cache(file) - - def linereader(file=file, lnum=[lnum], getline=ulinecache.getline): - line = getline(file, lnum[0]) - lnum[0] += 1 - return line - - # Build the list of names on this line of code where the exception - # occurred. - try: - names = [] - name_cont = False - - for token_type, token, start, end, line in generate_tokens(linereader): - # build composite names - if token_type == tokenize.NAME and token not in keyword.kwlist: - if name_cont: - # Continuation of a dotted name - try: - names[-1].append(token) - except IndexError: - names.append([token]) - name_cont = False - else: - # Regular new names. We append everything, the caller - # will be responsible for pruning the list later. It's - # very tricky to try to prune as we go, b/c composite - # names can fool us. The pruning at the end is easy - # to do (or the caller can print a list with repeated - # names if so desired. - names.append([token]) - elif token == '.': - name_cont = True - elif token_type == tokenize.NEWLINE: + fullname = os.path.join(dirname, file) + if os.path.isfile(fullname): + file = os.path.abspath(fullname) break + except Exception: + # Just in case that sys.path contains very + # strange entries... + pass - except (IndexError, UnicodeDecodeError, SyntaxError): - # signals exit of tokenizer - # SyntaxError can occur if the file is not actually Python - # - see gh-6300 - pass - except tokenize.TokenError as msg: - _m = ("An unexpected error occurred while tokenizing input\n" - "The following traceback may be corrupted or invalid\n" - "The error message is: %s\n" % msg) - error(_m) - - # Join composite names (e.g. "dict.fromkeys") - names = ['.'.join(n) for n in names] - # prune names list of duplicates, but keep the right order - unique_names = uniq_stable(names) - - # Start loop over vars - lvals = [] - if self.include_vars: - for name_full in unique_names: - name_base = name_full.split('.', 1)[0] - if name_base in frame.f_code.co_varnames: - if name_base in locals: - try: - value = repr(eval(name_full, locals)) - except: - value = undefined - else: + file = py3compat.cast_unicode(file, util_path.fs_encoding) + link = tpl_link % file + args, varargs, varkw, locals = fixed_getargvalues(frame) + + if func == '?': + call = '' + else: + # Decide whether to include variable details or not + var_repr = self.include_vars and eqrepr or nullrepr + try: + call = tpl_call % (func, inspect.formatargvalues(args, + varargs, varkw, + locals, formatvalue=var_repr)) + except KeyError: + # This happens in situations like errors inside generator + # expressions, where local variables are listed in the + # line, but can't be extracted from the frame. I'm not + # 100% sure this isn't actually a bug in inspect itself, + # but since there's no info for us to compute with, the + # best we can do is report the failure and move on. Here + # we must *not* call any traceback construction again, + # because that would mess up use of %debug later on. So we + # simply report the failure and move on. The only + # limitation will be that this frame won't have locals + # listed in the call signature. Quite subtle problem... + # I can't think of a good way to validate this in a unit + # test, but running a script consisting of: + # dict( (k,v.strip()) for (k,v) in range(10) ) + # will illustrate the error, if this exception catch is + # disabled. + call = tpl_call_fail % func + + # Don't attempt to tokenize binary files. + if file.endswith(('.so', '.pyd', '.dll')): + return '%s %s\n' % (link, call) + + elif file.endswith(('.pyc', '.pyo')): + # Look up the corresponding source file. + file = openpy.source_from_cache(file) + + def linereader(file=file, lnum=[lnum], getline=ulinecache.getline): + line = getline(file, lnum[0]) + lnum[0] += 1 + return line + + # Build the list of names on this line of code where the exception + # occurred. + try: + names = [] + name_cont = False + + for token_type, token, start, end, line in generate_tokens(linereader): + # build composite names + if token_type == tokenize.NAME and token not in keyword.kwlist: + if name_cont: + # Continuation of a dotted name + try: + names[-1].append(token) + except IndexError: + names.append([token]) + name_cont = False + else: + # Regular new names. We append everything, the caller + # will be responsible for pruning the list later. It's + # very tricky to try to prune as we go, b/c composite + # names can fool us. The pruning at the end is easy + # to do (or the caller can print a list with repeated + # names if so desired. + names.append([token]) + elif token == '.': + name_cont = True + elif token_type == tokenize.NEWLINE: + break + + except (IndexError, UnicodeDecodeError, SyntaxError): + # signals exit of tokenizer + # SyntaxError can occur if the file is not actually Python + # - see gh-6300 + pass + except tokenize.TokenError as msg: + _m = ("An unexpected error occurred while tokenizing input\n" + "The following traceback may be corrupted or invalid\n" + "The error message is: %s\n" % msg) + error(_m) + + # Join composite names (e.g. "dict.fromkeys") + names = ['.'.join(n) for n in names] + # prune names list of duplicates, but keep the right order + unique_names = uniq_stable(names) + + # Start loop over vars + lvals = [] + if self.include_vars: + for name_full in unique_names: + name_base = name_full.split('.', 1)[0] + if name_base in frame.f_code.co_varnames: + if name_base in locals: + try: + value = repr(eval(name_full, locals)) + except: value = undefined - name = tpl_local_var % name_full else: - if name_base in frame.f_globals: - try: - value = repr(eval(name_full, frame.f_globals)) - except: - value = undefined - else: + value = undefined + name = tpl_local_var % name_full + else: + if name_base in frame.f_globals: + try: + value = repr(eval(name_full, frame.f_globals)) + except: value = undefined - name = tpl_global_var % name_full - lvals.append(tpl_name_val % (name, value)) - if lvals: - lvals = '%s%s' % (indent, em_normal.join(lvals)) - else: - lvals = '' - - level = '%s %s\n' % (link, call) + else: + value = undefined + name = tpl_global_var % name_full + lvals.append(tpl_name_val % (name, value)) + if lvals: + lvals = '%s%s' % (indent, em_normal.join(lvals)) + else: + lvals = '' - if index is None: - frames.append(level) - else: - frames.append('%s%s' % (level, ''.join( - _format_traceback_lines(lnum, index, lines, Colors, lvals, - col_scheme)))) + level = '%s %s\n' % (link, call) - return frames + if index is None: + return level + else: + return '%s%s' % (level, ''.join( + _format_traceback_lines(lnum, index, lines, Colors, lvals, + col_scheme))) def prepare_chained_exception_message(self, cause): direct_cause = "\nThe above exception was the direct cause of the following exception:\n" @@ -1016,7 +1077,13 @@ def format_exception(self, etype, evalue): return exception def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset): + """Formats the header, traceback and exception message for a single exception. + + This may be called multiple times by Python 3 exception chaining + (PEP 3134). + """ # some locals + orig_etype = etype try: etype = etype.__name__ except AttributeError: @@ -1029,7 +1096,9 @@ def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_con if records is None: return "" - frames = self.format_records(records) + last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records) + + frames = self.format_records(records, last_unique, recursion_repeat) formatted_exception = self.format_exception(etype, evalue) if records: From d42ed570a6b17866dd7b90a9e505dff1e881590d Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 25 Jan 2016 12:42:33 -0800 Subject: [PATCH 0116/4859] Make should_backport work on other projects --- tools/backport_pr.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/backport_pr.py b/tools/backport_pr.py index 21df4b32a4c..308ebf9ec49 100755 --- a/tools/backport_pr.py +++ b/tools/backport_pr.py @@ -117,22 +117,22 @@ def already_backported(branch, since_tag=None): lines = check_output(cmd).decode('utf8') return set(int(num) for num in backport_re.findall(lines)) -def should_backport(labels=None, milestone=None): +def should_backport(labels=None, milestone=None, project='ipython/ipython'): """return set of PRs marked for backport""" if labels is None and milestone is None: raise ValueError("Specify one of labels or milestone.") elif labels is not None and milestone is not None: raise ValueError("Specify only one of labels or milestone.") if labels is not None: - issues = get_issues_list("ipython/ipython", + issues = get_issues_list(project, labels=labels, state='closed', auth=True, ) else: - milestone_id = get_milestone_id("ipython/ipython", milestone, + milestone_id = get_milestone_id(project, milestone, auth=True) - issues = get_issues_list("ipython/ipython", + issues = get_issues_list(project, milestone=milestone_id, state='closed', auth=True, @@ -142,7 +142,7 @@ def should_backport(labels=None, milestone=None): for issue in issues: if not is_pull_request(issue): continue - pr = get_pull_request("ipython/ipython", issue['number'], + pr = get_pull_request(project, issue['number'], auth=True) if not pr['merged']: print ("Marked PR closed without merge: %i" % pr['number']) From d7f0db73d29dfb46e2f8fed72940f0d5a50c9be9 Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Mon, 25 Jan 2016 12:49:18 -0800 Subject: [PATCH 0117/4859] Add repo support --- tools/backport_pr.py | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/tools/backport_pr.py b/tools/backport_pr.py index 308ebf9ec49..eb405fc669c 100755 --- a/tools/backport_pr.py +++ b/tools/backport_pr.py @@ -2,20 +2,27 @@ """ Backport pull requests to a particular branch. -Usage: backport_pr.py branch [PR] [PR2] +Usage: backport_pr.py [org/repository] branch [PR] [PR2] e.g.: python tools/backport_pr.py 0.13.1 123 155 -to backport PR #123 onto branch 0.13.1 +to backport PRs #123 and #155 onto branch 0.13.1 or python tools/backport_pr.py 2.1 to see what PRs are marked for backport with milestone=2.1 that have yet to be applied -to branch 2.x. +to branch 2.x + +or + + python tools/backport_pr.py jupyter/notebook 0.13.1 123 155 + +to backport PRs #123 and #155 of the `jupyter/notebook` repo onto branch 0.13.1 +of that repo. """ @@ -153,24 +160,30 @@ def should_backport(labels=None, milestone=None, project='ipython/ipython'): return should_backport if __name__ == '__main__': - - if len(sys.argv) < 2: + project = 'ipython/ipython' + args = list(sys.argv) + if len(args) >= 2: + if '/' in args[1]: + project = args[1] + del args[1] + + if len(args) < 2: print(__doc__) sys.exit(1) - if len(sys.argv) < 3: - milestone = sys.argv[1] + if len(args) < 3: + milestone = args[1] branch = milestone.split('.')[0] + '.x' already = already_backported(branch) - should = should_backport(milestone=milestone) + should = should_backport(milestone=milestone, project=project) print ("The following PRs should be backported:") for pr in sorted(should.difference(already)): print (pr) sys.exit(0) - - for prno in map(int, sys.argv[2:]): + + for prno in map(int, args[2:]): print("Backporting PR #%i" % prno) - rc = backport_pr(sys.argv[1], prno) + rc = backport_pr(args[1], prno, project=project) if rc: print("Backporting PR #%i failed" % prno) sys.exit(rc) From bcced3ca44eb2a6ccb0a9f8d6e3bd42d4925a526 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jan 2016 14:00:16 -0800 Subject: [PATCH 0118/4859] Add release instructions for IPython. Mostly adapt from notebooks one. --- IPython/core/release.py | 4 +-- docs/source/development/index.rst | 48 +++++++++++++++++++++++++++++++ setup.py | 9 +++++- 3 files changed, 58 insertions(+), 3 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 9e22b03f804..6f27f56673e 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -22,7 +22,7 @@ _version_major = 4 _version_minor = 1 _version_patch = 0 -_version_extra = 'dev' +_version_extra = '.dev' # _version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases @@ -34,7 +34,7 @@ __version__ = '.'.join(map(str, _ver)) if _version_extra: - __version__ = __version__ + '-' + _version_extra + __version__ = __version__ + _version_extra version = __version__ # backwards compatibility name version_info = (_version_major, _version_minor, _version_patch, _version_extra) diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index 5eac096a2b0..a75971614f5 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -26,3 +26,51 @@ on the IPython GitHub wiki. pycompat config inputhook_app + +Making an IPython release +========================= + +Make sure the repository is clean of any file that could be problematic. +You can remove all non-tracked files with: + +.. code:: + + $ git clean -xfdi + +This would ask you for confirmation before removing all untracked files. Make +sure the ``dist/`` folder is clean and avoid stale build from +previous attempts. + +1. Update version number in ``IPython/core/release.py``. + +Make sure the version number match pep440, in particular, `rc` and `beta` are +not separated by `.` or the `sdist` and `bdist` will appear as different +releases. + +2. Commit and tag the release with the current version number: + +.. code:: + + git commit -am "release $VERSION" + git tag $VERSION + + +3. You are now ready to build the ``sdist`` and ``wheel``: + +.. code:: + + $ python setup.py sdist --formats=zip,gztar + $ python setup.py bdist_wheel + + +4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. +Make sure to use `twine `_ to upload the archives over SSL. + +.. code:: + + $ twine upload dist/* + +5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. + +6. Push directly on master, not forgetting to push ``--tags``. + diff --git a/setup.py b/setup.py index 132ab3d0319..c5a8bf53770 100755 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ from __future__ import print_function import sys +import re # This check is also made in IPython/__init__, don't forget to update both when # changing Python version requirements. @@ -42,7 +43,6 @@ # Stdlib imports import os -import shutil from glob import glob @@ -291,7 +291,14 @@ def run(self): setup_args.update(setuptools_extra_args) + +# loose as `.dev` is suppose to be invalid +loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') + def main(): + import IPython.core.release as r + if not loose_pep440re.match(r.version): + raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) setup(**setup_args) if __name__ == '__main__': From 6dd95701b8e750b8024154b4c03afa4ea7986992 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jan 2016 15:38:41 -0800 Subject: [PATCH 0119/4859] Refactor to exit and raise immediately on exit. Sadly make it python 2 also. --- IPython/terminal/embed.py | 48 +++++++++++---------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index ddb10291b90..4efca4c83c1 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -46,41 +46,19 @@ def kill_embedded(self, parameter_s=''): print ("This embedded IPython will not reactivate anymore " "once you exit.") - if sys.version_info > (3,): - - @line_magic - def raise_on_exit(self, parameter_s=''): - """%raise_on_exit [True|False]: Make the current embeded kernel to raise an exception on exit. - - You can change that again during current session by calling `%raise_on_exit` with `True`/`False` as parameter - - This function (after asking for confirmation) sets an internal flag so - that an embedded IPython will raise a `KillEmbeded` Exception on exit. This is useful to - permanently exit a loop that create IPython embed instance. - - Available only for Python 3. - """ - parameter_s = parameter_s.strip().lower() - - should_raise = None - if parameter_s in {'yes', 'raise', 'true', '1'}: - should_raise = True - elif parameter_s in {'no', 'false', '0', 'None'}: - should_raise = False - else: - if self.shell.should_raise : - print("The current embed instance will raise on exit, use `%raise_on_exit False` to disable") - return - else: - print("The current embed instance will not raise on exit, use `%raise_on_exit True` to enable") - return - - if should_raise: - self.shell.should_raise = True - print ("This embedded IPython will raise while exiting.") - else : - self.shell.should_raise = False - print ("This embedded IPython will not raise while exiting.") + + @line_magic + def exit_raise(self, parameter_s=''): + """%exit_raise Make the current embedded kernel exit and raise and exception. + + This function (after asking for confirmation) sets an internal flag so + that an embedded IPython will raise a `KillEmbeded` Exception on exit. + This is useful to permanently exit a loop that create IPython embed + instance. + """ + + self.shell.should_raise = True + self.shell.ask_exit() From 9360f0d2d2152b950cacda24f677c7058626f099 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jan 2016 16:49:59 -0800 Subject: [PATCH 0120/4859] Explicitely install traitlets on travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 291473c99ff..dd39336abec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ 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" - - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] + - pip install "setuptools>=18.5" + - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] traitlets - pip install codecov script: - cd /tmp && iptest --coverage xml && cd - From 14e61a50e22a21b07e77a2e43b1756a206116208 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jan 2016 16:57:42 -0800 Subject: [PATCH 0121/4859] Check verison number only at build time or pip install -e fails --- .travis.yml | 4 ++-- setup.py | 14 +++++++++----- setupbase.py | 13 +++++++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index dd39336abec..291473c99ff 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ 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" - - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] traitlets + - pip install "setuptools>=18.5" + - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] - pip install codecov script: - cd /tmp && iptest --coverage xml && cd - diff --git a/setup.py b/setup.py index c5a8bf53770..7fcc724ec36 100755 --- a/setup.py +++ b/setup.py @@ -292,13 +292,17 @@ def run(self): setup_args.update(setuptools_extra_args) -# loose as `.dev` is suppose to be invalid -loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') def main(): - import IPython.core.release as r - if not loose_pep440re.match(r.version): - raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) + try: + # loose as `.dev` is suppose to be invalid + print("check version number") + loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') + import IPython.core.release as r + if not loose_pep440re.match(r.version): + raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) + except: + pass setup(**setup_args) if __name__ == '__main__': diff --git a/setupbase.py b/setupbase.py index 68b51b2ea2f..9d801f408d7 100644 --- a/setupbase.py +++ b/setupbase.py @@ -14,7 +14,7 @@ from __future__ import print_function -import errno +import re import os import sys @@ -24,10 +24,7 @@ from distutils.command.install import install from distutils.command.install_scripts import install_scripts from distutils.cmd import Command -from distutils.errors import DistutilsExecError -from fnmatch import fnmatch from glob import glob -from subprocess import Popen, PIPE from setupext import install_data_ext @@ -426,6 +423,14 @@ def git_prebuild(pkg_dir, build_cmd=build_py): class MyBuildPy(build_cmd): ''' Subclass to write commit data into installation tree ''' def run(self): + # loose as `.dev` is suppose to be invalid + print("check version number") + loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') + import IPython.core.release as r + if not loose_pep440re.match(r.version): + raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) + + build_cmd.run(self) # this one will only fire for build commands if hasattr(self, 'build_lib'): From f0d27b8ca714487621c0df03473e6ad34870e188 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jan 2016 16:58:50 -0800 Subject: [PATCH 0122/4859] Clean setup.py --- setup.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/setup.py b/setup.py index 7fcc724ec36..7354bfa603c 100755 --- a/setup.py +++ b/setup.py @@ -23,7 +23,6 @@ from __future__ import print_function import sys -import re # This check is also made in IPython/__init__, don't forget to update both when # changing Python version requirements. @@ -294,15 +293,6 @@ def run(self): def main(): - try: - # loose as `.dev` is suppose to be invalid - print("check version number") - loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') - import IPython.core.release as r - if not loose_pep440re.match(r.version): - raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) - except: - pass setup(**setup_args) if __name__ == '__main__': From 39ce2053aeb43223a110a9e4bc8f3c47ea7bd98d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 26 Jan 2016 12:24:30 +0000 Subject: [PATCH 0123/4859] Allow IPython to start when PYTHONOPTIMIZE=2 Closes gh-8971 --- IPython/utils/py3compat.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/utils/py3compat.py b/IPython/utils/py3compat.py index 4f0ed410b32..f42f55c959b 100644 --- a/IPython/utils/py3compat.py +++ b/IPython/utils/py3compat.py @@ -47,7 +47,9 @@ def wrapper(func_or_str): func = func_or_str doc = func.__doc__ - doc = str_change_func(doc) + # PYTHONOPTIMIZE=2 strips docstrings, so they can disappear unexpectedly + if doc is not None: + doc = str_change_func(doc) if func: func.__doc__ = doc From 8a1aee298716dd71165eb66f7d297ec4b5b151a3 Mon Sep 17 00:00:00 2001 From: Peter Waller Date: Tue, 26 Jan 2016 13:13:27 +0000 Subject: [PATCH 0124/4859] Clarify display_html docs in case of no HTML repr If there is no HTML representation for the object, nothing is shown. See also #9172. --- IPython/core/display.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/display.py b/IPython/core/display.py index 32889500e0d..b522c0ec403 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -185,6 +185,9 @@ 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. Parameters ---------- From 39c534a7283b3f2d02493521302cda05f0a50daa Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 26 Jan 2016 13:33:53 +0000 Subject: [PATCH 0125/4859] Tweak elision message --- IPython/core/ultratb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 04470370f27..0a5fcc21800 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -834,7 +834,7 @@ def format_records(self, records, last_unique, recursion_repeat): frames.append(self.format_record(*r)) if recursion_repeat: - frames.append('Last %d frames repeated, from:\n' % recursion_repeat) + frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat) frames.append(self.format_record(*records[last_unique+recursion_repeat+1])) return frames From 872bf4950923ced272bfcf8164157789f1a39d8a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 09:40:36 -0800 Subject: [PATCH 0126/4859] Update docs and error message --- IPython/terminal/embed.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 4efca4c83c1..bc232e02578 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -51,10 +51,9 @@ def kill_embedded(self, parameter_s=''): def exit_raise(self, parameter_s=''): """%exit_raise Make the current embedded kernel exit and raise and exception. - This function (after asking for confirmation) sets an internal flag so - that an embedded IPython will raise a `KillEmbeded` Exception on exit. - This is useful to permanently exit a loop that create IPython embed - instance. + This function sets an internal flag so that an embedded IPython will + raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is + useful to permanently exit a loop that create IPython embed instance. """ self.shell.should_raise = True @@ -148,7 +147,7 @@ def __call__(self, header='', local_ns=None, module=None, dummy=None, print(self.exit_msg) if self.should_raise: - raise KillEmbeded('This instance has been marked as must raise on exit.') + raise KillEmbeded('Embedded IPython raising error, as user requested.') def mainloop(self, local_ns=None, module=None, stack_depth=0, From e1aa5ab3a4006e1e95981f9bc3b0d8b33407c809 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 11:25:08 -0800 Subject: [PATCH 0127/4859] Fix Docs building --- docs/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/requirements.txt b/docs/requirements.txt index 56e97229a18..958b938fc76 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,2 +1,3 @@ -e . ipykernel +setuptools>=18.5 From fce837c72d812c25449624da78aefdddc0b95310 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 11:34:55 -0800 Subject: [PATCH 0128/4859] Release 4.1.rc1 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 6f27f56673e..f5085d4d498 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 1 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'rc1' +_version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From f34c720041dfba9c50bf8f586b257064dcf3146c Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Tue, 26 Jan 2016 12:01:18 -0800 Subject: [PATCH 0129/4859] Set back dev version number after RC1 release. --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index f5085d4d498..cca49ce324a 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 1 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'rc1' +#_version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 0802028bb44e4483b40d5fa3f2456fb1e428548d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 12:01:55 -0800 Subject: [PATCH 0130/4859] Fix release instructions. Closes #9176 --- docs/source/development/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index a75971614f5..0a9481eb53c 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -59,8 +59,8 @@ releases. .. code:: - $ python setup.py sdist --formats=zip,gztar - $ python setup.py bdist_wheel + python setup.py sdist --formats=zip,gztar + python setup.py bdist_wheel --universal 4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. From 4e91a49fd61f7f7b6125e64c06f7fc531a8fac7c Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 27 Jan 2016 10:25:46 +0100 Subject: [PATCH 0131/4859] Don't build universal wheels We can't provide ipython2/ipython3 executables with universal wheels. --- docs/source/development/index.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index 0a9481eb53c..2553d2216ac 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -35,7 +35,7 @@ You can remove all non-tracked files with: .. code:: - $ git clean -xfdi + git clean -xfdi This would ask you for confirmation before removing all untracked files. Make sure the ``dist/`` folder is clean and avoid stale build from @@ -60,7 +60,8 @@ releases. .. code:: python setup.py sdist --formats=zip,gztar - python setup.py bdist_wheel --universal + python2 setup.py bdist_wheel + python3 setup.py bdist_wheel 4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. From b156bccb58668662cf5473dfe749d27d37d7f4d9 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 27 Jan 2016 10:38:11 +0100 Subject: [PATCH 0132/4859] run update_whatsnew --- docs/source/whatsnew/development.rst | 20 +++++++++++++++++++- docs/source/whatsnew/pr/do_where.rst | 3 --- docs/source/whatsnew/pr/newfeat.rst | 14 -------------- 3 files changed, 19 insertions(+), 18 deletions(-) delete mode 100644 docs/source/whatsnew/pr/do_where.rst delete mode 100644 docs/source/whatsnew/pr/newfeat.rst diff --git a/docs/source/whatsnew/development.rst b/docs/source/whatsnew/development.rst index edc6a93774e..ad6917ac088 100644 --- a/docs/source/whatsnew/development.rst +++ b/docs/source/whatsnew/development.rst @@ -11,6 +11,24 @@ This document describes in-flight development work. `docs/source/whatsnew/pr` folder +IPython debugger (IPdb) now supports the number of context lines for the +``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. +See PR :ghpull:`9097` + +YouTube video will now show thumbnail when exported to a media that do not support video. (:ghpull:`9086`) + +Add warning when running `ipython ` when subcommand is deprecated. `jupyter` should now be used. + +Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`8947`) + +`%aimport` now support module completion. (:ghpull:`8884`) + +`ipdb` output is now colored ! (:ghpull:`8842`) + +Add ability to transpose columns for completion: (:ghpull:`8748`) + +Many many docs improvements and bug fixes, you can see the list of changes [add link to GitHub diff] + .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. @@ -18,4 +36,4 @@ Backwards incompatible changes ------------------------------ -.. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. +.. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. \ No newline at end of file diff --git a/docs/source/whatsnew/pr/do_where.rst b/docs/source/whatsnew/pr/do_where.rst deleted file mode 100644 index 36889d90f2d..00000000000 --- a/docs/source/whatsnew/pr/do_where.rst +++ /dev/null @@ -1,3 +0,0 @@ -IPython debugger (IPdb) now supports the number of context lines for the -``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. -See PR :ghpull:`9097` diff --git a/docs/source/whatsnew/pr/newfeat.rst b/docs/source/whatsnew/pr/newfeat.rst deleted file mode 100644 index 7a3e345e249..00000000000 --- a/docs/source/whatsnew/pr/newfeat.rst +++ /dev/null @@ -1,14 +0,0 @@ -YouTube video will now show thumbnail when exported to a media that do not support video. (:ghpull:`9086`) - -Add warning when running `ipython ` when subcommand is deprecated. `jupyter` should now be used. - -Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`8947`) - -`%aimport` now support module completion. (:ghpull:`8884`) - -`ipdb` output is now colored ! (:ghpull:`8842`) - -Add ability to transpose columns for completion: (:ghpull:`8748`) - -Many many docs improvements and bug fixes, you can see the list of changes [add link to GitHub diff] - From 0fe95653b2e0091f97364b62d4fb83d58dd3a3be Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 27 Jan 2016 16:19:25 +0000 Subject: [PATCH 0133/4859] Fix set_next_input on Python 2 --- IPython/terminal/ptshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 895c9ac27b4..9f81418ef9e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -4,7 +4,7 @@ import sys from IPython.core.interactiveshell import InteractiveShell -from IPython.utils.py3compat import PY3 +from IPython.utils.py3compat import PY3, cast_unicode_py2 from traitlets import Bool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion @@ -177,7 +177,7 @@ def ask_exit(self): def pre_prompt(self): if self.rl_next_input: - self.pt_cli.application.buffer.text = self.rl_next_input + self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input) self.rl_next_input = None def interact(self): From b40a2dd0e08895c827eb936da6c8e8f5997cd51d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 27 Jan 2016 16:38:31 +0000 Subject: [PATCH 0134/4859] Make behaviour more natural with blank lines at the end of input --- IPython/terminal/ptshell.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 9f81418ef9e..58b2ad6f486 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -89,11 +89,13 @@ def init_prompt_toolkit_cli(self): )) def _(event): b = event.current_buffer - if not b.document.on_last_line: + d = b.document + if not (d.on_last_line or d.cursor_position_row >= d.line_count + - d.empty_line_count_at_the_end()): b.newline() return - status, indent = self.input_splitter.check_complete(b.document.text) + status, indent = self.input_splitter.check_complete(d.text) if (status != 'incomplete') and b.accept_action.is_returnable: b.accept_action.validate_and_handle(event.cli, b) From 1b35b82fb32bd3f5e5bb96d4ea5a7822aefdd374 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 16:13:24 -0800 Subject: [PATCH 0135/4859] Fix Image when passing only data, and add tests. Closes #9181 --- IPython/core/display.py | 9 ++++----- IPython/core/tests/test_display.py | 3 +++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index b522c0ec403..bf9590a5468 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -12,7 +12,6 @@ import struct import warnings -from IPython.core.formatters import _safe_get_formatter_method from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, unicode_type) from IPython.testing.skipdoctest import skip_doctest @@ -731,14 +730,14 @@ def __init__(self, data=None, url=None, filename=None, format=None, if data[:2] == _JPEG: format = self._FMT_JPEG - if format.lower() == 'jpg': - # jpg->jpeg - format = self._FMT_JPEG - # failed to detect format, default png if format is None: format = 'png' + if format.lower() == 'jpg': + # jpg->jpeg + format = self._FMT_JPEG + self.format = unicode_type(format).lower() self.embed = embed if embed is not None else (url is None) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index e95a81cb530..d332fc8c9b4 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -43,6 +43,9 @@ def test_retina_jpeg(): nt.assert_equal(md['width'], 1) nt.assert_equal(md['height'], 1) +def test_base64image(): + display.Image("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AAAAACAAHiIbwzAAAAAElFTkSuQmCC") + def test_image_filename_defaults(): '''test format constraint, and validity of jpeg and png''' tpath = ipath.get_ipython_package_dir() From f3b08f3896e4e33e2ca8e925f9f935c9f7de39e4 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 27 Jan 2016 17:58:59 +0100 Subject: [PATCH 0136/4859] fix #9179 2fa login --- tools/gh_api.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/gh_api.py b/tools/gh_api.py index a34e95ddc17..9d7a7d506b9 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -64,6 +64,13 @@ def get_auth_token(): } response = requests.post('https://api.github.com/authorizations', auth=(user, pw), data=json.dumps(auth_request)) + if response.status_code == 401 and response.headers.get('X-GitHub-OTP') == 'required; sms': + print("Your login API resquest a SMS one time password") + sms_pw = getpass.getpass("SMS password: ") + response = requests.post('https://api.github.com/authorizations', + auth=(user, pw), + data=json.dumps(auth_request), + headers={'X-GitHub-OTP':sms_pw}) response.raise_for_status() token = json.loads(response.text)['token'] keyring.set_password('github', fake_username, token) From efef6d6135fbf956bb54e308ac20f62cc31a8fd1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 26 Jan 2016 20:11:30 -0800 Subject: [PATCH 0137/4859] Fix 2fa for gh_stats tools. --- tools/gh_api.py | 2 +- tools/github_stats.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/gh_api.py b/tools/gh_api.py index 9d7a7d506b9..de3fbf3646c 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -17,7 +17,7 @@ try: import requests_cache except ImportError: - print("no cache", file=sys.stderr) + print("cache not available, install `requests_cache` for caching.", file=sys.stderr) else: requests_cache.install_cache("gh_api", expire_after=3600) diff --git a/tools/github_stats.py b/tools/github_stats.py index e170887d78f..fe76affdc94 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -212,8 +212,7 @@ def report(issues, show_urls=False): print("We closed %d issues and merged %d pull requests." % (n_issues, n_pulls)) if milestone: - print("The full list can be seen `on GitHub `__" - % (project, milestone) + print("The full list can be seen `on GitHub `__".format(project=project,milestone=milestone) ) print() From a11bc79715e05a4f98b725e87bcdfb895c07710a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 09:23:47 -0800 Subject: [PATCH 0138/4859] De-duplicate authors, in particular Thomas. --- .mailmap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.mailmap b/.mailmap index bd6544e25c8..2282bd17284 100644 --- a/.mailmap +++ b/.mailmap @@ -132,7 +132,9 @@ Sylvain Corlay Sylvain Corlay sylvain.corlay Ted Drain TD22057 Théophile Studer Théophile Studer +Thomas A Caswell Thomas A Caswell Thomas Kluyver Thomas +Thomas Kluyver Thomas Kluyver Thomas Spura Thomas Spura Timo Paulssen timo vds vds2212 @@ -145,5 +147,7 @@ Ville M. Vainio Ville M. Vainio Ville M. Vainio Ville M. Vainio Walter Doerwald walter.doerwald <> Walter Doerwald Walter Doerwald <> +Wieland Hoffmann Wieland Hoffmann W. Trevor King W. Trevor King Yoval P. y-p + From 8a6cdb0e065d558b50e21ac4571568770678813a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 09:32:36 -0800 Subject: [PATCH 0139/4859] Swap Thomas for correct canonical mail --- .mailmap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.mailmap b/.mailmap index 2282bd17284..5e092be6876 100644 --- a/.mailmap +++ b/.mailmap @@ -133,8 +133,8 @@ Sylvain Corlay sylvain.corlay Ted Drain TD22057 Théophile Studer Théophile Studer Thomas A Caswell Thomas A Caswell -Thomas Kluyver Thomas -Thomas Kluyver Thomas Kluyver +Thomas Kluyver Thomas +Thomas Kluyver Thomas Kluyver Thomas Spura Thomas Spura Timo Paulssen timo vds vds2212 From 9233241bbe4a39749060fb89e94446822c83cbff Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 09:36:00 -0800 Subject: [PATCH 0140/4859] add explicits imports on release tools --- tools/build_release | 2 +- tools/release | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/build_release b/tools/build_release index 1c5246b4d04..e5bf3164364 100755 --- a/tools/build_release +++ b/tools/build_release @@ -5,7 +5,7 @@ import os from shutil import rmtree -from toollib import * +from toollib import sh, pjoin, get_ipdir, cd, compile_tree, execfile, sdists, wheels # Get main ipython dir, this will raise if it doesn't pass some checks ipdir = get_ipdir() diff --git a/tools/release b/tools/release index 78f18052d03..92028740f43 100755 --- a/tools/release +++ b/tools/release @@ -5,7 +5,11 @@ This should ONLY be run at real release time. """ from __future__ import print_function -from toollib import * +import os +import sys + +from toollib import (get_ipdir, pjoin, cd, execfile, version, sh, archive, + sdists, archive_user, archive_dir) from gh_api import post_download # Get main ipython dir, this will raise if it doesn't pass some checks From 86151b821f5a0ad3d6a9245779174bf57dbdffd2 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Thu, 28 Jan 2016 09:36:57 -0800 Subject: [PATCH 0141/4859] Add a core dev section to docs --- docs/source/coredev/index.rst | 67 +++++++++++++++++ docs/source/coredev/release_process.rst | 99 +++++++++++++++++++++++++ docs/source/development/index.rst | 24 +++--- 3 files changed, 175 insertions(+), 15 deletions(-) create mode 100644 docs/source/coredev/index.rst create mode 100644 docs/source/coredev/release_process.rst diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst new file mode 100644 index 00000000000..3d5445ca08f --- /dev/null +++ b/docs/source/coredev/index.rst @@ -0,0 +1,67 @@ +.. _core_developer_guide: + +================================== +Developer's guide for core IPython +================================== + +This guide documents the development of core *IPython itself*. Developers of +third party tools and libraries that use IPython should see the +:doc:`development/index` at `Developer's guide for Third Party Tools and Libraries`. + +Developers working on IPython itself should also consult the +`developer information `_ +on the IPython GitHub wiki. + +.. toctree:: + :maxdepth: 1 + + release_process + +Making an IPython release +========================= + +Make sure the repository is clean of any file that could be problematic. +You can remove all non-tracked files with: + +.. code:: + + git clean -xfdi + +This would ask you for confirmation before removing all untracked files. Make +sure the ``dist/`` folder is clean and avoid stale build from +previous attempts. + +1. Update version number in ``IPython/core/release.py``. + +Make sure the version number match pep440, in particular, `rc` and `beta` are +not separated by `.` or the `sdist` and `bdist` will appear as different +releases. + +2. Commit and tag the release with the current version number: + +.. code:: + + git commit -am "release $VERSION" + git tag $VERSION + + +3. You are now ready to build the ``sdist`` and ``wheel``: + +.. code:: + + python setup.py sdist --formats=zip,gztar + python2 setup.py bdist_wheel + python3 setup.py bdist_wheel + + +4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. +Make sure to use `twine `_ to upload the archives over SSL. + +.. code:: + + $ twine upload dist/* + +5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. + +6. Push directly on master, not forgetting to push ``--tags``. + diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst new file mode 100644 index 00000000000..f45b7a70d51 --- /dev/null +++ b/docs/source/coredev/release_process.rst @@ -0,0 +1,99 @@ +This document contains notes about the process that is used to release IPython. +Our release process is currently not very formal and could be improved. + +Most of the release process is automated by the `release` script in the `tools` +directory of our main repository. This document is just a handy reminder for +the release manager. + +# 0. Environment variables + +You can set some env variables to note previous release tag and current release milestone, version, and git tag: + + PREV_RELEASE=rel-1.0.0 + MILESTONE=1.1 + VERSION=1.1.0 + TAG="rel-$VERSION" + BRANCH=master + +These will be used later if you want to copy/paste, or you can just type the appropriate command when the time comes. These variables are not used by scripts (hence no `export`). + +# 1. Finish release notes + +- If a major release: + + - merge any pull request notes into what's new: + + python tools/update_whatsnew.py + + - update `docs/source/whatsnew/development.rst`, to ensure it covers the major points. + - move the contents of `development.rst` to `versionX.rst` +- generate summary of GitHub contributions, which can be done with: + + python tools/github_stats.py --milestone $MILESTONE > stats.rst + + which may need some manual cleanup. Add the cleaned up result and add it to `docs/source/whatsnew/github-stats-X.rst` (make a new file, or add it to the top, depending on whether it is a major release). + You can use: + + git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f + + to find duplicates and update `.mailmap`. + Before generating the GitHub stats, verify that all closed issues and pull requests [have appropriate milestones](https://github.com/ipython/ipython/wiki/Dev%3A-GitHub-workflow#milestones). [This search](https://github.com/ipython/ipython/issues?q=is%3Aclosed+no%3Amilestone+is%3Aissue) should return no results. + +# 2. Run the `tools/build_release` script + +This does all the file checking and building that the real release script will do. +This will let you do test installations, check that the build procedure runs OK, etc. +You may want to also do a test build of the docs. + +# 3. Create and push the new tag + +Edit `IPython/core/release.py` to have the current version. + +Commit the changes to release.py and jsversion: + + git commit -am "release $VERSION" + git push origin $BRANCH + +Create and push the tag: + + git tag -am "release $VERSION" "$TAG" + git push origin --tags + +Update release.py back to `x.y-dev` or `x.y-maint`, and push: + + git commit -am "back to development" + git push origin $BRANCH + +# 4. Get a fresh clone of the tag for building the release: + + cd /tmp + git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" + +# 5. Run the `release` script + + cd tools && ./release + +This makes the tarballs, zipfiles, and wheels. It posts them to archive.ipython.org and +registers the release with PyPI. + +This will require that you have current wheel, Python 3.4 and Python 2.7. + +# 7. Update the IPython website + +- release announcement (news, announcements) +- update current version and download links +- (If major release) update links on the documentation page + +# 8. Drafting a short release announcement + +This should include i) highlights and ii) a link to the html version of +the *What's new* section of the documentation. + +Post to mailing list, and link from Twitter. + +# 9. Update milestones on GitHub + +- close the milestone you just released +- open new milestone for (x, y+1), if it doesn't exist already + +# 10. Celebrate! diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index 2553d2216ac..42bd32724ae 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -1,20 +1,14 @@ .. _developer_guide: -========================= -IPython developer's guide -========================= - -This are two categories of developer focused documentation: - -1. Documentation for developers of *IPython itself*. -2. Documentation for developers of third party tools and libraries - that use IPython. - -This part of our documentation only contains information in the second category. - -Developers interested in working on IPython itself should consult -our `developer information `_ -on the IPython GitHub wiki. +===================================================== +Developer's guide for Third Party Tools and Libraries +===================================================== + +.. important: + + This guide contains information for developers of third party tools and + libraries that use IPython. Documentation for developers of core + *IPython itself* can be found in the :doc:`coredev/index`. .. toctree:: :maxdepth: 1 From 0afa956dcdc1c4cf60e904bee88514eb646da36e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 09:43:32 -0800 Subject: [PATCH 0142/4859] Update release script not to upload insecurly --- tools/release | 13 ++++++++----- tools/toollib.py | 1 - 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/release b/tools/release index 78f18052d03..017f5534f1c 100755 --- a/tools/release +++ b/tools/release @@ -51,17 +51,19 @@ if 'upload' not in sys.argv: sys.exit(0) # Register with the Python Package Index (PyPI) -print( 'Registering with PyPI...') +print( 'Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted') cd(ipdir) -sh('./setup.py register') +# sh('./setup.py register') # Upload all files -sh(sdists + ' upload') +sh(sdists) for py in ('2.7', '3.4'): - sh('python%s setupegg.py bdist_wheel upload' % py) + sh('python%s setupegg.py bdist_wheel' % py) + +print('Will not upload with setuptools as upload connection is insecure. Please use `twine upload dist/*` to upload the files to PyPI') cd(distdir) -print( 'Uploading distribution files...') +print( 'Uploading distribution files to GitHub...') for fname in os.listdir('.'): # TODO: update to GitHub releases API @@ -71,6 +73,7 @@ for fname in os.listdir('.'): post_download("ipython/ipython", fname, description=desc) # Make target dir if it doesn't exist +print('Uploading IPython to backup site.') sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version)) sh('scp * %s' % release_site) diff --git a/tools/toollib.py b/tools/toollib.py index 48028e97965..020560bb779 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -4,7 +4,6 @@ # Library imports import os -import sys # Useful shorthands pjoin = os.path.join From 60d73c57455d1c12147832244c04709628d09d35 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 09:54:32 -0800 Subject: [PATCH 0143/4859] turn print into comment --- tools/release | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/release b/tools/release index 017f5534f1c..e07fc3acb78 100755 --- a/tools/release +++ b/tools/release @@ -50,10 +50,8 @@ if 'upload' not in sys.argv: print("`./release upload` to register and release") sys.exit(0) -# Register with the Python Package Index (PyPI) -print( 'Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted') +# Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted cd(ipdir) -# sh('./setup.py register') # Upload all files sh(sdists) From f55cccf5b15f0ddedf2f38f9cf76fcc709787f96 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 10:51:12 -0800 Subject: [PATCH 0144/4859] Improve build script. - does not compile git folder. - go a step further when building various things, upload at as lat step. --- tools/build_release | 2 +- tools/release | 14 ++++++++------ tools/toollib.py | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/build_release b/tools/build_release index e5bf3164364..65efd11b581 100755 --- a/tools/build_release +++ b/tools/build_release @@ -15,7 +15,7 @@ cd(ipdir) execfile(pjoin('IPython', 'core', 'release.py'), globals()) # Check that everything compiles -compile_tree() +compile_tree('*') # Cleanup for d in ['build', 'dist', pjoin('docs', 'build'), pjoin('docs', 'dist'), diff --git a/tools/release b/tools/release index 5ba7c19b0fc..c6c8909920d 100755 --- a/tools/release +++ b/tools/release @@ -8,7 +8,7 @@ from __future__ import print_function import os import sys -from toollib import (get_ipdir, pjoin, cd, execfile, version, sh, archive, +from toollib import (get_ipdir, pjoin, cd, execfile, sh, archive, sdists, archive_user, archive_dir) from gh_api import post_download @@ -26,6 +26,7 @@ if not os.path.exists(ipbackupdir): cd(ipdir) # Load release info +version = None execfile(pjoin('IPython','core','release.py'), globals()) # Build site addresses for file uploads @@ -50,18 +51,19 @@ sh('mv ipython-*.tgz %s' % ipbackupdir) # Build release files sh('./build_release %s' % ipdir) -if 'upload' not in sys.argv: - print("`./release upload` to register and release") - sys.exit(0) - # Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted cd(ipdir) # Upload all files sh(sdists) -for py in ('2.7', '3.4'): +for py in ('2', '3'): sh('python%s setupegg.py bdist_wheel' % py) +if 'upload' not in sys.argv: + print("`./release upload` to register and release") + sys.exit(0) + + print('Will not upload with setuptools as upload connection is insecure. Please use `twine upload dist/*` to upload the files to PyPI') cd(distdir) diff --git a/tools/toollib.py b/tools/toollib.py index 020560bb779..7406c2b1251 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -48,9 +48,9 @@ def get_ipdir(): return ipdir -def compile_tree(): +def compile_tree(folder='.'): """Compile all Python files below current directory.""" - stat = os.system('python -m compileall .') + stat = os.system('python -m compileall {}'.format(folder)) if stat: msg = '*** ERROR: Some Python files in tree do NOT compile! ***\n' msg += 'See messages above for the actual file that produced it.\n' From 8532e5ef0777d78870d88d5cfafd657b189a82d9 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Thu, 28 Jan 2016 14:28:33 -0800 Subject: [PATCH 0145/4859] Migrate the wiki contents to release process doc --- docs/source/coredev/index.rst | 50 +-------- docs/source/coredev/old_release_doc.rst | 50 +++++++++ docs/source/coredev/release_process.rst | 129 ++++++++++++++++-------- docs/source/development/index.rst | 6 +- docs/source/index.rst | 1 + 5 files changed, 141 insertions(+), 95 deletions(-) create mode 100644 docs/source/coredev/old_release_doc.rst diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 3d5445ca08f..306b8cc243a 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -16,52 +16,4 @@ on the IPython GitHub wiki. :maxdepth: 1 release_process - -Making an IPython release -========================= - -Make sure the repository is clean of any file that could be problematic. -You can remove all non-tracked files with: - -.. code:: - - git clean -xfdi - -This would ask you for confirmation before removing all untracked files. Make -sure the ``dist/`` folder is clean and avoid stale build from -previous attempts. - -1. Update version number in ``IPython/core/release.py``. - -Make sure the version number match pep440, in particular, `rc` and `beta` are -not separated by `.` or the `sdist` and `bdist` will appear as different -releases. - -2. Commit and tag the release with the current version number: - -.. code:: - - git commit -am "release $VERSION" - git tag $VERSION - - -3. You are now ready to build the ``sdist`` and ``wheel``: - -.. code:: - - python setup.py sdist --formats=zip,gztar - python2 setup.py bdist_wheel - python3 setup.py bdist_wheel - - -4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. -Make sure to use `twine `_ to upload the archives over SSL. - -.. code:: - - $ twine upload dist/* - -5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. - -6. Push directly on master, not forgetting to push ``--tags``. - + old_release_doc diff --git a/docs/source/coredev/old_release_doc.rst b/docs/source/coredev/old_release_doc.rst new file mode 100644 index 00000000000..480cc969f0c --- /dev/null +++ b/docs/source/coredev/old_release_doc.rst @@ -0,0 +1,50 @@ +.. old_release_doc:: + +Making an IPython release [TODO:: Can this be replaced by the Release Process document???] +========================================================================================== + +Make sure the repository is clean of any file that could be problematic. +You can remove all non-tracked files with: + +.. code:: + + git clean -xfdi + +This would ask you for confirmation before removing all untracked files. Make +sure the ``dist/`` folder is clean and avoid stale build from +previous attempts. + +1. Update version number in ``IPython/core/release.py``. + +Make sure the version number match pep440, in particular, `rc` and `beta` are +not separated by `.` or the `sdist` and `bdist` will appear as different +releases. + +2. Commit and tag the release with the current version number: + +.. code:: + + git commit -am "release $VERSION" + git tag $VERSION + + +3. You are now ready to build the ``sdist`` and ``wheel``: + +.. code:: + + python setup.py sdist --formats=zip,gztar + python2 setup.py bdist_wheel + python3 setup.py bdist_wheel + + +4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. +Make sure to use `twine `_ to upload the archives over SSL. + +.. code:: + + $ twine upload dist/* + +5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. + +6. Push directly on master, not forgetting to push ``--tags``. + diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index f45b7a70d51..c6e312faf5d 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -1,13 +1,20 @@ -This document contains notes about the process that is used to release IPython. -Our release process is currently not very formal and could be improved. +.. _release_process: -Most of the release process is automated by the `release` script in the `tools` -directory of our main repository. This document is just a handy reminder for -the release manager. +====================== +Releasing core IPython +====================== -# 0. Environment variables +This document contains the process that is used to create an IPython release. -You can set some env variables to note previous release tag and current release milestone, version, and git tag: +Conveniently, the `release` script in the `tools` directory of the `IPython` +repository automates most of the release process. This document serves as a +handy reminder and checklist for the release manager. + +#. Set Environment variables +---------------------------- + +Set environment variables to document previous release tag, current +release milestone, current release version, and git tag: PREV_RELEASE=rel-1.0.0 MILESTONE=1.1 @@ -15,37 +22,58 @@ You can set some env variables to note previous release tag and current release TAG="rel-$VERSION" BRANCH=master -These will be used later if you want to copy/paste, or you can just type the appropriate command when the time comes. These variables are not used by scripts (hence no `export`). +These variables may be used later to copy/paste as answers to the script +questions instead of typing the appropriate command when the time comes. These +variables are not used by the scripts directly; therefore, there is no need to +`export` the variables. + +#. Finish release notes +----------------------- + +.. note:: -# 1. Finish release notes + Before generating the GitHub stats, verify that all closed issues and + pull requests `have appropriate milestones `_. + `This search `_ + should return no results before creating the GitHub stats. -- If a major release: +If a major release: - - merge any pull request notes into what's new: + - merge any pull request notes into what's new:: python tools/update_whatsnew.py - - update `docs/source/whatsnew/development.rst`, to ensure it covers the major points. - - move the contents of `development.rst` to `versionX.rst` -- generate summary of GitHub contributions, which can be done with: + - update `docs/source/whatsnew/development.rst`, to ensure it covers + the major release features + - move the contents of `development.rst` to `versionX.rst` where `X` is + the numerical release version + - generate summary of GitHub contributions, which can be done with:: - python tools/github_stats.py --milestone $MILESTONE > stats.rst + python tools/github_stats.py --milestone $MILESTONE > stats.rst - which may need some manual cleanup. Add the cleaned up result and add it to `docs/source/whatsnew/github-stats-X.rst` (make a new file, or add it to the top, depending on whether it is a major release). - You can use: + which may need some manual cleanup of `stats.rst`. Add the cleaned + `stats.rst` results to `docs/source/whatsnew/github-stats-X.rst` where + `X` is the numerical release version. If creating a major release, make + a new `github-stats-X.rst` file; if creating a minor release, the + content from `stats.rst` may simply be added to the top of an existing + `github-stats-X.rst` file. - git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f +To find duplicates and update `.mailmap`, use: - to find duplicates and update `.mailmap`. - Before generating the GitHub stats, verify that all closed issues and pull requests [have appropriate milestones](https://github.com/ipython/ipython/wiki/Dev%3A-GitHub-workflow#milestones). [This search](https://github.com/ipython/ipython/issues?q=is%3Aclosed+no%3Amilestone+is%3Aissue) should return no results. + git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f -# 2. Run the `tools/build_release` script -This does all the file checking and building that the real release script will do. -This will let you do test installations, check that the build procedure runs OK, etc. -You may want to also do a test build of the docs. +#. Run the `tools/build_release` script +--------------------------------------- -# 3. Create and push the new tag +This does all the file checking and building that the real release script will +do. This makes test installations, checks that the build procedure runs OK, +and tests other steps in the release process. + +We encourage creating a test build of the docs as well. + +#. Create and push the new tag +------------------------------ Edit `IPython/core/release.py` to have the current version. @@ -64,36 +92,51 @@ Update release.py back to `x.y-dev` or `x.y-maint`, and push: git commit -am "back to development" git push origin $BRANCH -# 4. Get a fresh clone of the tag for building the release: +#. Get a fresh clone +-------------------- - cd /tmp - git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" +Get a fresh clone of the tag for building the release: -# 5. Run the `release` script + cd /tmp + git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" - cd tools && ./release +#. Run the release script +------------------------- -This makes the tarballs, zipfiles, and wheels. It posts them to archive.ipython.org and -registers the release with PyPI. +Run the `release` script:: -This will require that you have current wheel, Python 3.4 and Python 2.7. + cd tools && ./release -# 7. Update the IPython website +This makes the tarballs, zipfiles, and wheels. It posts +them to archive.ipython.org and registers the release with PyPI. -- release announcement (news, announcements) -- update current version and download links -- (If major release) update links on the documentation page +This step requires having a current wheel, Python 3.4 and Python 2.7. -# 8. Drafting a short release announcement +#. Draft a short release announcement +------------------------------------- This should include i) highlights and ii) a link to the html version of the *What's new* section of the documentation. -Post to mailing list, and link from Twitter. +Post the announcement to the mailing list, and link from Twitter. + +#. Update milestones on GitHub +------------------------------ + +- close the just released milestone +- open a new milestone for the next release (x, y+1), if the milestone doesn't + exist already + +#. Update the IPython website +----------------------------- +The IPython website should document the new release: + +- add release announcement (news, announcements) +- update current version and download links +- update links on the documentation page (especially if a major release) -# 9. Update milestones on GitHub +#. Celebrate! +------------- -- close the milestone you just released -- open new milestone for (x, y+1), if it doesn't exist already +Celebrate the release and thank the contributors for their work. -# 10. Celebrate! diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index 42bd32724ae..e346b844b40 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -5,9 +5,9 @@ Developer's guide for Third Party Tools and Libraries ===================================================== .. important: - + This guide contains information for developers of third party tools and - libraries that use IPython. Documentation for developers of core + libraries that use IPython. Documentation for developers of co *IPython itself* can be found in the :doc:`coredev/index`. .. toctree:: @@ -24,7 +24,7 @@ Developer's guide for Third Party Tools and Libraries Making an IPython release ========================= -Make sure the repository is clean of any file that could be problematic. +Make sure the repository is clean of any file that could be problematic. You can remove all non-tracked files with: .. code:: diff --git a/docs/source/index.rst b/docs/source/index.rst index 4423601a2ac..fc948f13fed 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,6 +21,7 @@ Contents interactive/index config/index development/index + coredev/index api/index about/index From 8e7473017f27caa060cd68418ec5d833b99ee1de Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Thu, 28 Jan 2016 15:22:20 -0800 Subject: [PATCH 0146/4859] Fix up rst formatting --- docs/source/coredev/index.rst | 12 ++--- docs/source/coredev/old_release_doc.rst | 4 +- docs/source/coredev/release_process.rst | 57 +++++++++++++----------- docs/source/development/index.rst | 59 +++---------------------- 4 files changed, 45 insertions(+), 87 deletions(-) diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 306b8cc243a..69c70c6f94f 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -1,15 +1,15 @@ .. _core_developer_guide: ================================== -Developer's guide for core IPython +Developer's guide to core IPython ================================== -This guide documents the development of core *IPython itself*. Developers of -third party tools and libraries that use IPython should see the -:doc:`development/index` at `Developer's guide for Third Party Tools and Libraries`. +This guide documents the development of core IPython. Alternatively, +developers of third party tools and libraries that use IPython should see the +:doc:`../development/index`. -Developers working on IPython itself should also consult the -`developer information `_ +Developers working on core IPython should also consult the +`developer information `_ on the IPython GitHub wiki. .. toctree:: diff --git a/docs/source/coredev/old_release_doc.rst b/docs/source/coredev/old_release_doc.rst index 480cc969f0c..3040497199f 100644 --- a/docs/source/coredev/old_release_doc.rst +++ b/docs/source/coredev/old_release_doc.rst @@ -1,7 +1,7 @@ .. old_release_doc:: -Making an IPython release [TODO:: Can this be replaced by the Release Process document???] -========================================================================================== +Making an IPython release [TODO:: Can this content by removed ???] +================================================================== Make sure the repository is clean of any file that could be problematic. You can remove all non-tracked files with: diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index c6e312faf5d..6a3e0e9c60b 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -10,11 +10,11 @@ Conveniently, the `release` script in the `tools` directory of the `IPython` repository automates most of the release process. This document serves as a handy reminder and checklist for the release manager. -#. Set Environment variables +1. Set Environment variables ---------------------------- Set environment variables to document previous release tag, current -release milestone, current release version, and git tag: +release milestone, current release version, and git tag:: PREV_RELEASE=rel-1.0.0 MILESTONE=1.1 @@ -27,13 +27,13 @@ questions instead of typing the appropriate command when the time comes. These variables are not used by the scripts directly; therefore, there is no need to `export` the variables. -#. Finish release notes ------------------------ +2. Create GitHub stats and finish release note +---------------------------------------------- .. note:: Before generating the GitHub stats, verify that all closed issues and - pull requests `have appropriate milestones `_. + pull requests have `appropriate milestones `_. `This search `_ should return no results before creating the GitHub stats. @@ -58,49 +58,49 @@ If a major release: content from `stats.rst` may simply be added to the top of an existing `github-stats-X.rst` file. -To find duplicates and update `.mailmap`, use: +To find duplicates and update `.mailmap`, use:: git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f -#. Run the `tools/build_release` script +3. Run the `tools/build_release` script --------------------------------------- -This does all the file checking and building that the real release script will -do. This makes test installations, checks that the build procedure runs OK, -and tests other steps in the release process. +Running `tools/build_release` does all the file checking and building that +the real release script will do. This makes test installations, checks that +the build procedure runs OK, and tests other steps in the release process. We encourage creating a test build of the docs as well. -#. Create and push the new tag +4. Create and push the new tag ------------------------------ Edit `IPython/core/release.py` to have the current version. -Commit the changes to release.py and jsversion: +Commit the changes to release.py and jsversion:: git commit -am "release $VERSION" git push origin $BRANCH -Create and push the tag: +Create and push the tag:: git tag -am "release $VERSION" "$TAG" git push origin --tags -Update release.py back to `x.y-dev` or `x.y-maint`, and push: +Update release.py back to `x.y-dev` or `x.y-maint`, and push:: git commit -am "back to development" git push origin $BRANCH -#. Get a fresh clone +5. Get a fresh clone -------------------- -Get a fresh clone of the tag for building the release: +Get a fresh clone of the tag for building the release:: cd /tmp git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" -#. Run the release script +6. Run the release script ------------------------- Run the `release` script:: @@ -112,31 +112,38 @@ them to archive.ipython.org and registers the release with PyPI. This step requires having a current wheel, Python 3.4 and Python 2.7. -#. Draft a short release announcement +7. Draft a short release announcement ------------------------------------- -This should include i) highlights and ii) a link to the html version of -the *What's new* section of the documentation. +The announcement should include: + +- release highlights +- a link to the html version of the *What's new* section of the documentation +- a link to upgrade or installation tips (if necessary) Post the announcement to the mailing list, and link from Twitter. -#. Update milestones on GitHub +8. Update milestones on GitHub ------------------------------ +These steps will bring milestones up to date: + - close the just released milestone - open a new milestone for the next release (x, y+1), if the milestone doesn't exist already -#. Update the IPython website +9. Update the IPython website ----------------------------- + The IPython website should document the new release: - add release announcement (news, announcements) - update current version and download links - update links on the documentation page (especially if a major release) -#. Celebrate! -------------- +10. Celebrate! +-------------- -Celebrate the release and thank the contributors for their work. +Celebrate the release and please thank the contributors for their work. Great +job! diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index e346b844b40..a94562555f4 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -1,14 +1,14 @@ .. _developer_guide: ===================================================== -Developer's guide for Third Party Tools and Libraries +Developer's guide for third party tools and libraries ===================================================== -.. important: +.. important:: This guide contains information for developers of third party tools and - libraries that use IPython. Documentation for developers of co - *IPython itself* can be found in the :doc:`coredev/index`. + libraries that use IPython. Alternatively, documentation for core + **IPython** development can be found in the :doc:`../coredev/index`. .. toctree:: :maxdepth: 1 @@ -19,53 +19,4 @@ Developer's guide for Third Party Tools and Libraries lexer pycompat config - inputhook_app - -Making an IPython release -========================= - -Make sure the repository is clean of any file that could be problematic. -You can remove all non-tracked files with: - -.. code:: - - git clean -xfdi - -This would ask you for confirmation before removing all untracked files. Make -sure the ``dist/`` folder is clean and avoid stale build from -previous attempts. - -1. Update version number in ``IPython/core/release.py``. - -Make sure the version number match pep440, in particular, `rc` and `beta` are -not separated by `.` or the `sdist` and `bdist` will appear as different -releases. - -2. Commit and tag the release with the current version number: - -.. code:: - - git commit -am "release $VERSION" - git tag $VERSION - - -3. You are now ready to build the ``sdist`` and ``wheel``: - -.. code:: - - python setup.py sdist --formats=zip,gztar - python2 setup.py bdist_wheel - python3 setup.py bdist_wheel - - -4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. -Make sure to use `twine `_ to upload the archives over SSL. - -.. code:: - - $ twine upload dist/* - -5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. - -6. Push directly on master, not forgetting to push ``--tags``. - + inputhook_app \ No newline at end of file From 2f458ab8123b82542e10280b74946599c878ddab Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Thu, 28 Jan 2016 16:42:58 -0800 Subject: [PATCH 0147/4859] Update release process docs --- docs/source/coredev/index.rst | 2 +- docs/source/coredev/making_release.rst | 56 +++++++++++++++++++++++++ docs/source/coredev/old_release_doc.rst | 50 ---------------------- docs/source/coredev/release_process.rst | 6 +-- 4 files changed, 60 insertions(+), 54 deletions(-) create mode 100644 docs/source/coredev/making_release.rst delete mode 100644 docs/source/coredev/old_release_doc.rst diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 69c70c6f94f..0999547ab71 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -16,4 +16,4 @@ on the IPython GitHub wiki. :maxdepth: 1 release_process - old_release_doc + making_release diff --git a/docs/source/coredev/making_release.rst b/docs/source/coredev/making_release.rst new file mode 100644 index 00000000000..273d5af8cc1 --- /dev/null +++ b/docs/source/coredev/making_release.rst @@ -0,0 +1,56 @@ +.. making_release:: + +Making an IPython release +========================= + +1. Make sure the repository is clean of any file that could be problematic. + Remove all non-tracked files with: + + .. code:: + + git clean -xfdi + + This will ask for confirmation before removing all untracked files. Make + sure the ``dist/`` folder is clean to avoid any stale builds from + previous build attempts. + +2. Update version number and ``_version_extra`` content in + ``IPython/core/release.py``. + + Make sure the version number matches pep440, in particular, `rc` and `beta` + are not separated by `.` or the `sdist` and `bdist` will appear as different + releases. For example, a valid version number for a release candidate (rc) + release is: ``1.3rc1``. Notice that there is no separator between the '3' + and the 'r'. + + +3. Commit and tag the release with the current version number: + + .. code:: + + git commit -am "release $VERSION" + git tag $VERSION + + +4. Build the ``sdist`` and ``wheel``: + + .. code:: + + python setup.py sdist --formats=zip,gztar + python2 setup.py bdist_wheel + python3 setup.py bdist_wheel + + +5. Be sure to test the ``wheel`` and the ``sdist`` locally before uploading + them to PyPI. Make sure to use `twine `_ to + upload these archives over SSL. + + .. code:: + + $ twine upload dist/* + +6. If all went well, change the ``_version_extra = ''`` in + ``IPython/core/release.py`` back to the ``.dev`` suffix, or + ``_version_extra='.dev'``. + +7. Push directly to master, remembering to push ``--tags`` too. \ No newline at end of file diff --git a/docs/source/coredev/old_release_doc.rst b/docs/source/coredev/old_release_doc.rst deleted file mode 100644 index 3040497199f..00000000000 --- a/docs/source/coredev/old_release_doc.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. old_release_doc:: - -Making an IPython release [TODO:: Can this content by removed ???] -================================================================== - -Make sure the repository is clean of any file that could be problematic. -You can remove all non-tracked files with: - -.. code:: - - git clean -xfdi - -This would ask you for confirmation before removing all untracked files. Make -sure the ``dist/`` folder is clean and avoid stale build from -previous attempts. - -1. Update version number in ``IPython/core/release.py``. - -Make sure the version number match pep440, in particular, `rc` and `beta` are -not separated by `.` or the `sdist` and `bdist` will appear as different -releases. - -2. Commit and tag the release with the current version number: - -.. code:: - - git commit -am "release $VERSION" - git tag $VERSION - - -3. You are now ready to build the ``sdist`` and ``wheel``: - -.. code:: - - python setup.py sdist --formats=zip,gztar - python2 setup.py bdist_wheel - python3 setup.py bdist_wheel - - -4. You can now test the ``wheel`` and the ``sdist`` locally before uploading to PyPI. -Make sure to use `twine `_ to upload the archives over SSL. - -.. code:: - - $ twine upload dist/* - -5. If all went well, change the ``IPython/core/release.py`` back adding the ``.dev`` suffix. - -6. Push directly on master, not forgetting to push ``--tags``. - diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 6a3e0e9c60b..87715fa756d 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -1,8 +1,8 @@ .. _release_process: -====================== -Releasing core IPython -====================== +======================= +IPython release process +======================= This document contains the process that is used to create an IPython release. From d8372424c99ad5aac9ba8dd4ad8a94e19241ac6c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 17:46:09 -0800 Subject: [PATCH 0148/4859] Consolidate the 2 files. --- docs/source/coredev/index.rst | 1 - docs/source/coredev/making_release.rst | 56 ---------------------- docs/source/coredev/release_process.rst | 64 +++++++++++++++++++------ 3 files changed, 50 insertions(+), 71 deletions(-) delete mode 100644 docs/source/coredev/making_release.rst diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 0999547ab71..3d2953933a0 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -16,4 +16,3 @@ on the IPython GitHub wiki. :maxdepth: 1 release_process - making_release diff --git a/docs/source/coredev/making_release.rst b/docs/source/coredev/making_release.rst deleted file mode 100644 index 273d5af8cc1..00000000000 --- a/docs/source/coredev/making_release.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. making_release:: - -Making an IPython release -========================= - -1. Make sure the repository is clean of any file that could be problematic. - Remove all non-tracked files with: - - .. code:: - - git clean -xfdi - - This will ask for confirmation before removing all untracked files. Make - sure the ``dist/`` folder is clean to avoid any stale builds from - previous build attempts. - -2. Update version number and ``_version_extra`` content in - ``IPython/core/release.py``. - - Make sure the version number matches pep440, in particular, `rc` and `beta` - are not separated by `.` or the `sdist` and `bdist` will appear as different - releases. For example, a valid version number for a release candidate (rc) - release is: ``1.3rc1``. Notice that there is no separator between the '3' - and the 'r'. - - -3. Commit and tag the release with the current version number: - - .. code:: - - git commit -am "release $VERSION" - git tag $VERSION - - -4. Build the ``sdist`` and ``wheel``: - - .. code:: - - python setup.py sdist --formats=zip,gztar - python2 setup.py bdist_wheel - python3 setup.py bdist_wheel - - -5. Be sure to test the ``wheel`` and the ``sdist`` locally before uploading - them to PyPI. Make sure to use `twine `_ to - upload these archives over SSL. - - .. code:: - - $ twine upload dist/* - -6. If all went well, change the ``_version_extra = ''`` in - ``IPython/core/release.py`` back to the ``.dev`` suffix, or - ``_version_extra='.dev'``. - -7. Push directly to master, remembering to push ``--tags`` too. \ No newline at end of file diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 87715fa756d..7ab4fc6b736 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -62,8 +62,23 @@ To find duplicates and update `.mailmap`, use:: git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f +3. Make sure the repository is clean +------------------------------------ -3. Run the `tools/build_release` script +of any file that could be problematic. + Remove all non-tracked files with: + + .. code:: + + git clean -xfdi + + This will ask for confirmation before removing all untracked files. Make + sure the ``dist/`` folder is clean to avoid any stale builds from + previous build attempts. + + + +4. Run the `tools/build_release` script --------------------------------------- Running `tools/build_release` does all the file checking and building that @@ -72,11 +87,21 @@ the build procedure runs OK, and tests other steps in the release process. We encourage creating a test build of the docs as well. -4. Create and push the new tag +5. Create and push the new tag ------------------------------ Edit `IPython/core/release.py` to have the current version. +in particular, update version number and ``_version_extra`` content in +``IPython/core/release.py``. + +Make sure the version number matches pep440, in particular, `rc` and `beta` are +not separated by `.` or the `sdist` and `bdist` will appear as different +releases. For example, a valid version number for a release candidate (rc) +release is: ``1.3rc1``. Notice that there is no separator between the '3' and +the 'r'. + + Commit the changes to release.py and jsversion:: git commit -am "release $VERSION" @@ -92,7 +117,7 @@ Update release.py back to `x.y-dev` or `x.y-maint`, and push:: git commit -am "back to development" git push origin $BRANCH -5. Get a fresh clone +6. Get a fresh clone -------------------- Get a fresh clone of the tag for building the release:: @@ -100,19 +125,30 @@ Get a fresh clone of the tag for building the release:: cd /tmp git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" -6. Run the release script +7. Run the release script ------------------------- -Run the `release` script:: +Run the `release` script, this step requires having a current wheel, Python >=3.4 and Python 2.7.:: cd tools && ./release -This makes the tarballs, zipfiles, and wheels. It posts -them to archive.ipython.org and registers the release with PyPI. +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. + +Use the following to actually upload the result of the build: + + ./release upload -This step requires having a current wheel, Python 3.4 and Python 2.7. +It should posts them to ``archive.ipython.org`` and registers the release +with PyPI if you have the various authorisations. -7. Draft a short release announcement +You might need to use `twine `_ (`twine upload +dist/*`) manually to actually upload on PyPI. Unlike setuptools, twine is able +to upload packages over SSL. + + +8. Draft a short release announcement ------------------------------------- The announcement should include: @@ -121,9 +157,9 @@ The announcement should include: - a link to the html version of the *What's new* section of the documentation - a link to upgrade or installation tips (if necessary) -Post the announcement to the mailing list, and link from Twitter. +Post the announcement to the mailing list and or blog, and link from Twitter. -8. Update milestones on GitHub +9. Update milestones on GitHub ------------------------------ These steps will bring milestones up to date: @@ -132,8 +168,8 @@ These steps will bring milestones up to date: - open a new milestone for the next release (x, y+1), if the milestone doesn't exist already -9. Update the IPython website ------------------------------ +10. Update the IPython website +------------------------------ The IPython website should document the new release: @@ -141,7 +177,7 @@ The IPython website should document the new release: - update current version and download links - update links on the documentation page (especially if a major release) -10. Celebrate! +11. Celebrate! -------------- Celebrate the release and please thank the contributors for their work. Great From e4ac2edff151e27b8fec51f31e570c775d2e1104 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 29 Jan 2016 08:57:01 +0100 Subject: [PATCH 0149/4859] missing comma in setuptools requirement --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 7354bfa603c..0d0b7a3d5aa 100755 --- a/setup.py +++ b/setup.py @@ -193,7 +193,7 @@ def run(self): nbconvert = ['nbconvert'], ) install_requires = [ - 'setuptools>=18.5' + 'setuptools>=18.5', 'decorator', 'pickleshare', 'simplegeneric>0.8', From f3b50686512973288029d3ac9cc0dc3de4c2048f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 29 Jan 2016 12:32:43 +0000 Subject: [PATCH 0150/4859] Remove setuptools version check Fixes gh-9196 Checking version numbers isn't that easy. --- setup.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/setup.py b/setup.py index 132ab3d0319..7e0b7159abf 100755 --- a/setup.py +++ b/setup.py @@ -172,9 +172,6 @@ def run(self): if len(needs_setuptools.intersection(sys.argv)) > 0: import setuptools - v = tuple(int(x) for x in setuptools.__version__.split('.')) - if v < (18,5): - raise ValueError('Setuptools version >=18.5 is required, found: %s'%setuptools.__version__) # This dict is used for passing extra arguments that are setuptools # specific to setup From 5d4a78146c3f116a608bc08e39f30c22c23c24fb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jan 2016 11:16:51 -0800 Subject: [PATCH 0151/4859] Update package metadata --- IPython/core/release.py | 6 ++---- setupbase.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index cca49ce324a..576a2c6b899 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -105,12 +105,10 @@ url = 'http://ipython.org' -download_url = 'https://github.com/ipython/ipython/downloads' -platforms = ['Linux','Mac OSX','Windows XP/Vista/7/8'] +platforms = ['Linux','Mac OSX','Windows'] -keywords = ['Interactive','Interpreter','Shell','Parallel','Distributed', - 'Web-based computing', 'Qt console', 'Embedding'] +keywords = ['Interactive','Interpreter','Shell', 'Embedding'] classifiers = [ 'Framework :: IPython', diff --git a/setupbase.py b/setupbase.py index 9d801f408d7..e73641d26f2 100644 --- a/setupbase.py +++ b/setupbase.py @@ -80,7 +80,6 @@ def file_doesnt_endwith(test,endings): author = author, author_email = author_email, url = url, - download_url = download_url, license = license, platforms = platforms, keywords = keywords, From 892b1c4967af3986abb952ef51d938a79000056d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jan 2016 14:07:24 -0800 Subject: [PATCH 0152/4859] Tell if no automatic update possible --- tools/update_whatsnew.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/update_whatsnew.py b/tools/update_whatsnew.py index d960bb08062..f3156c52a15 100755 --- a/tools/update_whatsnew.py +++ b/tools/update_whatsnew.py @@ -6,7 +6,7 @@ """ import io -import os +import sys from glob import glob from os.path import dirname, basename, abspath, join as pjoin from subprocess import check_call, check_output @@ -28,6 +28,10 @@ 'antigravity-feature.rst'} }) +if not files: + print("No automatic update available for what's new") + sys.exit(0) + def getmtime(f): return check_output(['git', 'log', '-1', '--format="%ai"', '--', f]) From 13d26ddda3b8b175c8cd7bece4c680052077f7f1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jan 2016 14:30:39 -0800 Subject: [PATCH 0153/4859] Update release notes --- docs/source/whatsnew/development.rst | 18 +----------------- docs/source/whatsnew/version4.rst | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/source/whatsnew/development.rst b/docs/source/whatsnew/development.rst index ad6917ac088..a07ee1ecb4d 100644 --- a/docs/source/whatsnew/development.rst +++ b/docs/source/whatsnew/development.rst @@ -11,23 +11,7 @@ This document describes in-flight development work. `docs/source/whatsnew/pr` folder -IPython debugger (IPdb) now supports the number of context lines for the -``where`` (and ``w``) commands. The `context` keyword is also available in various APIs. -See PR :ghpull:`9097` -YouTube video will now show thumbnail when exported to a media that do not support video. (:ghpull:`9086`) - -Add warning when running `ipython ` when subcommand is deprecated. `jupyter` should now be used. - -Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`8947`) - -`%aimport` now support module completion. (:ghpull:`8884`) - -`ipdb` output is now colored ! (:ghpull:`8842`) - -Add ability to transpose columns for completion: (:ghpull:`8748`) - -Many many docs improvements and bug fixes, you can see the list of changes [add link to GitHub diff] .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. @@ -36,4 +20,4 @@ Backwards incompatible changes ------------------------------ -.. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. \ No newline at end of file +.. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. diff --git a/docs/source/whatsnew/version4.rst b/docs/source/whatsnew/version4.rst index f150a4f1355..c16ea48eeb9 100644 --- a/docs/source/whatsnew/version4.rst +++ b/docs/source/whatsnew/version4.rst @@ -2,6 +2,29 @@ 4.x Series ============ + +IPython 4.1 +=========== + +Release February, 2016. IPython 4.1 contain mostly bug fixes. It though contain +a few improvement. + + +- IPython debugger (IPdb) now supports the number of context lines for the + ``where`` (and ``w``) commands. The `context` keyword is also available in + various APIs. See PR :ghpull:`9097` +- YouTube video will now show thumbnail when exported to a media that do not + support video. (:ghpull:`9086`) +- Add warning when running `ipython ` when subcommand is + deprecated. `jupyter` should now be used. +- Code in `%pinfo` (also known as `??`) are now highlighter (:ghpull:`8947`) +- `%aimport` now support module completion. (:ghpull:`8884`) +- `ipdb` output is now colored ! (:ghpull:`8842`) +- Add ability to transpose columns for completion: (:ghpull:`8748`) + +Many many docs improvements and bug fixes, you can see the +`list of changes `_ + IPython 4.0 =========== From e3227929c9e30f3651798d240654c3348c37dbf1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jan 2016 14:52:06 -0800 Subject: [PATCH 0154/4859] Factor build logic into function --- tools/build_release | 38 +++++++++++++++++++++----------------- tools/release | 6 +++--- tools/toollib.py | 4 +++- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/tools/build_release b/tools/build_release index 65efd11b581..3521e5f5311 100755 --- a/tools/build_release +++ b/tools/build_release @@ -1,28 +1,32 @@ #!/usr/bin/env python """IPython release build script. """ - import os from shutil import rmtree -from toollib import sh, pjoin, get_ipdir, cd, compile_tree, execfile, sdists, wheels +from toollib import sh, pjoin, get_ipdir, cd, compile_tree, execfile, sdists, buildwheels + +def build_release(): + + # Get main ipython dir, this will raise if it doesn't pass some checks + ipdir = get_ipdir() + cd(ipdir) -# Get main ipython dir, this will raise if it doesn't pass some checks -ipdir = get_ipdir() -cd(ipdir) + # Load release info + execfile(pjoin('IPython', 'core', 'release.py'), globals()) -# Load release info -execfile(pjoin('IPython', 'core', 'release.py'), globals()) + # Check that everything compiles + compile_tree('*') -# Check that everything compiles -compile_tree('*') + # Cleanup + for d in ['build', 'dist', pjoin('docs', 'build'), pjoin('docs', 'dist'), + pjoin('docs', 'source', 'api', 'generated')]: + if os.path.isdir(d): + rmtree(d) -# Cleanup -for d in ['build', 'dist', pjoin('docs', 'build'), pjoin('docs', 'dist'), - pjoin('docs', 'source', 'api', 'generated')]: - if os.path.isdir(d): - rmtree(d) + # Build source and binary distros + sh(sdists) + buildwheels() -# Build source and binary distros -sh(sdists) -sh(wheels) +if __name__ == '__main__': + build_release() diff --git a/tools/release b/tools/release index c6c8909920d..69e51231bc1 100755 --- a/tools/release +++ b/tools/release @@ -9,7 +9,7 @@ import os import sys from toollib import (get_ipdir, pjoin, cd, execfile, sh, archive, - sdists, archive_user, archive_dir) + sdists, archive_user, archive_dir, buildwheels) from gh_api import post_download # Get main ipython dir, this will raise if it doesn't pass some checks @@ -56,8 +56,8 @@ cd(ipdir) # Upload all files sh(sdists) -for py in ('2', '3'): - sh('python%s setupegg.py bdist_wheel' % py) + +buildwheels() if 'upload' not in sys.argv: print("`./release upload` to register and release") diff --git a/tools/toollib.py b/tools/toollib.py index 7406c2b1251..1b390c7f0e9 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -20,7 +20,9 @@ # Source dists sdists = './setup.py sdist --formats=gztar,zip' # Binary dists -wheels = './setupegg.py bdist_wheel' +def buildwheels(): + for py in ('2', '3'): + sh('python%s setupegg.py bdist_wheel' % py) # Utility functions def sh(cmd): From 1f5cea7dec9d385e5b6816547d071ec56d94845c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jan 2016 15:11:02 -0800 Subject: [PATCH 0155/4859] release 4.1.0rc2 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 576a2c6b899..1d9ad0e6faf 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 1 _version_patch = 0 _version_extra = '.dev' -#_version_extra = 'rc1' +_version_extra = 'rc2' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From aafdf482f8b9f949b9bd74f19ccbd3ebc082d038 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Jan 2016 15:14:09 -0800 Subject: [PATCH 0156/4859] back to development --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 1d9ad0e6faf..7956c281888 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 1 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'rc2' +# _version_extra = 'rc2' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 22d6258fe3dc28668d0d8cb99ae627a6676484a3 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 1 Feb 2016 16:05:27 +0100 Subject: [PATCH 0157/4859] compare shell tokens with BashLexer output rather than assuming BashLexer's output will never change --- IPython/lib/tests/test_lexers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/IPython/lib/tests/test_lexers.py b/IPython/lib/tests/test_lexers.py index 0f795504314..bb2de2e5f8e 100644 --- a/IPython/lib/tests/test_lexers.py +++ b/IPython/lib/tests/test_lexers.py @@ -5,6 +5,7 @@ from unittest import TestCase from pygments.token import Token +from pygments.lexers import BashLexer from .. import lexers @@ -13,16 +14,14 @@ class TestLexers(TestCase): """Collection of lexers tests""" def setUp(self): self.lexer = lexers.IPythonLexer() + self.bash_lexer = BashLexer() def testIPythonLexer(self): fragment = '!echo $HOME\n' tokens = [ (Token.Operator, '!'), - (Token.Name.Builtin, 'echo'), - (Token.Text, ' '), - (Token.Name.Variable, '$HOME'), - (Token.Text, '\n'), ] + tokens.extend(self.bash_lexer.get_tokens(fragment[1:])) self.assertEqual(tokens, list(self.lexer.get_tokens(fragment))) fragment_2 = '!' + fragment From 9c77db54f12381f85da223b7b9df3ea3a298bb31 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 1 Feb 2016 16:07:59 +0100 Subject: [PATCH 0158/4859] ensure pygments is installed for testing --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 39233e72bf0..45fb2fdc074 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], From 607cdcdd71572a53806d328b965e0c45ac6634dd Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Mon, 1 Feb 2016 19:48:23 -0500 Subject: [PATCH 0159/4859] Latextools: Make latex_to_png_mpl not fail on errors - Also make make both latex_to_foo functions to return None on failure. - This will help to solve the errors qtconsole is having to handle Latex. --- IPython/lib/latextools.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index 159b8228e2d..eb7c27b16df 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -104,11 +104,14 @@ def latex_to_png_mpl(s, wrap): s = s.replace('$$', '$') if wrap: s = u'${0}$'.format(s) - - mt = mathtext.MathTextParser('bitmap') - f = BytesIO() - mt.to_png(f, s, fontsize=12) - return f.getvalue() + + try: + mt = mathtext.MathTextParser('bitmap') + f = BytesIO() + mt.to_png(f, s, fontsize=12) + return f.getvalue() + except: + return None def latex_to_png_dvipng(s, wrap): @@ -138,6 +141,8 @@ def latex_to_png_dvipng(s, wrap): with open(outfile, "rb") as f: return f.read() + except: + return None finally: shutil.rmtree(workdir) From f9680417c24973e35199e29afd7d01956618b9f5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 2 Feb 2016 17:00:42 -0800 Subject: [PATCH 0160/4859] Generate stats for 4.0.0..4.0.1 --- docs/source/whatsnew/github-stats-4.rst | 67 +++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/docs/source/whatsnew/github-stats-4.rst b/docs/source/whatsnew/github-stats-4.rst index 02634e52673..480ddc2540d 100644 --- a/docs/source/whatsnew/github-stats-4.rst +++ b/docs/source/whatsnew/github-stats-4.rst @@ -3,6 +3,73 @@ Issues closed in the 4.x development cycle ========================================== +Issues closed in 4.1 +-------------------- + + +GitHub stats for 2015/08/12 - 2016/02/02 (since 4.0.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 60 issues and merged 148 pull requests. +The full list can be seen `on GitHub `__ + +The following 52 authors contributed 468 commits. + +* Aaron Meurer +* Alexandre Avanian +* Anthony Sottile +* Antony Lee +* Arthur Loder +* Ben Kasel +* Ben Rousch +* Benjamin Ragan-Kelley +* bollwyvl +* Carol Willing +* Christopher Roach +* Douglas La Rocca +* Fairly +* Fernando Perez +* Frank Sachsenheim +* Guillaume DOUMENC +* Gábor Luk +* Hoyt Koepke +* Ivan Timokhin +* Jacob Niehus +* JamshedVesuna +* Jan Schulz +* Jan-Philip Gehrcke +* jc +* Jessica B. Hamrick +* jferrara +* John Bohannon +* John Kirkham +* Jonathan Frederic +* Kyle Kelley +* Lev Givon +* Lilian Besson +* lingxz +* Matthias Bussonnier +* memeplex +* Michael Droettboom +* naught101 +* Peter Waller +* Pierre Gerold +* Rémy Léone +* Scott Sanderson +* Shanzhuo Zhang +* Sylvain Corlay +* Tayfun Sen +* Thomas A Caswell +* Thomas Ballinger +* Thomas Kluyver +* Vincent Legoll +* Wouter Bolsterlee +* xconverge +* Yuri Numerov +* Zachary Pincus + + Issues closed in 4.0 -------------------- From 9cbb747586ca0e9b62d52531062aa36437ae317e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 2 Feb 2016 17:03:04 -0800 Subject: [PATCH 0161/4859] release 4.1.0 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 7956c281888..bb22d59bffb 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -24,7 +24,7 @@ _version_patch = 0 _version_extra = '.dev' # _version_extra = 'rc2' -# _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 b302f1ea566f21bb7f88829a6cb276a123983048 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 2 Feb 2016 17:05:15 -0800 Subject: [PATCH 0162/4859] Chage version 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 bb22d59bffb..26a52a32efa 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 = 4 -_version_minor = 1 +_version_minor = 2 _version_patch = 0 _version_extra = '.dev' # _version_extra = 'rc2' -_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 90e30a8f28cc55e870c9a40a5e64a5238b143474 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 12:31:17 +0000 Subject: [PATCH 0163/4859] Add a mainloop() method to mimic existing shell API --- IPython/terminal/ptshell.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 58b2ad6f486..5c13e87f75b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -196,6 +196,16 @@ def interact(self): if document: self.run_cell(document.text, store_history=True) + def mainloop(self): + # An extra layer of protection in case someone mashing Ctrl-C breaks + # out of our internal code. + while True: + try: + self.interact() + break + except KeyboardInterrupt: + print("\nKeyboardInterrupt escaped interact()\n") + _inputhook = None def inputhook(self, context): if self._inputhook is not None: From e9384160dd1e213ed690cecffa11224dfcbe0037 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 12:34:07 +0000 Subject: [PATCH 0164/4859] Config option to enable mouse support --- IPython/terminal/ptshell.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 5c13e87f75b..e751b85bd9e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -54,6 +54,10 @@ class PTInteractiveShell(InteractiveShell): help="Use vi style keybindings at the prompt", ) + mouse_support = Bool(False, config=True, + help="Enable mouse support in the prompt" + ) + highlighting_style = Unicode('', config=True, help="The name of a Pygments style to use for syntax highlighting" ) @@ -148,6 +152,7 @@ def _(event): completer=IPythonPTCompleter(self.Completer), enable_history_search=True, style=style, + mouse_support=self.mouse_support, ) self.pt_cli = CommandLineInterface(app, From 46f9e03d1c015a9d894bf33397f42e170614fa13 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 15:30:48 +0000 Subject: [PATCH 0165/4859] Don't import IPython to check version number in setup The version number is already exec-ed into the global scope of this module, so we don't need the import here. Don't you just love Python packaging? Closes gh-9208 --- setupbase.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/setupbase.py b/setupbase.py index e73641d26f2..dc94cb82df6 100644 --- a/setupbase.py +++ b/setupbase.py @@ -425,9 +425,8 @@ def run(self): # loose as `.dev` is suppose to be invalid print("check version number") loose_pep440re = re.compile('^(\d+)\.(\d+)\.(\d+((a|b|rc)\d+)?)(\.post\d+)?(\.dev\d*)?$') - import IPython.core.release as r - if not loose_pep440re.match(r.version): - raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % r.version) + if not loose_pep440re.match(version): + raise ValueError("Version number '%s' is not valid (should match [N!]N(.N)*[{a|b|rc}N][.postN][.devN])" % version) build_cmd.run(self) From fd93c6ac2f68113246fd1880cca8556c7557f996 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 16:09:51 +0000 Subject: [PATCH 0166/4859] Bump version to 5.0 The circling PRs are running low on fuel! --- 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 26a52a32efa..a267d6bda83 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 = 4 -_version_minor = 2 +_version_major = 5 +_version_minor = 0 _version_patch = 0 _version_extra = '.dev' # _version_extra = 'rc2' From 8f76839d6f6b2fa902851650c5f2c99128d0152d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 17:34:20 +0000 Subject: [PATCH 0167/4859] jsversion is no longer part of IPython --- 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 7ab4fc6b736..b279c6ad626 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -102,7 +102,7 @@ release is: ``1.3rc1``. Notice that there is no separator between the '3' and the 'r'. -Commit the changes to release.py and jsversion:: +Commit the changes to release.py:: git commit -am "release $VERSION" git push origin $BRANCH From 45f6813353f21ef963d8d3548f2a9bd1544bdb81 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 17:35:11 +0000 Subject: [PATCH 0168/4859] Fix importing execfile from toollib on Python 2 --- tools/toollib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/toollib.py b/tools/toollib.py index 1b390c7f0e9..a5440ea5de3 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -59,7 +59,7 @@ def compile_tree(folder='.'): raise SystemExit(msg) try: - execfile + execfile = execfile except NameError: def execfile(fname, globs, locs=None): locs = locs or globs From 3b61f32870c696fd6540e91a93c7676f46e04e4a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 3 Feb 2016 17:36:52 +0000 Subject: [PATCH 0169/4859] Remove pycompile check for building packages --- tools/build_release | 5 +---- tools/toollib.py | 9 --------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/tools/build_release b/tools/build_release index 3521e5f5311..3b115f11905 100755 --- a/tools/build_release +++ b/tools/build_release @@ -4,7 +4,7 @@ import os from shutil import rmtree -from toollib import sh, pjoin, get_ipdir, cd, compile_tree, execfile, sdists, buildwheels +from toollib import sh, pjoin, get_ipdir, cd, execfile, sdists, buildwheels def build_release(): @@ -15,9 +15,6 @@ def build_release(): # Load release info execfile(pjoin('IPython', 'core', 'release.py'), globals()) - # Check that everything compiles - compile_tree('*') - # Cleanup for d in ['build', 'dist', pjoin('docs', 'build'), pjoin('docs', 'dist'), pjoin('docs', 'source', 'api', 'generated')]: diff --git a/tools/toollib.py b/tools/toollib.py index a5440ea5de3..ad71bd063a3 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -49,15 +49,6 @@ def get_ipdir(): raise SystemExit('Invalid ipython directory: %s' % ipdir) return ipdir - -def compile_tree(folder='.'): - """Compile all Python files below current directory.""" - stat = os.system('python -m compileall {}'.format(folder)) - if stat: - msg = '*** ERROR: Some Python files in tree do NOT compile! ***\n' - msg += 'See messages above for the actual file that produced it.\n' - raise SystemExit(msg) - try: execfile = execfile except NameError: From 1d9e725c3e5397b8756dc941a06a885666ebfae5 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 5 Feb 2016 11:25:11 +0000 Subject: [PATCH 0170/4859] Make release tags without rel- prefix This seems to be the consensus emerging on gh-9213 --- docs/source/coredev/release_process.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index b279c6ad626..4bba61b74a9 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -16,10 +16,9 @@ handy reminder and checklist for the release manager. Set environment variables to document previous release tag, current release milestone, current release version, and git tag:: - PREV_RELEASE=rel-1.0.0 - MILESTONE=1.1 - VERSION=1.1.0 - TAG="rel-$VERSION" + PREV_RELEASE=4.0.0 + MILESTONE=4.1 + VERSION=4.1.0 BRANCH=master These variables may be used later to copy/paste as answers to the script @@ -109,7 +108,7 @@ Commit the changes to release.py:: Create and push the tag:: - git tag -am "release $VERSION" "$TAG" + git tag -am "release $VERSION" "$VERSION" git push origin --tags Update release.py back to `x.y-dev` or `x.y-maint`, and push:: @@ -123,7 +122,7 @@ Update release.py back to `x.y-dev` or `x.y-maint`, and push:: Get a fresh clone of the tag for building the release:: cd /tmp - git clone --depth 1 https://github.com/ipython/ipython.git -b "$TAG" + git clone --depth 1 https://github.com/ipython/ipython.git -b "$VERSION" 7. Run the release script ------------------------- From 58b87f43ac27b3c8fb3b496ec926d3e6087e205d Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 12 Feb 2016 12:00:45 +0100 Subject: [PATCH 0171/4859] move interact trait up one level to InteractiveShellApp --- IPython/core/shellapp.py | 2 ++ IPython/terminal/ipapp.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 45e78aa2910..6d50e0cfe8f 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -198,6 +198,8 @@ class InteractiveShellApp(Configurable): ) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) + # whether interact-loop should start + interact = Bool(True) user_ns = Instance(dict, args=None, allow_none=True) def _user_ns_changed(self, name, old, new): diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index fe3d0083269..ddc38d4f340 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -272,7 +272,6 @@ def _file_to_run_changed(self, name, old, new): _module_to_run_changed = _file_to_run_changed # internal, not-configurable - interact=Bool(True) something_to_run=Bool(False) def parse_command_line(self, argv=None): From e697dfcf32df11132f4a17fba7302e3980f4c00f Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 12 Feb 2016 12:01:11 +0100 Subject: [PATCH 0172/4859] only exit on error if `interact` is False --- IPython/core/shellapp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 6d50e0cfe8f..2b6b29cf2c9 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -413,6 +413,8 @@ def _run_cmd_line_code(self): self.log.warning("Error in executing line in user namespace: %s" % line) self.shell.showtraceback() + if not self.interact: + self.exit(1) # Like Python itself, ignore the second if the first of these is present elif self.file_to_run: @@ -421,7 +423,8 @@ def _run_cmd_line_code(self): self._exec_file(fname, shell_futures=True) except: self.shell.showtraceback(tb_offset=4) - self.exit(1) + if not self.interact: + self.exit(1) def _run_module(self): """Run module specified at the command-line.""" From 6346e89b1203362fc1e85cffee3884c0c9c352ac Mon Sep 17 00:00:00 2001 From: Yuri Numerov Date: Sun, 23 Aug 2015 19:17:56 +0200 Subject: [PATCH 0173/4859] removed install_ext magic, as asked in issue #8634 --- IPython/core/magics/extension.py | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/IPython/core/magics/extension.py b/IPython/core/magics/extension.py index 65f3993258c..2991d55ca40 100644 --- a/IPython/core/magics/extension.py +++ b/IPython/core/magics/extension.py @@ -29,35 +29,6 @@ class ExtensionMagics(Magics): """Magics to manage the IPython extensions system.""" - @line_magic - def install_ext(self, parameter_s=''): - """Download and install an extension from a URL, e.g.:: - - %install_ext https://bitbucket.org/birkenfeld/ipython-physics/raw/d1310a2ab15d/physics.py - - The URL should point to an importable Python module - either a .py file - or a .zip file. - - Parameters: - - -n filename : Specify a name for the file, rather than taking it from - the URL. - """ - warn("%install_ext` is deprecated, please distribute your extension " - "as a python package.", UserWarning) - opts, args = self.parse_options(parameter_s, 'n:') - try: - filename = self.shell.extension_manager.install_extension(args, - opts.get('n')) - except ValueError as e: - print(e) - return - - filename = os.path.basename(filename) - print("Installed %s. To use it, type:" % filename) - print(" %%load_ext %s" % os.path.splitext(filename)[0]) - - @line_magic def load_ext(self, module_str): """Load an IPython extension by its module name.""" From 838bb758101c9dce6684eaee8e8323b7b5586e2a Mon Sep 17 00:00:00 2001 From: Yuri Numerov Date: Sun, 23 Aug 2015 20:02:02 +0200 Subject: [PATCH 0174/4859] added pr info to docs/source/whatsnew/pr/ --- docs/source/whatsnew/pr/incompat-deleted-install_ext.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/source/whatsnew/pr/incompat-deleted-install_ext.rst diff --git a/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst b/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst new file mode 100644 index 00000000000..01b6d750497 --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst @@ -0,0 +1 @@ +Deleted the install_ext magic function From 23b082fe0a89d5431633426fff1db958195b93cb Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sat, 13 Feb 2016 22:19:46 -0500 Subject: [PATCH 0175/4859] Latextools: Use the right exceptions to catch errors --- IPython/lib/latextools.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index eb7c27b16df..88b0978b036 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -97,9 +97,10 @@ def latex_to_png(s, encode=False, backend=None, wrap=False): def latex_to_png_mpl(s, wrap): try: from matplotlib import mathtext + from pyparsing import ParseFatalException except ImportError: return None - + # mpl mathtext doesn't support display math, force inline s = s.replace('$$', '$') if wrap: @@ -110,7 +111,7 @@ def latex_to_png_mpl(s, wrap): f = BytesIO() mt.to_png(f, s, fontsize=12) return f.getvalue() - except: + except (ValueError, RuntimeError, ParseFatalException): return None @@ -141,7 +142,7 @@ def latex_to_png_dvipng(s, wrap): with open(outfile, "rb") as f: return f.read() - except: + except subprocess.CalledProcessError: return None finally: shutil.rmtree(workdir) From 6f1f1ae4f35943d6f5b895481b9d078048747241 Mon Sep 17 00:00:00 2001 From: Sebastian Bank Date: Sun, 14 Feb 2016 14:45:09 +0100 Subject: [PATCH 0176/4859] adapt DisplayHook.quiet() for multiline input --- IPython/core/displayhook.py | 2 +- IPython/core/tests/test_displayhook.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 5f0fd4846ca..860c744c74f 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -96,7 +96,7 @@ def quiet(self): tokens = list(tokenize.generate_tokens(sio.readline)) for token in reversed(tokens): - if token[0] in (tokenize.ENDMARKER, tokenize.COMMENT): + if token[0] in (tokenize.ENDMARKER, tokenize.NL, tokenize.NEWLINE, tokenize.COMMENT): continue if (token[0] == tokenize.OP) and (token[1] == ';'): return True diff --git a/IPython/core/tests/test_displayhook.py b/IPython/core/tests/test_displayhook.py index 6435808b528..3cca42a8089 100644 --- a/IPython/core/tests/test_displayhook.py +++ b/IPython/core/tests/test_displayhook.py @@ -10,6 +10,10 @@ def test_output_displayed(): with AssertPrints('2'): ip.run_cell('1+1 # comment with a semicolon;', store_history=True) + + with AssertPrints('2'): + ip.run_cell('1+1\n#commented_out_function();', store_history=True) + def test_output_quiet(): """Checking to make sure that output is quiet""" @@ -19,3 +23,6 @@ def test_output_quiet(): with AssertNotPrints('2'): ip.run_cell('1+1; # comment with a semicolon', store_history=True) + + with AssertNotPrints('2'): + ip.run_cell('1+1;\n#commented_out_function()', store_history=True) From baf168537044cebecd2097cd9ac62128e0e28863 Mon Sep 17 00:00:00 2001 From: Carlos Cordoba Date: Sun, 14 Feb 2016 12:51:05 -0500 Subject: [PATCH 0177/4859] Remove gui_reference and page_guiref because they were moved to qtconsole --- IPython/core/usage.py | 216 ------------------------------------------ 1 file changed, 216 deletions(-) diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 143f3ebb148..d1a03b7df1b 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -329,214 +329,6 @@ """ -gui_reference = """\ -=============================== - The graphical IPython console -=============================== - -This console is designed to emulate the look, feel and workflow of a terminal -environment, while adding a number of enhancements that are simply not possible -in a real terminal, such as inline syntax highlighting, true multiline editing, -inline graphics and much more. - -This quick reference document contains the basic information you'll need to -know to make the most efficient use of it. For the various command line -options available at startup, type ``ipython qtconsole --help`` at the command line. - - -Multiline editing -================= - -The graphical console is capable of true multiline editing, but it also tries -to behave intuitively like a terminal when possible. If you are used to -IPython's old terminal behavior, you should find the transition painless, and -once you learn a few basic keybindings it will be a much more efficient -environment. - -For single expressions or indented blocks, the console behaves almost like the -terminal IPython: single expressions are immediately evaluated, and indented -blocks are evaluated once a single blank line is entered:: - - In [1]: print "Hello IPython!" # Enter was pressed at the end of the line - Hello IPython! - - In [2]: for i in range(10): - ...: print i, - ...: - 0 1 2 3 4 5 6 7 8 9 - -If you want to enter more than one expression in a single input block -(something not possible in the terminal), you can use ``Control-Enter`` at the -end of your first line instead of ``Enter``. At that point the console goes -into 'cell mode' and even if your inputs are not indented, it will continue -accepting arbitrarily many lines until either you enter an extra blank line or -you hit ``Shift-Enter`` (the key binding that forces execution). When a -multiline cell is entered, IPython analyzes it and executes its code producing -an ``Out[n]`` prompt only for the last expression in it, while the rest of the -cell is executed as if it was a script. An example should clarify this:: - - In [3]: x=1 # Hit C-Enter here - ...: y=2 # from now on, regular Enter is sufficient - ...: z=3 - ...: x**2 # This does *not* produce an Out[] value - ...: x+y+z # Only the last expression does - ...: - Out[3]: 6 - -The behavior where an extra blank line forces execution is only active if you -are actually typing at the keyboard each line, and is meant to make it mimic -the IPython terminal behavior. If you paste a long chunk of input (for example -a long script copied form an editor or web browser), it can contain arbitrarily -many intermediate blank lines and they won't cause any problems. As always, -you can then make it execute by appending a blank line *at the end* or hitting -``Shift-Enter`` anywhere within the cell. - -With the up arrow key, you can retrieve previous blocks of input that contain -multiple lines. You can move inside of a multiline cell like you would in any -text editor. When you want it executed, the simplest thing to do is to hit the -force execution key, ``Shift-Enter`` (though you can also navigate to the end -and append a blank line by using ``Enter`` twice). - -If you've edited a multiline cell and accidentally navigate out of it with the -up or down arrow keys, IPython will clear the cell and replace it with the -contents of the one above or below that you navigated to. If this was an -accident and you want to retrieve the cell you were editing, use the Undo -keybinding, ``Control-z``. - - -Key bindings -============ - -The IPython console supports most of the basic Emacs line-oriented keybindings, -in addition to some of its own. - -The keybinding prefixes mean: - -- ``C``: Control -- ``S``: Shift -- ``M``: Meta (typically the Alt key) - -The keybindings themselves are: - -- ``Enter``: insert new line (may cause execution, see above). -- ``C-Enter``: *force* new line, *never* causes execution. -- ``S-Enter``: *force* execution regardless of where cursor is, no newline added. -- ``Up``: step backwards through the history. -- ``Down``: step forwards through the history. -- ``S-Up``: search backwards through the history (like ``C-r`` in bash). -- ``S-Down``: search forwards through the history. -- ``C-c``: copy highlighted text to clipboard (prompts are automatically stripped). -- ``C-S-c``: copy highlighted text to clipboard (prompts are not stripped). -- ``C-v``: paste text from clipboard. -- ``C-z``: undo (retrieves lost text if you move out of a cell with the arrows). -- ``C-S-z``: redo. -- ``C-o``: move to 'other' area, between pager and terminal. -- ``C-l``: clear terminal. -- ``C-a``: go to beginning of line. -- ``C-e``: go to end of line. -- ``C-u``: kill from cursor to the begining of the line. -- ``C-k``: kill from cursor to the end of the line. -- ``C-y``: yank (paste) -- ``C-p``: previous line (like up arrow) -- ``C-n``: next line (like down arrow) -- ``C-f``: forward (like right arrow) -- ``C-b``: back (like left arrow) -- ``C-d``: delete next character, or exits if input is empty -- ``M-<``: move to the beginning of the input region. -- ``M->``: move to the end of the input region. -- ``M-d``: delete next word. -- ``M-Backspace``: delete previous word. -- ``C-.``: force a kernel restart (a confirmation dialog appears). -- ``C-+``: increase font size. -- ``C--``: decrease font size. -- ``C-M-Space``: toggle full screen. (Command-Control-Space on Mac OS X) - -The IPython pager -================= - -IPython will show long blocks of text from many sources using a builtin pager. -You can control where this pager appears with the ``--paging`` command-line -flag: - -- ``inside`` [default]: the pager is overlaid on top of the main terminal. You - must quit the pager to get back to the terminal (similar to how a pager such - as ``less`` or ``more`` works). - -- ``vsplit``: the console is made double-tall, and the pager appears on the - bottom area when needed. You can view its contents while using the terminal. - -- ``hsplit``: the console is made double-wide, and the pager appears on the - right area when needed. You can view its contents while using the terminal. - -- ``none``: the console never pages output. - -If you use the vertical or horizontal paging modes, you can navigate between -terminal and pager as follows: - -- Tab key: goes from pager to terminal (but not the other way around). -- Control-o: goes from one to another always. -- Mouse: click on either. - -In all cases, the ``q`` or ``Escape`` keys quit the pager (when used with the -focus on the pager area). - -Running subprocesses -==================== - -The graphical IPython console uses the ``pexpect`` module to run subprocesses -when you type ``!command``. This has a number of advantages (true asynchronous -output from subprocesses as well as very robust termination of rogue -subprocesses with ``Control-C``), as well as some limitations. The main -limitation is that you can *not* interact back with the subprocess, so anything -that invokes a pager or expects you to type input into it will block and hang -(you can kill it with ``Control-C``). - -We have provided as magics ``%less`` to page files (aliased to ``%more``), -``%clear`` to clear the terminal, and ``%man`` on Linux/OSX. These cover the -most common commands you'd want to call in your subshell and that would cause -problems if invoked via ``!cmd``, but you need to be aware of this limitation. - -Display -======= - -The IPython console can now display objects in a variety of formats, including -HTML, PNG and SVG. This is accomplished using the display functions in -``IPython.core.display``:: - - In [4]: from IPython.core.display import display, display_html - - In [5]: from IPython.core.display import display_png, display_svg - -Python objects can simply be passed to these functions and the appropriate -representations will be displayed in the console as long as the objects know -how to compute those representations. The easiest way of teaching objects how -to format themselves in various representations is to define special methods -such as: ``_repr_html_``, ``_repr_svg_`` and ``_repr_png_``. IPython's display formatters -can also be given custom formatter functions for various types:: - - In [6]: ip = get_ipython() - - In [7]: html_formatter = ip.display_formatter.formatters['text/html'] - - In [8]: html_formatter.for_type(Foo, foo_to_html) - -For further details, see ``IPython.core.formatters``. - -Inline matplotlib graphics -========================== - -The IPython console is capable of displaying matplotlib figures inline, in SVG -or PNG format. If started with the ``matplotlib=inline``, then all figures are -rendered inline automatically (PNG by default). If started with ``--matplotlib`` -or ``matplotlib=``, then a GUI backend will be used, but IPython's -``display()`` and ``getfigs()`` functions can be used to view plots inline:: - - In [9]: display(*getfigs()) # display all figures inline - - In[10]: display(*getfigs(1,2)) # display figures 1 and 2 inline -""" - - quick_guide = """\ ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. @@ -562,11 +354,3 @@ default_banner = ''.join(default_banner_parts) default_gui_banner = ''.join(default_gui_banner_parts) - -# page GUI Reference, for use as a magic: - -def page_guiref(arg_s=None): - """Show a basic reference about the GUI Console.""" - from IPython.core import page - page.page(gui_reference) - From 58ddb7de8e3e6030074f41d7db356f4a2644b3be Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 15 Feb 2016 20:41:05 -0800 Subject: [PATCH 0178/4859] Force nocolor in some cases. will help for the refactoring using pygments. --- IPython/terminal/embed.py | 1 + IPython/terminal/tests/test_embed.py | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index bc232e02578..85dc9d1cb36 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -270,6 +270,7 @@ def embed(**kwargs): if config is None: config = load_default_config() config.InteractiveShellEmbed = config.TerminalInteractiveShell + config.InteractiveShellEmbed.colors='nocolor' kwargs['config'] = config #save ps1/ps2 if defined ps1 = None diff --git a/IPython/terminal/tests/test_embed.py b/IPython/terminal/tests/test_embed.py index 2767392b623..5103c47e3df 100644 --- a/IPython/terminal/tests/test_embed.py +++ b/IPython/terminal/tests/test_embed.py @@ -64,7 +64,7 @@ def test_nest_embed(): ipy_prompt = r']:' #ansi color codes give problems matching beyond this - child = pexpect.spawn('%s -m IPython'%(sys.executable, )) + child = pexpect.spawn('%s -m IPython --colors=nocolor'%(sys.executable, )) child.expect(ipy_prompt) child.sendline("from __future__ import print_function") child.expect(ipy_prompt) @@ -123,3 +123,5 @@ def test_nest_embed(): child.sendline("print('true' if IPython.get_ipython() is ip0 else 'false')") assert(child.expect(['true\r\n', 'false\r\n']) == 0) child.expect(ipy_prompt) + child.sendline('exit') + child.close() From a4b702559c86ec4b86e25f967c5d2d416f5cf1e1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 15 Feb 2016 20:53:56 -0800 Subject: [PATCH 0179/4859] Remove annoying unused variable --- IPython/core/debugger.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index a1ba878d875..02e0df9c28f 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -557,7 +557,6 @@ def getsourcelines(self, obj): def do_longlist(self, arg): self.lastcmd = 'longlist' - filename = self.curframe.f_code.co_filename try: lines, lineno = self.getsourcelines(self.curframe) except OSError as err: From d169e44478dcaf1cbe28c9addcc74ebc077eb524 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 15 Feb 2016 21:04:02 -0800 Subject: [PATCH 0180/4859] Refactor simplify and share common function. --- IPython/core/debugger.py | 25 +++++++++++++------------ IPython/core/ultratb.py | 10 +--------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index a1ba878d875..c4d63143627 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -60,6 +60,16 @@ # Allow the set_trace code to operate outside of an ipython instance, even if # it does so with some limitations. The rest of this support is implemented in # the Tracer constructor. + +def make_arrow(pad): + """generate the leading arrow in front of traceback or debugger""" + if pad >= 2: + return '-'*(pad-2) + '> ' + elif pad == 1: + return '>' + return '' + + def BdbQuit_excepthook(et, ev, tb, excepthook=None): """Exception hook which handles `BdbQuit` exceptions. @@ -460,21 +470,12 @@ def __format_line(self, tpl_line, filename, lineno, line, arrow = False): if arrow: # This is the line with the error pad = numbers_width - len(str(lineno)) - len(bp_mark) - if pad >= 3: - marker = '-'*(pad-3) + '-> ' - elif pad == 2: - marker = '> ' - elif pad == 1: - marker = '>' - else: - marker = '' - num = '%s%s' % (marker, str(lineno)) - line = tpl_line % (bp_mark_color + bp_mark, num, line) + num = '%s%s' % (make_arrow(pad), str(lineno)) else: num = '%*s' % (numbers_width - len(bp_mark), str(lineno)) - line = tpl_line % (bp_mark_color + bp_mark, num, line) - return line + return tpl_line % (bp_mark_color + bp_mark, num, line) + def list_command_pydb(self, arg): """List command to use if we have a newer pydb installed""" diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 0a5fcc21800..74f1b8e8a7f 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -400,15 +400,7 @@ def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None) if i == lnum: # This is the line with the error pad = numbers_width - len(str(i)) - if pad >= 3: - marker = '-' * (pad - 3) + '-> ' - elif pad == 2: - marker = '> ' - elif pad == 1: - marker = '>' - else: - marker = '' - num = marker + str(i) + num = '%s%s' % (debugger.make_arrow(pad), str(lnum)) line = '%s%s%s %s%s' % (Colors.linenoEm, num, Colors.line, line, Colors.Normal) else: From 133a2aa4d2dc7f37d722ca93c6af5e339bc47d3e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 15 Feb 2016 15:02:21 +0000 Subject: [PATCH 0181/4859] Remove separate 'GUI' banner for ipykernel See ipython/ipykernel#101 This will break compatibility with ipykernel releases before that PR is merged, so milestoning for 5.0. --- IPython/core/usage.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/IPython/core/usage.py b/IPython/core/usage.py index d1a03b7df1b..0f2ff03787e 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -336,10 +336,6 @@ object? -> Details about 'object', use 'object??' for extra details. """ -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', @@ -349,8 +345,4 @@ quick_guide ] -default_gui_banner_parts = default_banner_parts + [gui_note] - default_banner = ''.join(default_banner_parts) - -default_gui_banner = ''.join(default_gui_banner_parts) From dca04a24257f7ccded1551dfb2a2169030ef9180 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 17 Feb 2016 14:04:24 +0000 Subject: [PATCH 0182/4859] Don't try to pass shell up kwargs from Magics class See ipython/traitlets#176 - this is causing test failures. --- IPython/core/magic.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 0566fa9329f..065650aed41 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -520,7 +520,6 @@ def __init__(self, shell=None, **kwargs): shell.configurables.append(self) if hasattr(shell, 'config'): kwargs.setdefault('parent', shell) - kwargs['shell'] = shell self.shell = shell self.options_table = {} From c03585df74fce99b154f87ec908116af31c07a26 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 17 Feb 2016 17:39:53 +0100 Subject: [PATCH 0183/4859] Deprecated the module IPython.utils.warn --- IPython/utils/warn.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 907d2f1cf50..83bf543024a 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -12,6 +12,9 @@ from IPython.utils import io +from warning import warn + +warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) def warn(msg,level=2,exit_val=1): """Standard warning printer. Gives formatting consistency. @@ -29,7 +32,8 @@ def warn(msg,level=2,exit_val=1): -exit_val (1): exit value returned by sys.exit() for a level 4 warning. Ignored for all other levels.""" - + + warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) if level>0: header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] print(header[level], msg, sep='', file=io.stderr) @@ -54,4 +58,3 @@ def fatal(msg,exit_val=1): """Equivalent to warn(msg,exit_val=exit_val,level=4).""" warn(msg,exit_val=exit_val,level=4) - From c4935968de2bb87203a16b59846e840c03495834 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 17 Feb 2016 18:06:01 +0100 Subject: [PATCH 0184/4859] Replace all import of IPython.utils.warn module --- IPython/core/alias.py | 2 +- IPython/core/displayhook.py | 3 +-- IPython/core/history.py | 4 +--- IPython/core/interactiveshell.py | 3 ++- IPython/core/magic.py | 2 +- IPython/core/magics/auto.py | 2 +- IPython/core/magics/basic.py | 3 ++- IPython/core/magics/code.py | 3 ++- IPython/core/magics/config.py | 2 +- IPython/core/magics/execution.py | 3 ++- IPython/core/magics/logging.py | 2 +- IPython/core/magics/pylab.py | 2 +- IPython/core/ultratb.py | 2 +- IPython/lib/backgroundjobs.py | 2 +- IPython/lib/inputhook.py | 2 +- IPython/terminal/interactiveshell.py | 3 ++- IPython/testing/iptest.py | 3 +-- IPython/utils/warn.py | 2 +- 18 files changed, 23 insertions(+), 22 deletions(-) diff --git a/IPython/core/alias.py b/IPython/core/alias.py index b0dd2bf356e..7dc81c71f7e 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -29,7 +29,7 @@ from IPython.utils.py3compat import string_types from traitlets import List, Instance -from IPython.utils.warn import error +from logging import error #----------------------------------------------------------------------------- # Utilities diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 860c744c74f..1e721f967b4 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -18,7 +18,7 @@ from IPython.utils import io from IPython.utils.py3compat import builtin_mod, cast_unicode_py2 from traitlets import Instance, Float -from IPython.utils.warn import warn +from warnings import warn # TODO: Move the various attributes (cache_size, [others now moved]). Some # of these are also attributes of InteractiveShell. They should be on ONE object @@ -293,4 +293,3 @@ def flush(self): # IronPython blocks here forever if sys.platform != "cli": gc.collect() - diff --git a/IPython/core/history.py b/IPython/core/history.py index f63870397d8..5272ab7f9bb 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -35,7 +35,7 @@ from traitlets import ( Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError, ) -from IPython.utils.warn import warn +from warnings import warn #----------------------------------------------------------------------------- # Classes and functions @@ -879,5 +879,3 @@ def _format_lineno(session, line): if session == 0: return str(line) return "%s#%s" % (session, line) - - diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 9486475a3e8..3a053f7b003 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -77,7 +77,8 @@ DollarFormatter) from traitlets import (Integer, Bool, CBool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type) -from IPython.utils.warn import warn, error +from warnings import warn +from logging import error import IPython.core.hooks #----------------------------------------------------------------------------- diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 065650aed41..47d5ad0d915 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -33,7 +33,7 @@ from IPython.utils.py3compat import string_types, iteritems from IPython.utils.text import dedent from traitlets import Bool, Dict, Instance -from IPython.utils.warn import error +from logging import error #----------------------------------------------------------------------------- # Globals diff --git a/IPython/core/magics/auto.py b/IPython/core/magics/auto.py index fac5d1f12e6..bec35998dab 100644 --- a/IPython/core/magics/auto.py +++ b/IPython/core/magics/auto.py @@ -16,7 +16,7 @@ # Our own packages from IPython.core.magic import Bunch, Magics, magics_class, line_magic from IPython.testing.skipdoctest import skip_doctest -from IPython.utils.warn import error +from logging import error #----------------------------------------------------------------------------- # Magic implementation classes diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 7cf7898597a..df069f6591a 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -14,7 +14,8 @@ from IPython.utils.ipstruct import Struct from IPython.utils.path import unquote_filename from IPython.utils.py3compat import unicode_type -from IPython.utils.warn import warn, error +from warnings import warn +from logging import error class MagicsDisplay(object): diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index 75fd6e59c2d..924dd13e5ec 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -32,7 +32,8 @@ from IPython.utils.py3compat import string_types from IPython.utils.contexts import preserve_keys from IPython.utils.path import get_py_filename, unquote_filename -from IPython.utils.warn import warn, error +from warnings import warn +from logging import error from IPython.utils.text import get_text_list #----------------------------------------------------------------------------- diff --git a/IPython/core/magics/config.py b/IPython/core/magics/config.py index 745ca50cc6a..e69aee61930 100644 --- a/IPython/core/magics/config.py +++ b/IPython/core/magics/config.py @@ -19,7 +19,7 @@ # Our own packages from IPython.core.error import UsageError from IPython.core.magic import Magics, magics_class, line_magic -from IPython.utils.warn import error +from logging import error #----------------------------------------------------------------------------- # Magic implementation classes diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 7191cf881f5..c0e30f7b3fc 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -43,7 +43,8 @@ from IPython.utils.module_paths import find_mod from IPython.utils.path import get_py_filename, unquote_filename, shellglob from IPython.utils.timing import clock, clock2 -from IPython.utils.warn import warn, error +from warnings import warn +from logging import error if PY3: from io import StringIO diff --git a/IPython/core/magics/logging.py b/IPython/core/magics/logging.py index 3dcb8cb146d..90214ab54ab 100644 --- a/IPython/core/magics/logging.py +++ b/IPython/core/magics/logging.py @@ -18,7 +18,7 @@ # Our own packages from IPython.core.magic import Magics, magics_class, line_magic -from IPython.utils.warn import warn +from warnings import warn from IPython.utils.py3compat import str_to_unicode #----------------------------------------------------------------------------- diff --git a/IPython/core/magics/pylab.py b/IPython/core/magics/pylab.py index 4db116ab0df..6c5cd68a597 100644 --- a/IPython/core/magics/pylab.py +++ b/IPython/core/magics/pylab.py @@ -18,7 +18,7 @@ from IPython.core import magic_arguments from IPython.core.magic import Magics, magics_class, line_magic from IPython.testing.skipdoctest import skip_doctest -from IPython.utils.warn import warn +from warnings import warn from IPython.core.pylabtools import backends #----------------------------------------------------------------------------- diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 74f1b8e8a7f..b709c6b4fd9 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -118,7 +118,7 @@ from IPython.utils import py3compat from IPython.utils import ulinecache from IPython.utils.data import uniq_stable -from IPython.utils.warn import info, error +from logging import info, error # Globals # amount of space to put line numbers before verbose tracebacks diff --git a/IPython/lib/backgroundjobs.py b/IPython/lib/backgroundjobs.py index b843dcbe35a..b724126bbb3 100644 --- a/IPython/lib/backgroundjobs.py +++ b/IPython/lib/backgroundjobs.py @@ -36,7 +36,7 @@ from IPython import get_ipython from IPython.core.ultratb import AutoFormattedTB -from IPython.utils.warn import error +from logging import error from IPython.utils.py3compat import string_types diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py index 674f7e86e76..00b650a2ed7 100644 --- a/IPython/lib/inputhook.py +++ b/IPython/lib/inputhook.py @@ -17,7 +17,7 @@ import sys from distutils.version import LooseVersion as V -from IPython.utils.warn import warn +from warnings import warn #----------------------------------------------------------------------------- # Constants diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 226b4b85187..aa4a2602615 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -22,7 +22,8 @@ from IPython.utils import py3compat from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from IPython.utils.warn import warn, error +from warnings import warn +from logging import error from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes from traitlets import Integer, CBool, Unicode diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index eb7ef8f27b8..35cab1a3cab 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -212,7 +212,7 @@ def will_run(self): def check_exclusions_exist(): from IPython.paths import get_ipython_package_dir - from IPython.utils.warn import warn + from warnings import warn parent = os.path.dirname(get_ipython_package_dir()) for sec in test_sections: for pattern in sec.exclusions: @@ -439,4 +439,3 @@ def run_iptest(): if __name__ == '__main__': run_iptest() - diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 83bf543024a..07ecf64162a 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -12,7 +12,7 @@ from IPython.utils import io -from warning import warn +from warnings import warn warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) From c8b055b8e835da7d3dd54fb01a8430a16fe52ef5 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 17 Feb 2016 18:10:55 +0100 Subject: [PATCH 0185/4859] Carrefully separate warnings.warn and warn in IPython/utils/warn.py --- IPython/utils/warn.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 07ecf64162a..bb610ac3824 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -12,9 +12,9 @@ from IPython.utils import io -from warnings import warn +import warnings -warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) +warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) def warn(msg,level=2,exit_val=1): """Standard warning printer. Gives formatting consistency. @@ -33,7 +33,7 @@ def warn(msg,level=2,exit_val=1): -exit_val (1): exit value returned by sys.exit() for a level 4 warning. Ignored for all other levels.""" - warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) + warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) if level>0: header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] print(header[level], msg, sep='', file=io.stderr) From 2d89b93a284331a346117f0ae18158ffafc56e67 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 18 Feb 2016 15:02:28 +0000 Subject: [PATCH 0186/4859] Wrap colour sequences in debugger prompt in marker bytes Readline expects ANSI escapes in the prompt to be wrapped in 01 and 02 so that it can calculate the width. Closes gh-9243 --- IPython/core/debugger.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index a7ffb2a0fc2..39abf9b12d4 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -284,9 +284,14 @@ def __init__(self,color_scheme='NoColor',completekey=None, # debugging. self.parser = PyColorize.Parser() - # Set the prompt + # Set the prompt - the default prompt is '(Pdb)' Colors = cst.active_colors - self.prompt = u'%s%s%s' % (Colors.prompt, prompt, Colors.Normal) # The default prompt is '(Pdb)' + if color_scheme == 'NoColor': + self.prompt = prompt + else: + # The colour markers are wrapped by bytes 01 and 02 so that readline + # can calculate the width. + self.prompt = u'\x01%s\x02%s\x01%s\x02' % (Colors.prompt, prompt, Colors.Normal) def set_colors(self, scheme): """Shorthand access to the color table scheme selector method.""" From 3a2d9350c6ebed884e0d08bdc6150ddfbe8fdff5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 18 Feb 2016 10:55:30 -0800 Subject: [PATCH 0187/4859] add docs and cleanup bad code style --- IPython/core/ultratb.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 74f1b8e8a7f..737217a3b4f 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -38,6 +38,11 @@ variables (but otherwise includes the information and context given by Verbose). +.. note:: + + The verbose mode print all variables in the stack, which means it can + potentially leak sensitive information like access keys, or unencryted + password. Installation instructions for VerboseTB:: @@ -216,7 +221,8 @@ def findsource(object): # the length of lines, which causes an error. Safeguard against that. lnum = min(object.co_firstlineno, len(lines)) - 1 while lnum > 0: - if pmatch(lines[lnum]): break + if pmatch(lines[lnum]): + break lnum -= 1 return lines, lnum @@ -272,9 +278,11 @@ def getargs(co): remain.pop() size = count.pop() stack[-size:] = [stack[-size:]] - if not remain: break + if not remain: + break remain[-1] = remain[-1] - 1 - if not remain: break + if not remain: + break args[i] = stack[0] varargs = None From 18bbd7487c520918849bc8ff91269276a046679e Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Thu, 18 Feb 2016 21:39:46 +0100 Subject: [PATCH 0188/4859] @carreau comment's --- IPython/core/magics/auto.py | 1 + IPython/core/magics/basic.py | 1 + IPython/core/magics/code.py | 1 + IPython/core/magics/config.py | 1 + IPython/core/magics/execution.py | 1 + 5 files changed, 5 insertions(+) diff --git a/IPython/core/magics/auto.py b/IPython/core/magics/auto.py index bec35998dab..f87bafdeb17 100644 --- a/IPython/core/magics/auto.py +++ b/IPython/core/magics/auto.py @@ -1,6 +1,7 @@ """Implementation of magic functions that control various automatic behaviors. """ from __future__ import print_function +from __future__ import absolute_import #----------------------------------------------------------------------------- # Copyright (c) 2012 The IPython Development Team. # diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index df069f6591a..b42aab9e9d1 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -1,6 +1,7 @@ """Implementation of basic magic functions.""" from __future__ import print_function +from __future__ import absolute_import import io import sys diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index 924dd13e5ec..4581fff6f96 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -1,6 +1,7 @@ """Implementation of code management magic functions. """ from __future__ import print_function +from __future__ import absolute_import #----------------------------------------------------------------------------- # Copyright (c) 2012 The IPython Development Team. # diff --git a/IPython/core/magics/config.py b/IPython/core/magics/config.py index e69aee61930..4a17ba5d939 100644 --- a/IPython/core/magics/config.py +++ b/IPython/core/magics/config.py @@ -1,6 +1,7 @@ """Implementation of configuration-related magic functions. """ from __future__ import print_function +from __future__ import absolute_import #----------------------------------------------------------------------------- # Copyright (c) 2012 The IPython Development Team. # diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index c0e30f7b3fc..4dd208b96f3 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -5,6 +5,7 @@ # Distributed under the terms of the Modified BSD License. from __future__ import print_function +from __future__ import absolute_import import ast import bdb From 62d11a71592cc5b273bf1e9e330cc59944639b06 Mon Sep 17 00:00:00 2001 From: Dmitry Zotikov Date: Sun, 21 Feb 2016 01:55:40 +0300 Subject: [PATCH 0189/4859] Ensure pager interprets escape sequences If less is specified in $PAGER, but $LESS either doesn't exist or doesn't contain `-r` option, append `-r` to the pager command string. --- IPython/core/page.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/core/page.py b/IPython/core/page.py index 35677d342e7..340d703dad0 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -308,6 +308,13 @@ def get_pager_cmd(pager_cmd=None): pager_cmd = os.environ['PAGER'] except: pager_cmd = default_pager_cmd + + if pager_cmd == 'less': + try: + os.getenv('LESS').index('-r') + except (ValueError, AttributeError): + pager_cmd += ' -r' + return pager_cmd From 9553793de9b338c783726f885d3892096b397ce5 Mon Sep 17 00:00:00 2001 From: Dmitry Zotikov Date: Sun, 21 Feb 2016 02:24:41 +0300 Subject: [PATCH 0190/4859] (nesting typo) --- IPython/core/page.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index 340d703dad0..df38ddfc831 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -310,10 +310,10 @@ def get_pager_cmd(pager_cmd=None): pager_cmd = default_pager_cmd if pager_cmd == 'less': - try: - os.getenv('LESS').index('-r') - except (ValueError, AttributeError): - pager_cmd += ' -r' + try: + os.getenv('LESS').index('-r') + except (ValueError, AttributeError): + pager_cmd += ' -r' return pager_cmd From fffd0e3d53a6a27fa038d6e2bce6d919f3f9ba25 Mon Sep 17 00:00:00 2001 From: Dmitry Zotikov Date: Sun, 21 Feb 2016 12:39:17 +0300 Subject: [PATCH 0191/4859] Use if instead of try..except --- IPython/core/page.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index df38ddfc831..4b29faaf5f3 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -309,11 +309,8 @@ def get_pager_cmd(pager_cmd=None): except: pager_cmd = default_pager_cmd - if pager_cmd == 'less': - try: - os.getenv('LESS').index('-r') - except (ValueError, AttributeError): - pager_cmd += ' -r' + if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): + pager_cmd += ' -r' return pager_cmd From 164d1459141ace26b746232a4d7903d30b0880f0 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 22 Feb 2016 10:58:56 +0100 Subject: [PATCH 0192/4859] deprecate default_gui_banner instead of removing it outright, which breaks things unnecessarily --- IPython/core/usage.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 0f2ff03787e..21de20b79e3 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -346,3 +346,10 @@ ] default_banner = ''.join(default_banner_parts) + +# deprecated GUI banner + +default_gui_banner = '\n'.join([ + 'DEPRECATED: IPython.core.usage.default_gui_banner is deprecated and will be removed', + default_banner, +]) From ac0799c5812a9daaed1438311a1d75c7723399bf Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 22 Feb 2016 16:59:32 +0000 Subject: [PATCH 0193/4859] Disable continuation prompts to work with stable release of prompt_toolkit --- IPython/terminal/ptshell.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index e751b85bd9e..4c7418f8fef 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -146,7 +146,9 @@ def _(event): app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer), get_prompt_tokens=self.get_prompt_tokens, - get_continuation_tokens=self.get_continuation_tokens, + # The line below is waiting for a new release of + # prompt_toolkit (> 0.57) + #get_continuation_tokens=self.get_continuation_tokens, key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), From 67d7c405d3ee45570b44d4c37a5c23b5f21068d8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 22 Feb 2016 17:02:41 +0000 Subject: [PATCH 0194/4859] Switch over to use prompt_toolkit in IPython --- IPython/terminal/ipapp.py | 2 +- setup.py | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index fe3d0083269..f2c61a92541 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -32,7 +32,7 @@ InteractiveShellApp, shell_flags, shell_aliases ) from IPython.extensions.storemagic import StoreMagics -from IPython.terminal.interactiveshell import TerminalInteractiveShell +from .ptshell import PTInteractiveShell as TerminalInteractiveShell from IPython.utils import warn from IPython.paths import get_ipython_dir from traitlets import ( diff --git a/setup.py b/setup.py index c16bd1d1ed4..fe58b5fd272 100755 --- a/setup.py +++ b/setup.py @@ -195,6 +195,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets', + 'prompt_toolkit', # We will require > 0.57 once a new release is made ] # Platform-specific dependencies: @@ -204,8 +205,6 @@ def run(self): extras_require.update({ ':sys_platform != "win32"': ['pexpect'], ':sys_platform == "darwin"': ['appnope'], - ':sys_platform == "darwin" and platform_python_implementation == "CPython"': ['gnureadline'], - 'terminal:sys_platform == "win32"': ['pyreadline>=2'], 'test:python_version == "2.7"': ['mock'], }) # FIXME: re-specify above platform dependencies for pip < 6 From 7505eae52c463ab83b0b9ce6744af1fb837e3c05 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 22 Feb 2016 17:27:19 +0000 Subject: [PATCH 0195/4859] Fix 'interactive' tests using pipes to a subprocess --- IPython/core/tests/test_shellapp.py | 6 ++++-- IPython/terminal/ptshell.py | 20 ++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/IPython/core/tests/test_shellapp.py b/IPython/core/tests/test_shellapp.py index 197e8286776..6e2e31b0fa6 100644 --- a/IPython/core/tests/test_shellapp.py +++ b/IPython/core/tests/test_shellapp.py @@ -52,8 +52,9 @@ def test_py_script_file_attribute_interactively(self): src = "True\n" self.mktmp(src) + out = 'In [1]: False\n\nIn [2]:' err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None - tt.ipexec_validate(self.fname, 'False', err, options=['-i'], + tt.ipexec_validate(self.fname, out, err, options=['-i'], commands=['"__file__" in globals()', 'exit()']) @dec.skip_win32 @@ -63,6 +64,7 @@ def test_py_script_file_compiler_directive(self): src = "from __future__ import division\n" self.mktmp(src) + out = 'In [1]: float\n\nIn [2]:' err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None - tt.ipexec_validate(self.fname, 'float', err, options=['-i'], + tt.ipexec_validate(self.fname, out, err, options=['-i'], commands=['type(1/2)', 'exit()']) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4c7418f8fef..97f8bb5e9bf 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -4,7 +4,7 @@ import sys from IPython.core.interactiveshell import InteractiveShell -from IPython.utils.py3compat import PY3, cast_unicode_py2 +from IPython.utils.py3compat import PY3, cast_unicode_py2, input from traitlets import Bool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion @@ -83,6 +83,14 @@ def get_continuation_tokens(self, cli, width): ] def init_prompt_toolkit_cli(self): + if not sys.stdin.isatty(): + # Piped input - e.g. for tests. Fall back to plain non-interactive + # output. This is very limited, and only accepts a single line. + def prompt(): + return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) + self.prompt_for_code = prompt + return + kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode) insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT) # Ctrl+J == Enter, seemingly @@ -160,6 +168,10 @@ def _(event): self.pt_cli = CommandLineInterface(app, eventloop=create_eventloop(self.inputhook)) + def prompt_for_code(self): + document = self.pt_cli.run(pre_run=self.pre_prompt) + return document.text + def init_io(self): if sys.platform not in {'win32', 'cli'}: return @@ -194,14 +206,14 @@ def interact(self): print(self.separate_in, end='') try: - document = self.pt_cli.run(pre_run=self.pre_prompt) + code = self.prompt_for_code() except EOFError: if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): self.ask_exit() else: - if document: - self.run_cell(document.text, store_history=True) + if code: + self.run_cell(code, store_history=True) def mainloop(self): # An extra layer of protection in case someone mashing Ctrl-C breaks From 93d4f03a44f23a259f1c20f4252dd6751d1251af Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 18 Feb 2016 15:26:06 -0800 Subject: [PATCH 0196/4859] Introduce some classes necessary fro Pygments refactor. --- IPython/core/oinspect.py | 9 ++++++--- IPython/core/ultratb.py | 12 ++++++++---- IPython/utils/PyColorize.py | 9 +++++++-- IPython/utils/colorable.py | 26 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 IPython/utils/colorable.py diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 216f5e78e6d..5258e4cc6bd 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -42,6 +42,7 @@ from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable from IPython.utils.py3compat import cast_unicode, string_types, PY3 from IPython.utils.signatures import signature +from IPython.utils.colorable import Colorable # builtin docstrings to ignore _func_call_docstring = types.FunctionType.__call__.__doc__ @@ -365,13 +366,15 @@ def find_source_lines(obj): return lineno -class Inspector: +class Inspector(Colorable): def __init__(self, color_table=InspectColors, code_color_table=PyColorize.ANSICodeColors, scheme='NoColor', - str_detail_level=0): + str_detail_level=0, + parent=None, config=None): + super(Inspector, self).__init__(parent=parent, config=config) self.color_table = color_table - self.parser = PyColorize.Parser(code_color_table,out='str') + self.parser = PyColorize.Parser(out='str', parent=self, style=scheme) self.format = self.parser.format self.str_detail_level = str_detail_level self.set_active_scheme(scheme) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index e0d3ef5a1e3..f92568b5bd9 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -85,6 +85,7 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** +from __future__ import absolute_import from __future__ import unicode_literals from __future__ import print_function @@ -125,6 +126,8 @@ from IPython.utils.data import uniq_stable from logging import info, error +import IPython.utils.colorable as colorable + # Globals # amount of space to put line numbers before verbose tracebacks INDENT_SIZE = 8 @@ -476,15 +479,16 @@ def find_recursion(etype, value, records): #--------------------------------------------------------------------------- # Module classes -class TBTools(object): +class TBTools(colorable.Colorable): """Basic tools used by all traceback printer classes.""" # Number of frames to skip when reporting tracebacks tb_offset = 0 - def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None): + def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None): # Whether to call the interactive pdb debugger after printing # tracebacks or not + super(TBTools, self).__init__(parent=parent, config=config) self.call_pdb = call_pdb # Output stream to write to. Note that we store the original value in @@ -590,9 +594,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): + def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None): TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb, - ostream=ostream) + ostream=ostream, parent=parent) def __call__(self, etype, value, elist): self.ostream.flush() diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index e42c58d8c6d..def43864f22 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -54,6 +54,8 @@ from IPython.utils.coloransi import TermColors, InputTermColors ,ColorScheme, ColorSchemeTable from IPython.utils.py3compat import PY3 +from .colorable import Colorable + if PY3: from io import StringIO else: @@ -148,15 +150,18 @@ ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], _scheme_default) -class Parser: +class Parser(Colorable): """ Format colored Python source. """ - def __init__(self, color_table=None,out = sys.stdout): + def __init__(self, color_table=None, out = sys.stdout, parent=None, style=None): """ Create a parser with a specified color table and output channel. Call format() to process code. """ + + super(Parser, self).__init__(parent=parent) + self.color_table = color_table and color_table or ANSICodeColors self.out = out diff --git a/IPython/utils/colorable.py b/IPython/utils/colorable.py new file mode 100644 index 00000000000..a885eef092b --- /dev/null +++ b/IPython/utils/colorable.py @@ -0,0 +1,26 @@ +#***************************************************************************** +# Copyright (C) 2016 The IPython Team +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** +from __future__ import absolute_import + +""" +Color managing related utilities +""" + +import pygments + +from traitlets.config import Configurable +from traitlets import Unicode + + +available_themes = lambda : [s for s in pygments.styles.get_all_styles()]+['NoColor','LightBG','Linux'] + +class Colorable(Configurable): + """ + A subclass of configurable for all the classes that have a `default_scheme` + """ + default_style=Unicode('lightbg', config=True) + From d9bbe522ef5d49bab6bed8e6e542cdae39734f93 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 22 Feb 2016 21:23:44 +0000 Subject: [PATCH 0197/4859] Rename PTInteractiveShell to TerminalInteractiveShell This means that existing config will get applied, even if not all of it has the desired effect. I haven't thought of any adverse effects of renaming this. --- IPython/terminal/ipapp.py | 2 +- IPython/terminal/ptshell.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index 6e3b054f85e..ba801770ff2 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -32,7 +32,7 @@ InteractiveShellApp, shell_flags, shell_aliases ) from IPython.extensions.storemagic import StoreMagics -from .ptshell import PTInteractiveShell as TerminalInteractiveShell +from .ptshell import TerminalInteractiveShell from IPython.utils import warn from IPython.paths import get_ipython_dir from traitlets import ( diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 97f8bb5e9bf..1d158254d16 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -45,7 +45,7 @@ def get_completions(self, document, complete_event): for m in matches: yield Completion(m, start_position=start_pos) -class PTInteractiveShell(InteractiveShell): +class TerminalInteractiveShell(InteractiveShell): colors_force = True pt_cli = None @@ -187,7 +187,7 @@ def init_io(self): io.stderr = io.IOStream(sys.stderr) def __init__(self, *args, **kwargs): - super(PTInteractiveShell, self).__init__(*args, **kwargs) + super(TerminalInteractiveShell, self).__init__(*args, **kwargs) self.init_prompt_toolkit_cli() self.keep_running = True @@ -237,4 +237,4 @@ def enable_gui(self, gui=None): self._inputhook = None if __name__ == '__main__': - PTInteractiveShell.instance().interact() + TerminalInteractiveShell.instance().interact() From caa35a40d9ff995f45c53b3958792e06404a9db1 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 23 Feb 2016 10:12:11 +0100 Subject: [PATCH 0198/4859] handle raw video data as input to Video --- IPython/core/display.py | 34 +++++++++++++++++++++--------- IPython/core/tests/test_display.py | 12 +++++++++++ 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index b42e910ad12..3aa8ee172f8 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -6,7 +6,11 @@ from __future__ import print_function -import base64 +try: + from base64 import encodebytes as base64_encode +except ImportError: + from base64 import encodestring as base64_encode + import json import mimetypes import os @@ -849,13 +853,17 @@ def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None Note that QtConsole is not able to display images if `embed` is set to `False` mimetype: unicode Specify the mimetype in case you load in a encoded video. + Examples -------- + Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4') Video('path/to/video.mp4') Video('path/to/video.mp4', embed=False) + Video(b'videodata') + Video(u'b64-encoded-videodata') """ - if url is None and (data.startswith('http') or data.startswith('https')): + if url is None and isinstance(data, string_types) and data.startswith(('http:', 'https:')): url = data data = None embed = False @@ -877,19 +885,25 @@ def _repr_html_(self): """.format(url) return output # Embedded videos uses base64 encoded videos. + mimetype = self.mimetype if self.filename is not None: - mimetypes.init() - mimetype, encoding = mimetypes.guess_type(self.filename) - - video = open(self.filename, 'rb').read() - video_encoded = base64.b64encode(video) + if not mimetype: + mimetype, _ = mimetypes.guess_type(self.filename) + + with open(self.filename, 'rb') as f: + video = f.read() + else: + video = self.data + if isinstance(video, unicode_type): + # unicode input is already b64-encoded + b64_video = video else: - video_encoded = self.data - mimetype = self.mimetype + b64_video = base64_encode(video).decode('ascii').rstrip() + output = """""".format(mimetype, video_encoded.decode('ASCII')) + """.format(mimetype, b64_video) return output def reload(self): diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 97002151ba4..432e2e47242 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -162,3 +162,15 @@ def test_video_embedding(): v = display.Video(f.name, embed=True) html = v._repr_html_() nt.assert_in('src="data:video/mp4;base64,YWJj"',html) + + v = display.Video(f.name, embed=True, mimetype='video/other') + html = v._repr_html_() + nt.assert_in('src="data:video/other;base64,YWJj"',html) + + v = display.Video(b'abc', embed=True, mimetype='video/mp4') + html = v._repr_html_() + nt.assert_in('src="data:video/mp4;base64,YWJj"',html) + + v = display.Video(u'YWJj', embed=True, mimetype='video/xyz') + html = v._repr_html_() + nt.assert_in('src="data:video/xyz;base64,YWJj"',html) From ab815d8e0cb3ed9e8c3b7929f0c6d03a8ac24224 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 23 Feb 2016 15:39:02 +0100 Subject: [PATCH 0199/4859] require explicit embed=True before embedding b64-encoded video --- IPython/core/display.py | 50 ++++++++++++++++++------------ IPython/core/tests/test_display.py | 15 +++++++++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 3aa8ee172f8..458526a41f8 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -824,7 +824,7 @@ def _find_ext(self, s): class Video(DisplayObject): - def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None): + def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None): """Create a video object given raw data or an URL. When this object is returned by an input cell or passed to the @@ -834,45 +834,54 @@ def __init__(self, data=None, url=None, filename=None, embed=None, mimetype=None Parameters ---------- data : unicode, str or bytes - The raw image data or a URL or filename to load the data from. - This always results in embedded image data. + The raw video data or a URL or filename to load the data from. + Raw data will require passing `embed=True`. url : unicode - A URL to download the data from. If you specify `url=`, - the image data will not be embedded unless you also specify `embed=True`. + A URL for the video. If you specify `url=`, + the image data will not be embedded. filename : unicode - Path to a local file to load the data from. - Videos from a file are always embedded. + Path to a local file containing the video. + Will be interpreted as a local URL unless `embed=True`. embed : bool - Should the image data be embedded using a data URI (True) or be - loaded using an tag. Set this to True if you want the image - to be viewable later with no internet connection in the notebook. + Should the video be embedded using a data URI (True) or be + loaded using a """.format(url) return output - # Embedded videos uses base64 encoded videos. + + # Embedded videos are base64-encoded. mimetype = self.mimetype if self.filename is not None: if not mimetype: diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 432e2e47242..2d6cfe427a4 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -155,10 +155,24 @@ def test_json(): def test_video_embedding(): """use a tempfile, with dummy-data, to ensure that video embedding doesn't crash""" + v = display.Video("http://ignored") + assert not v.embed + html = v._repr_html_() + nt.assert_not_in('src="data:', html) + nt.assert_in('src="http://ignored"', html) + + with nt.assert_raises(ValueError): + v = display.Video(b'abc') + with tempfile.NamedTemporaryFile(suffix='.mp4') as f: with open(f.name,'wb') as f: f.write(b'abc') + v = display.Video(f.name) + assert not v.embed + html = v._repr_html_() + nt.assert_not_in('src="data:', html) + v = display.Video(f.name, embed=True) html = v._repr_html_() nt.assert_in('src="data:video/mp4;base64,YWJj"',html) @@ -174,3 +188,4 @@ def test_video_embedding(): v = display.Video(u'YWJj', embed=True, mimetype='video/xyz') html = v._repr_html_() nt.assert_in('src="data:video/xyz;base64,YWJj"',html) + From a711787105924c157c5423a9fabf1d269fcaef89 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 23 Feb 2016 17:48:04 +0000 Subject: [PATCH 0200/4859] Better error message for unknown input hook Closes gh-9264 --- IPython/terminal/pt_inputhooks/__init__.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index 94709ec1986..7030ec59554 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -3,14 +3,36 @@ aliases = { 'qt4': 'qt', + 'gtk2': 'gtk', } +backends = [ + 'qt', 'qt4', 'qt5', + 'gtk', 'gtk2', 'gtk3', + 'tk', + 'wx', + 'pyglet', 'glut', +] + +class UnknownBackend(KeyError): + def __init__(self, name): + self.name = name + + def __str__(self): + return ("No event loop integration for {!r}. " + "Supported event loops are: {}").format(self.name, + ', '.join(backends)) + def get_inputhook_func(gui): + if gui not in backends: + raise UnknownBackend(gui) + if gui in aliases: return get_inputhook_func(aliases[gui]) if gui == 'qt5': os.environ['QT_API'] = 'pyqt5' + gui = 'qt' mod = importlib.import_module('IPython.terminal.pt_inputhooks.'+gui) return mod.inputhook From be9226c6c9a6c5c8656cd1b5e3d169eab50f812f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 23 Feb 2016 23:21:08 +0000 Subject: [PATCH 0201/4859] Re-enable continuation prompts Now that prompt_toolkit 0.58 is out, this should work. --- IPython/terminal/ptshell.py | 4 +--- setup.py | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 1d158254d16..4ad704703e6 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -154,9 +154,7 @@ def _(event): app = create_prompt_application(multiline=True, lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer), get_prompt_tokens=self.get_prompt_tokens, - # The line below is waiting for a new release of - # prompt_toolkit (> 0.57) - #get_continuation_tokens=self.get_continuation_tokens, + get_continuation_tokens=self.get_continuation_tokens, key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), diff --git a/setup.py b/setup.py index 51ba3173169..7387f627157 100755 --- a/setup.py +++ b/setup.py @@ -195,7 +195,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets', - 'prompt_toolkit', # We will require > 0.57 once a new release is made + 'prompt_toolkit>=0.58', ] # Platform-specific dependencies: From f18a60ebd11e385eff17b451c22c3237b107151f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 23 Feb 2016 17:05:05 -0800 Subject: [PATCH 0202/4859] 'Restore `...:` as continuation prompt ' --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4ad704703e6..8c7372542eb 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -79,7 +79,7 @@ def get_prompt_tokens(self, cli): def get_continuation_tokens(self, cli, width): return [ - (Token.Prompt, (' ' * (width - 2)) + ': '), + (Token.Prompt, (' ' * (width - 5)) + '...: '), ] def init_prompt_toolkit_cli(self): From d09db506bbb6dc2c267f9f70f027da7a856fa99f Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 24 Feb 2016 10:14:47 +0100 Subject: [PATCH 0203/4859] support term_title in pt shell fixes failures in ipexec tests run with traitlets master, caused by warnings about ignored config (rightly so!) --- IPython/terminal/ptshell.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 8c7372542eb..801225ab982 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -5,6 +5,8 @@ from IPython.core.interactiveshell import InteractiveShell from IPython.utils.py3compat import PY3, cast_unicode_py2, input +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 from prompt_toolkit.completion import Completer, Completion @@ -28,6 +30,7 @@ from .interactiveshell import get_default_editor + class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" def __init__(self, ipy_completer): @@ -69,6 +72,20 @@ class TerminalInteractiveShell(InteractiveShell): editor = Unicode(get_default_editor(), config=True, help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ) + + term_title = Bool(True, config=True, + help="Automatically set the terminal title" + ) + def _term_title_changed(self, name, new_value): + self.init_term_title() + + def init_term_title(self): + # Enable or disable the terminal title. + if self.term_title: + toggle_set_term_title(True) + set_term_title('IPython: ' + abbrev_cwd()) + else: + toggle_set_term_title(False) def get_prompt_tokens(self, cli): return [ @@ -187,6 +204,7 @@ def init_io(self): def __init__(self, *args, **kwargs): super(TerminalInteractiveShell, self).__init__(*args, **kwargs) self.init_prompt_toolkit_cli() + self.init_term_title() self.keep_running = True def ask_exit(self): From 209d4a1697714139583187d15d6c086a5e7f2b5d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 24 Feb 2016 11:17:05 +0000 Subject: [PATCH 0204/4859] Add explicit dependency on pygments It's used for the syntax highlighting, and prompt_toolkit no longer depends on it. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 7387f627157..f741af59d74 100755 --- a/setup.py +++ b/setup.py @@ -196,6 +196,7 @@ def run(self): 'simplegeneric>0.8', 'traitlets', 'prompt_toolkit>=0.58', + 'pygments', ] # Platform-specific dependencies: From 5ab597c31e5d86c3e37db9ddbe3125bfed6e9e7f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 24 Feb 2016 11:34:09 +0000 Subject: [PATCH 0205/4859] Restore terminal magics and aliases Closes gh-9263 --- IPython/terminal/ptshell.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 801225ab982..7cf07a19888 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -1,6 +1,7 @@ """IPython terminal interface using prompt_toolkit in place of readline""" from __future__ import print_function +import os import sys from IPython.core.interactiveshell import InteractiveShell @@ -27,7 +28,7 @@ from pygments.token import Token from .pt_inputhooks import get_inputhook_func -from .interactiveshell import get_default_editor +from .interactiveshell import get_default_editor, TerminalMagics @@ -201,6 +202,23 @@ def init_io(self): io.stdout = io.IOStream(sys.stdout) io.stderr = io.IOStream(sys.stderr) + def init_magics(self): + super(TerminalInteractiveShell, self).init_magics() + self.register_magics(TerminalMagics) + + def init_alias(self): + # The parent class defines aliases that can be safely used with any + # frontend. + super(TerminalInteractiveShell, self).init_alias() + + # Now define aliases that only make sense on the terminal, because they + # need direct access to the console in a way that we can't emulate in + # GUI or web frontend + if os.name == 'posix': + for cmd in ['clear', 'more', 'less', 'man']: + self.alias_manager.soft_define_alias(cmd, cmd) + + def __init__(self, *args, **kwargs): super(TerminalInteractiveShell, self).__init__(*args, **kwargs) self.init_prompt_toolkit_cli() From 750f3c66306f3cffc65375998e117d5a779c18ad Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 24 Feb 2016 13:29:25 +0000 Subject: [PATCH 0206/4859] Don't try to open temporary file twice in video embed test This test fell foul of the Windows file locking behaviour where only one open handle is permitted on a file. --- IPython/core/tests/test_display.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 2d6cfe427a4..9f10df491aa 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -10,6 +10,7 @@ from IPython.core import display from IPython.core.getipython import get_ipython +from IPython.utils.tempdir import NamedFileInTemporaryDirectory from IPython import paths as ipath import IPython.testing.decorators as dec @@ -164,9 +165,9 @@ def test_video_embedding(): with nt.assert_raises(ValueError): v = display.Video(b'abc') - with tempfile.NamedTemporaryFile(suffix='.mp4') as f: - with open(f.name,'wb') as f: - f.write(b'abc') + with NamedFileInTemporaryDirectory('test.mp4') as f: + f.write(b'abc') + f.close() v = display.Video(f.name) assert not v.embed From 5ddb9d5f2d218f1d65dfa2baa88691a0ec014a2d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 24 Feb 2016 16:42:49 +0000 Subject: [PATCH 0207/4859] Use simplified prompt in test_embed This should avoid the intermittent failures we saw. --- IPython/terminal/ptshell.py | 6 +++--- IPython/terminal/tests/test_embed.py | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 7cf07a19888..e76b56a6323 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -101,9 +101,9 @@ def get_continuation_tokens(self, cli, width): ] def init_prompt_toolkit_cli(self): - if not sys.stdin.isatty(): - # Piped input - e.g. for tests. Fall back to plain non-interactive - # output. This is very limited, and only accepts a single line. + if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty(): + # Fall back to plain non-interactive output for tests. + # This is very limited, and only accepts a single line. def prompt(): return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) self.prompt_for_code = prompt diff --git a/IPython/terminal/tests/test_embed.py b/IPython/terminal/tests/test_embed.py index 5103c47e3df..9f164ea4463 100644 --- a/IPython/terminal/tests/test_embed.py +++ b/IPython/terminal/tests/test_embed.py @@ -12,9 +12,9 @@ #----------------------------------------------------------------------------- import os +import subprocess import sys import nose.tools as nt -from IPython.utils.process import process_handler from IPython.utils.tempdir import NamedFileInTemporaryDirectory from IPython.testing.decorators import skip_win32 @@ -47,9 +47,14 @@ def test_ipython_embed(): # run `python file_with_embed.py` cmd = [sys.executable, f.name] + env = os.environ.copy() + env['IPY_TEST_SIMPLE_PROMPT'] = '1' + + p = subprocess.Popen(cmd, env=env, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate(_exit) + std = out.decode('UTF-8') - out, p = process_handler(cmd, lambda p: (p.communicate(_exit), p)) - std = out[0].decode('UTF-8') nt.assert_equal(p.returncode, 0) nt.assert_in('3 . 14', std) if os.name != 'nt': @@ -62,9 +67,12 @@ def test_nest_embed(): """test that `IPython.embed()` is nestable""" import pexpect ipy_prompt = r']:' #ansi color codes give problems matching beyond this + env = os.environ.copy() + env['IPY_TEST_SIMPLE_PROMPT'] = '1' - child = pexpect.spawn('%s -m IPython --colors=nocolor'%(sys.executable, )) + child = pexpect.spawn(sys.executable, ['-m', 'IPython', '--colors=nocolor'], + env=env) child.expect(ipy_prompt) child.sendline("from __future__ import print_function") child.expect(ipy_prompt) From ea96ced4d3cacb503c26a2873a5bae041f5d17e1 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 26 Feb 2016 10:01:25 +0000 Subject: [PATCH 0208/4859] IPython requires colorama on Windows I forgot to add this to the dependencies in the prompt_toolkit PR. --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index f741af59d74..e3db2831463 100755 --- a/setup.py +++ b/setup.py @@ -206,6 +206,7 @@ def run(self): extras_require.update({ ':sys_platform != "win32"': ['pexpect'], ':sys_platform == "darwin"': ['appnope'], + ':sys_platform == "win32"': ['colorama'], 'test:python_version == "2.7"': ['mock'], }) # FIXME: re-specify above platform dependencies for pip < 6 From 8e53e7ba8a4f415165e30bf5c3c75d5d61cc4913 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 29 Feb 2016 22:09:02 +0000 Subject: [PATCH 0209/4859] Tab key inserts four spaces at the start of the line Addresses part of gh-9283 --- IPython/terminal/ptshell.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index e76b56a6323..c710ac5cce2 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -12,7 +12,7 @@ from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER -from prompt_toolkit.filters import HasFocus, HasSelection +from prompt_toolkit.filters import HasFocus, HasSelection, Condition from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop from prompt_toolkit.interface import CommandLineInterface @@ -136,6 +136,21 @@ def _(event): def _(event): event.current_buffer.reset() + @Condition + def cursor_in_leading_ws(cli): + before = cli.application.buffer.document.current_line_before_cursor + return (not before) or before.isspace() + + # Ctrl+I == Tab + @kbmanager.registry.add_binding(Keys.ControlI, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + & cursor_in_leading_ws + )) + def _(event): + event.current_buffer.insert_text(' ' * 4) + # Pre-populate history from IPython's history database history = InMemoryHistory() last_cell = u"" From f49962dc931870a1eba4b6467ce302c8ae095b3f Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 1 Mar 2016 12:32:53 +0100 Subject: [PATCH 0210/4859] 4.1.2 changes --- docs/source/whatsnew/version4.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/whatsnew/version4.rst b/docs/source/whatsnew/version4.rst index c16ea48eeb9..a7fc23c45c5 100644 --- a/docs/source/whatsnew/version4.rst +++ b/docs/source/whatsnew/version4.rst @@ -6,8 +6,10 @@ IPython 4.1 =========== -Release February, 2016. IPython 4.1 contain mostly bug fixes. It though contain -a few improvement. +IPython 4.1.2 (March, 2016) fixes installation issues with some versions of setuptools. + +Released February, 2016. IPython 4.1 contains mostly bug fixes, +though there are a few improvements. - IPython debugger (IPdb) now supports the number of context lines for the From 2a2b90ed3fe7e0cf2e56bd6c1bb798758b6f4d4b Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 1 Mar 2016 21:29:01 -0500 Subject: [PATCH 0211/4859] FIX: use mpl.get_backend() instead of a global Use `matplotlib.get_backend()` to look up the current backend rather than looking at a module-level golabl in `matplotlib.backends`. Closes #9286 --- IPython/core/pylabtools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 65281787666..a4a8450fec8 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -211,7 +211,7 @@ def select_figure_formats(shell, formats, **kwargs): [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ] - if matplotlib.backends.backend.lower() == 'nbagg': + if matplotlib.get_backend().lower() == 'nbagg': formatter = shell.display_formatter.ipython_display_formatter formatter.for_type(Figure, _reshow_nbagg_figure) From e05a5b61c59a5c1e8a5aa549db89c800bcb84e94 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 2 Mar 2016 12:23:04 +0000 Subject: [PATCH 0212/4859] Allow objects to define their own key completions Objects can specify their own key completions by defining an _ipy_key_completions_() method that returns a list of objects which it expects in a subscript expression. Closes gh-8865 --- IPython/core/completer.py | 21 +++++++++++++++++++-- IPython/core/tests/test_completer.py | 16 ++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 7953dbb065a..f6b119cba41 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -71,7 +71,7 @@ from IPython.utils import generics from IPython.utils import io from IPython.utils.decorators import undoc -from IPython.utils.dir2 import dir2 +from IPython.utils.dir2 import dir2, safe_hasattr from IPython.utils.process import arg_split from IPython.utils.py3compat import builtin_mod, string_types, PY3 from traitlets import CBool, Enum @@ -472,6 +472,18 @@ def _safe_isinstance(obj, module, class_name): return (module in sys.modules and isinstance(obj, getattr(__import__(module), class_name))) +def _safe_really_hasattr(obj, name): + """Checks that an object genuinely has a given attribute. + + Some objects claim to have any attribute that's requested, to act as a lazy + proxy for something else. We want to catch these cases and ignore their + claim to have the attribute we're interested in. + """ + if safe_hasattr(obj, '_ipy_proxy_check_dont_define_this_'): + # If it claims this exists, don't trust it + return False + + return safe_hasattr(obj, name) def back_unicode_name_matches(text): @@ -923,7 +935,12 @@ def python_func_kw_matches(self,text): def dict_key_matches(self, text): "Match string keys in a dictionary, after e.g. 'foo[' " def get_keys(obj): - # Only allow completion for known in-memory dict-like types + # Objects can define their own completions by defining an + # _ipy_key_completions_() method. + if _safe_really_hasattr(obj, '_ipy_key_completions_'): + return obj._ipy_key_completions_() + + # Special case some common in-memory dict-like types if isinstance(obj, dict) or\ _safe_isinstance(obj, 'pandas', 'DataFrame'): try: diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 5c6dbfb1116..5ab36bba128 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -761,6 +761,22 @@ def test_dict_key_completion_invalids(): _, matches = complete(line_buffer="name_error['") _, matches = complete(line_buffer="d['\\") # incomplete escape +class KeyCompletable(object): + def __init__(self, things=()): + self.things = things + + def _ipy_key_completions_(self): + return list(self.things) + +def test_object_key_completion(): + ip = get_ipython() + ip.user_ns['key_completable'] = KeyCompletable(['qwerty', 'qwick']) + + _, matches = ip.Completer.complete(line_buffer="key_completable['qw") + nt.assert_in('qwerty', matches) + nt.assert_in('qwick', matches) + + def test_aimport_module_completer(): ip = get_ipython() _, matches = ip.complete('i', '%aimport i') From b32efbdf76fe08004c1ba47d0d701ff5fb943de8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 2 Mar 2016 16:53:29 +0000 Subject: [PATCH 0213/4859] Rename method to _ipython_key_completions_ --- IPython/core/completer.py | 4 ++-- IPython/core/tests/test_completer.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index f6b119cba41..6ce32a79b94 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -937,8 +937,8 @@ def dict_key_matches(self, text): def get_keys(obj): # Objects can define their own completions by defining an # _ipy_key_completions_() method. - if _safe_really_hasattr(obj, '_ipy_key_completions_'): - return obj._ipy_key_completions_() + if _safe_really_hasattr(obj, '_ipython_key_completions_'): + return obj._ipython_key_completions_() # Special case some common in-memory dict-like types if isinstance(obj, dict) or\ diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 5ab36bba128..8d6f4f06f1f 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -765,7 +765,7 @@ class KeyCompletable(object): def __init__(self, things=()): self.things = things - def _ipy_key_completions_(self): + def _ipython_key_completions_(self): return list(self.things) def test_object_key_completion(): From 7fef958a2fb559bdfeb136b55dc0d2ff3238d184 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 2 Mar 2016 16:58:54 +0000 Subject: [PATCH 0214/4859] Document custom key completions --- docs/source/config/integrating.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/config/integrating.rst b/docs/source/config/integrating.rst index c2c4b585c70..3630ae80da3 100644 --- a/docs/source/config/integrating.rst +++ b/docs/source/config/integrating.rst @@ -11,6 +11,14 @@ To change the attributes displayed by tab-completing your object, define a ``__dir__(self)`` method for it. For more details, see the documentation of the built-in `dir() function `_. +You can also customise key completions for your objects, e.g. pressing tab after +``obj["a``. To do so, define a method ``_ipython_key_completions_()``, which +returns a list of objects which are possible keys in a subscript expression +``obj[key]``. + +.. versionadded:: 5.0 + Custom key completions + Rich display ============ From 9bf4fac39258adc331d864c5f04030accd642719 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 3 Mar 2016 13:11:33 +0000 Subject: [PATCH 0215/4859] Consolidate code to check for method in IPython.utils.dir2 --- IPython/core/completer.py | 20 +++------------ IPython/core/displayhook.py | 1 - IPython/core/formatters.py | 28 +++----------------- IPython/utils/dir2.py | 51 +++++++++++++++++++++++++++---------- 4 files changed, 44 insertions(+), 56 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 6ce32a79b94..86ba87e77cc 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -71,7 +71,7 @@ from IPython.utils import generics from IPython.utils import io from IPython.utils.decorators import undoc -from IPython.utils.dir2 import dir2, safe_hasattr +from IPython.utils.dir2 import dir2, get_real_method from IPython.utils.process import arg_split from IPython.utils.py3compat import builtin_mod, string_types, PY3 from traitlets import CBool, Enum @@ -472,19 +472,6 @@ def _safe_isinstance(obj, module, class_name): return (module in sys.modules and isinstance(obj, getattr(__import__(module), class_name))) -def _safe_really_hasattr(obj, name): - """Checks that an object genuinely has a given attribute. - - Some objects claim to have any attribute that's requested, to act as a lazy - proxy for something else. We want to catch these cases and ignore their - claim to have the attribute we're interested in. - """ - if safe_hasattr(obj, '_ipy_proxy_check_dont_define_this_'): - # If it claims this exists, don't trust it - return False - - return safe_hasattr(obj, name) - def back_unicode_name_matches(text): u"""Match unicode characters back to unicode name @@ -937,8 +924,9 @@ def dict_key_matches(self, text): def get_keys(obj): # Objects can define their own completions by defining an # _ipy_key_completions_() method. - if _safe_really_hasattr(obj, '_ipython_key_completions_'): - return obj._ipython_key_completions_() + method = get_real_method(obj, '_ipython_key_completions_') + if method is not None: + return method() # Special case some common in-memory dict-like types if isinstance(obj, dict) or\ diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 1e721f967b4..4d174085345 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -13,7 +13,6 @@ import io as _io import tokenize -from IPython.core.formatters import _safe_get_formatter_method from traitlets.config.configurable import Configurable from IPython.utils import io from IPython.utils.py3compat import builtin_mod, cast_unicode_py2 diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index aa0567929b8..700a90395b5 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -22,6 +22,7 @@ from traitlets.config.configurable import Configurable from IPython.core.getipython import get_ipython from IPython.utils.sentinel import Sentinel +from IPython.utils.dir2 import get_real_method from IPython.lib import pretty from traitlets import ( Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, @@ -32,29 +33,6 @@ ) -#----------------------------------------------------------------------------- -# The main DisplayFormatter class -#----------------------------------------------------------------------------- - - -def _safe_get_formatter_method(obj, name): - """Safely get a formatter method - - - Classes cannot have formatter methods, only instance - - protect against proxy objects that claim to have everything - """ - if inspect.isclass(obj): - # repr methods only make sense on instances, not classes - return None - method = pretty._safe_getattr(obj, name, None) - if callable(method): - # obj claims to have repr method... - if callable(pretty._safe_getattr(obj, '_ipython_canary_method_should_not_exist_', None)): - # ...but don't trust proxy objects that claim to have everything - return None - return method - - class DisplayFormatter(Configurable): # When set to true only the default plain text formatter will be used. @@ -338,7 +316,7 @@ def __call__(self, obj): else: return printer(obj) # Finally look for special method names - method = _safe_get_formatter_method(obj, self.print_method) + method = get_real_method(obj, self.print_method) if method is not None: return method() return None @@ -904,7 +882,7 @@ def __call__(self, obj): printer(obj) return True # Finally look for special method names - method = _safe_get_formatter_method(obj, self.print_method) + method = get_real_method(obj, self.print_method) if method is not None: method() return True diff --git a/IPython/utils/dir2.py b/IPython/utils/dir2.py index 50c660af321..f6f164f9b12 100644 --- a/IPython/utils/dir2.py +++ b/IPython/utils/dir2.py @@ -2,21 +2,11 @@ """A fancy version of Python's builtin :func:`dir` function. """ -#----------------------------------------------------------------------------- -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -from .py3compat import string_types +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. -#----------------------------------------------------------------------------- -# Code -#----------------------------------------------------------------------------- +import inspect +from .py3compat import string_types def safe_hasattr(obj, attr): @@ -56,3 +46,36 @@ def dir2(obj): words = [w for w in words if isinstance(w, string_types)] return sorted(words) + + +def get_real_method(obj, name): + """Like getattr, but with a few extra sanity checks: + + - If obj is a class, ignore its methods + - Check if obj is a proxy that claims to have all attributes + - Catch attribute access failing with any exception + - Check that the attribute is a callable object + + Returns the method or None. + """ + if inspect.isclass(obj): + return None + + try: + canary = getattr(obj, '_ipython_canary_method_should_not_exist_', None) + except Exception: + return None + + if canary is not None: + # It claimed to have an attribute it should never have + return None + + try: + m = getattr(obj, name, None) + except Exception: + return None + + if callable(m): + return m + + return None From 7e110f3b6c5247df3bdd0e759ec982fc126d1912 Mon Sep 17 00:00:00 2001 From: Vincent Woo Date: Sat, 5 Mar 2016 04:37:30 -0800 Subject: [PATCH 0216/4859] Use term width to determine header length --- IPython/core/ultratb.py | 12 +++++++----- IPython/utils/terminal.py | 37 +++---------------------------------- setup.py | 1 + 3 files changed, 11 insertions(+), 39 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index f92568b5bd9..8c4a8fc14ef 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -124,6 +124,7 @@ from IPython.utils import py3compat from IPython.utils import ulinecache from IPython.utils.data import uniq_stable +from IPython.utils.terminal import get_terminal_size from logging import info, error import IPython.utils.colorable as colorable @@ -1029,20 +1030,21 @@ def prepare_header(self, etype, long_version=False): colors = self.Colors # just a shorthand + quicker name lookup colorsnormal = colors.Normal # used a lot exc = '%s%s%s' % (colors.excName, etype, colorsnormal) + width = min(75, get_terminal_size()[0]) if long_version: # Header with the exception type, python version, and date pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable date = time.ctime(time.time()) - head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal, - exc, ' ' * (75 - len(str(etype)) - len(pyver)), - pyver, date.rjust(75) ) + head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * width, colorsnormal, + exc, ' ' * (width - len(str(etype)) - len(pyver)), + pyver, date.rjust(width) ) head += "\nA problem occurred executing Python code. Here is the sequence of function" \ "\ncalls leading up to the error, with the most recent (innermost) call last." else: # Simplified header head = '%s%s' % (exc, 'Traceback (most recent call last)'. \ - rjust(75 - len(str(etype))) ) + rjust(width - len(str(etype))) ) return head @@ -1155,7 +1157,7 @@ def structured_traceback(self, etype, evalue, etb, tb_offset=None, colors = self.Colors # just a shorthand + quicker name lookup colorsnormal = colors.Normal # used a lot - head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal) + head = '%s%s%s' % (colors.topline, '-' * min(75, get_terminal_size()[0]), colorsnormal) structured_traceback_parts = [head] if py3compat.PY3: chained_exceptions_tb_offset = 0 diff --git a/IPython/utils/terminal.py b/IPython/utils/terminal.py index ff31045cece..9e7be2a6da7 100644 --- a/IPython/utils/terminal.py +++ b/IPython/utils/terminal.py @@ -24,6 +24,7 @@ import struct import sys import warnings +import backports.shutil_get_terminal_size from . import py3compat @@ -120,37 +121,5 @@ def freeze_term_title(): ignore_termtitle = True -if sys.platform == 'win32': - def get_terminal_size(defaultx=80, defaulty=25): - """Return size of current terminal console. - - This function try to determine actual size of current working - console window and return tuple (sizex, sizey) if success, - or default size (defaultx, defaulty) otherwise. - - Dependencies: ctypes should be installed. - - Author: Alexander Belchenko (e-mail: bialix AT ukr.net) - """ - try: - import ctypes - except ImportError: - return defaultx, defaulty - - h = ctypes.windll.kernel32.GetStdHandle(-11) - csbi = ctypes.create_string_buffer(22) - res = ctypes.windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) - - if res: - (bufx, bufy, curx, cury, wattr, - left, top, right, bottom, maxx, maxy) = struct.unpack( - "hhhhHhhhhhh", csbi.raw) - sizex = right - left + 1 - sizey = bottom - top + 1 - return (sizex, sizey) - else: - return (defaultx, defaulty) -else: - def get_terminal_size(defaultx=80, defaulty=25): - return defaultx, defaulty - +def get_terminal_size(defaultx=80, defaulty=25): + return backports.shutil_get_terminal_size.get_terminal_size((defaultx, defaulty)) diff --git a/setup.py b/setup.py index e3db2831463..905b2b01e11 100755 --- a/setup.py +++ b/setup.py @@ -197,6 +197,7 @@ def run(self): 'traitlets', 'prompt_toolkit>=0.58', 'pygments', + 'backports.shutil_get_terminal_size', ] # Platform-specific dependencies: From 6fa1c178e1ec26062812db8e71c18458fe30897c Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 5 Mar 2016 20:26:24 -0500 Subject: [PATCH 0217/4859] FIX: account for dpi == 'figure' In mpl 1.5.0 'figure' became a valid dpi value, in 2.0 it will become the default. xref https://github.com/matplotlib/matplotlib/issues/6113 --- IPython/core/pylabtools.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index 65281787666..f8651995298 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -98,6 +98,8 @@ def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs): return dpi = rcParams['savefig.dpi'] + if dpi == 'figure': + dpi = fig.dpi if fmt == 'retina': dpi = dpi * 2 fmt = 'png' From ca5c92338360cacecc7e7fd9e4a39eb461bf0153 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 8 Mar 2016 11:24:51 +0000 Subject: [PATCH 0218/4859] Override terminal size in doctests to standardise traceback format Should fix test failures on Jenkins --- IPython/testing/plugin/ipdoctest.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index 015937b9af8..baebc8bcb4f 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -28,6 +28,8 @@ import traceback import unittest +from testpath import modified_env + from inspect import getmodule # We are overriding the default doctest runner, so we need to import a few @@ -587,8 +589,10 @@ def run(self, test, compileflags=None, out=None, clear_globs=True): test.globs.update(_ip.user_ns) - return super(IPDocTestRunner,self).run(test, - compileflags,out,clear_globs) + # Override terminal size to standardise traceback format + with modified_env({'COLUMNS': '80', 'LINES': '24'}): + return super(IPDocTestRunner,self).run(test, + compileflags,out,clear_globs) class DocFileCase(doctest.DocFileCase): From 11696ddc15765ca35fd15c5874520249ad6780b4 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 10 Mar 2016 16:35:33 +0100 Subject: [PATCH 0219/4859] Add OS X input hook It almost works: not responsive due to input callback not waking app until window is interacted with --- IPython/terminal/pt_inputhooks/__init__.py | 1 + IPython/terminal/pt_inputhooks/osx.py | 104 +++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 IPython/terminal/pt_inputhooks/osx.py diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index 7030ec59554..e98ea2ec1d2 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -12,6 +12,7 @@ 'tk', 'wx', 'pyglet', 'glut', + 'osx', ] class UnknownBackend(KeyError): diff --git a/IPython/terminal/pt_inputhooks/osx.py b/IPython/terminal/pt_inputhooks/osx.py new file mode 100644 index 00000000000..518a0b97ee3 --- /dev/null +++ b/IPython/terminal/pt_inputhooks/osx.py @@ -0,0 +1,104 @@ + +# obj-c boilerplate from appnope, used under BSD 2-clause + +import ctypes +import ctypes.util + +objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc')) +CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) +# Cocoa = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Cocoa')) + +void_p = ctypes.c_void_p + +objc.objc_getClass.restype = void_p +objc.sel_registerName.restype = void_p +objc.objc_msgSend.restype = void_p +objc.objc_msgSend.argtypes = [void_p, void_p] + +msg = objc.objc_msgSend + +def _utf8(s): + """ensure utf8 bytes""" + if not isinstance(s, bytes): + s = s.encode('utf8') + return s + +def n(name): + """create a selector name (for methods)""" + return objc.sel_registerName(_utf8(name)) + +def C(classname): + """get an ObjC Class by name""" + return objc.objc_getClass(_utf8(classname)) + +# CoreFoundation calls we will use: +CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate +CFFileDescriptorCreate.restype = void_p +CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p] + +CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor +CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int +CFFileDescriptorGetNativeDescriptor.argtypes = [void_p] + +CFFileDescriptorEnableCallBacks = CoreFoundation.CFFileDescriptorEnableCallBacks +CFFileDescriptorEnableCallBacks.restype = None +CFFileDescriptorEnableCallBacks.argtypes = [void_p, ctypes.c_ulong] + +CFFileDescriptorCreateRunLoopSource = CoreFoundation.CFFileDescriptorCreateRunLoopSource +CFFileDescriptorCreateRunLoopSource.restype = void_p +CFFileDescriptorCreateRunLoopSource.argtypes = [void_p, void_p, void_p] + +CFRunLoopGetCurrent = CoreFoundation.CFRunLoopGetCurrent +CFRunLoopGetCurrent.restype = void_p + +CFRunLoopAddSource = CoreFoundation.CFRunLoopAddSource +CFRunLoopAddSource.restype = None +CFRunLoopAddSource.argtypes = [void_p, void_p, void_p] + +CFRelease = CoreFoundation.CFRelease +CFRelease.restype = None +CFRelease.argtypes = [void_p] + +CFFileDescriptorInvalidate = CoreFoundation.CFFileDescriptorInvalidate +CFFileDescriptorInvalidate.restype = None +CFFileDescriptorInvalidate.argtypes = [void_p] + + +# From CFFileDescriptor.h +kCFFileDescriptorReadCallBack = 1 +kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes') + +def _NSApp(): + """Return the global NSApplication instance (NSApp)""" + return msg(C('NSApplication'), n('sharedApplication')) + +def _input_callback(fdref, flags, info): + """Callback to fire when there's input to be read""" + CFFileDescriptorInvalidate(fdref) + CFRelease(fdref) + NSApp = _NSApp() + msg(NSApp, n('stop:'), NSApp) + +_c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p) +_c_callback = _c_callback_func_type(_input_callback) + +def _stop_on_read(fd): + """Register callback to stop eventloop when there's data on fd""" + fdref = CFFileDescriptorCreate(None, fd, False, _c_callback, None) + CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack) + source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0) + loop = CFRunLoopGetCurrent() + CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes) + CFRelease(source) + +def inputhook(context): + """Inputhook for Cocoa (NSApp)""" + NSApp = _NSApp() + window_count = msg( + msg(NSApp, n('windows')), + n('count') + ) + if not window_count: + return + _stop_on_read(context.fileno()) + msg(NSApp, n('run')) From a59bda821aca72b80af774d72bb211da0eed70f8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 10 Mar 2016 17:37:54 +0100 Subject: [PATCH 0220/4859] Wake the main loop with an event --- IPython/terminal/pt_inputhooks/osx.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/pt_inputhooks/osx.py b/IPython/terminal/pt_inputhooks/osx.py index 518a0b97ee3..cd7eee388e9 100644 --- a/IPython/terminal/pt_inputhooks/osx.py +++ b/IPython/terminal/pt_inputhooks/osx.py @@ -6,7 +6,6 @@ objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc')) CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) -# Cocoa = ctypes.cdll.LoadLibrary(ctypes.util.find_library('Cocoa')) void_p = ctypes.c_void_p @@ -24,7 +23,7 @@ def _utf8(s): return s def n(name): - """create a selector name (for methods)""" + """create a selector name (for ObjC methods)""" return objc.sel_registerName(_utf8(name)) def C(classname): @@ -63,7 +62,6 @@ def C(classname): CFFileDescriptorInvalidate.restype = None CFFileDescriptorInvalidate.argtypes = [void_p] - # From CFFileDescriptor.h kCFFileDescriptorReadCallBack = 1 kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes') @@ -72,19 +70,37 @@ def _NSApp(): """Return the global NSApplication instance (NSApp)""" return msg(C('NSApplication'), n('sharedApplication')) +def _wake(NSApp): + """Wake the Application""" + event = msg(C('NSEvent'), + n('otherEventWithType:location:modifierFlags:' + 'timestamp:windowNumber:context:subtype:data1:data2:'), + 15, # Type + 0, # location + 0, # flags + 0, # timestamp + 0, # window + None, # context + 0, # subtype + 0, # data1 + 0, # data2 + ) + msg(NSApp, n('postEvent:atStart:'), void_p(event), True) + def _input_callback(fdref, flags, info): """Callback to fire when there's input to be read""" CFFileDescriptorInvalidate(fdref) CFRelease(fdref) NSApp = _NSApp() msg(NSApp, n('stop:'), NSApp) + _wake(NSApp) _c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p) -_c_callback = _c_callback_func_type(_input_callback) +_c_input_callback = _c_callback_func_type(_input_callback) def _stop_on_read(fd): """Register callback to stop eventloop when there's data on fd""" - fdref = CFFileDescriptorCreate(None, fd, False, _c_callback, None) + fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None) CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack) source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0) loop = CFRunLoopGetCurrent() @@ -102,3 +118,4 @@ def inputhook(context): return _stop_on_read(context.fileno()) msg(NSApp, n('run')) + From 64919366f54860542a60ad9ec5396879821362e7 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 10 Mar 2016 17:51:25 +0100 Subject: [PATCH 0221/4859] tidy, docstrings --- IPython/terminal/pt_inputhooks/osx.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/pt_inputhooks/osx.py b/IPython/terminal/pt_inputhooks/osx.py index cd7eee388e9..9f41c3f4a36 100644 --- a/IPython/terminal/pt_inputhooks/osx.py +++ b/IPython/terminal/pt_inputhooks/osx.py @@ -1,3 +1,7 @@ +"""Inputhook for OS X + +Calls NSApp / CoreFoundation APIs via ctypes. +""" # obj-c boilerplate from appnope, used under BSD 2-clause @@ -5,7 +9,6 @@ import ctypes.util objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc')) -CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) void_p = ctypes.c_void_p @@ -30,7 +33,11 @@ def C(classname): """get an ObjC Class by name""" return objc.objc_getClass(_utf8(classname)) -# CoreFoundation calls we will use: +# end obj-c boilerplate from appnope + +# CoreFoundation C-API calls we will use: +CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundation')) + CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate CFFileDescriptorCreate.restype = void_p CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p] @@ -66,10 +73,12 @@ def C(classname): kCFFileDescriptorReadCallBack = 1 kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes') + def _NSApp(): """Return the global NSApplication instance (NSApp)""" return msg(C('NSApplication'), n('sharedApplication')) + def _wake(NSApp): """Wake the Application""" event = msg(C('NSEvent'), @@ -86,7 +95,8 @@ def _wake(NSApp): 0, # data2 ) msg(NSApp, n('postEvent:atStart:'), void_p(event), True) - + + def _input_callback(fdref, flags, info): """Callback to fire when there's input to be read""" CFFileDescriptorInvalidate(fdref) @@ -98,6 +108,7 @@ def _input_callback(fdref, flags, info): _c_callback_func_type = ctypes.CFUNCTYPE(None, void_p, void_p, void_p) _c_input_callback = _c_callback_func_type(_input_callback) + def _stop_on_read(fd): """Register callback to stop eventloop when there's data on fd""" fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None) @@ -107,6 +118,7 @@ def _stop_on_read(fd): CFRunLoopAddSource(loop, source, kCFRunLoopCommonModes) CFRelease(source) + def inputhook(context): """Inputhook for Cocoa (NSApp)""" NSApp = _NSApp() From 024df253247717b59d7b285ad973b7d2bb4b491a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 10 Mar 2016 21:40:36 +0000 Subject: [PATCH 0222/4859] Only handle Ctrl-C when in main input buffer This allows Ctrl-C to work as normal within Ctrl-R search (see gh-9309) --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c710ac5cce2..3e5216098c5 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -132,7 +132,7 @@ def _(event): else: b.insert_text('\n' + (' ' * (indent or 0))) - @kbmanager.registry.add_binding(Keys.ControlC) + @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) def _(event): event.current_buffer.reset() From ad9c12c37b4de9eef412a4a285f6a0f01fec1daf Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Fri, 11 Mar 2016 13:54:37 -0800 Subject: [PATCH 0223/4859] remove nag screen delay see https://twitter.com/njgoldbaum/status/708360792677208064 and my response, which has support of 3 other people. https://twitter.com/ivanov/status/708409804448993280 --- IPython/core/application.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 86cfdcd3306..fddc525b619 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -202,12 +202,8 @@ def initialize_subcommand(self, subc, argv=None): import time self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " "in future versions.".format(sub=subc)) - self.log.warning("You likely want to use `jupyter {sub}`... continue " - "in 5 sec. Press Ctrl-C to quit now.".format(sub=subc)) - try: - time.sleep(5) - except KeyboardInterrupt: - sys.exit(1) + self.log.warning("You likely want to use `jupyter {sub}`... in the" + "future".format(sub=subc)) return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv) def init_crash_handler(self): From 45dcaa60191027438edf5ae832da7c98ab956035 Mon Sep 17 00:00:00 2001 From: Paul Ivanov Date: Fri, 11 Mar 2016 14:15:17 -0800 Subject: [PATCH 0224/4859] quickfix for #9317 --- IPython/core/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index fddc525b619..6374b7f709f 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -202,7 +202,7 @@ def initialize_subcommand(self, subc, argv=None): import time self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " "in future versions.".format(sub=subc)) - self.log.warning("You likely want to use `jupyter {sub}`... in the" + self.log.warning("You likely want to use `jupyter {sub}` in the " "future".format(sub=subc)) return super(BaseIPythonApplication, self).initialize_subcommand(subc, argv) From f33a826b135f3c259a8691c581fd5035544ed037 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 14 Mar 2016 19:52:36 +0100 Subject: [PATCH 0225/4859] Remove unused `display_banner=False` arg This is no longer used by pt_shell --- IPython/terminal/ipapp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index ba801770ff2..c1a3dad8e49 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -317,7 +317,7 @@ def init_shell(self): # based app, because we call shell.show_banner() by hand below # so the banner shows *before* all extension loading stuff. self.shell = TerminalInteractiveShell.instance(parent=self, - display_banner=False, profile_dir=self.profile_dir, + profile_dir=self.profile_dir, ipython_dir=self.ipython_dir, user_ns=self.user_ns) self.shell.configurables.append(self) From dad5f65facc5bf44dc3dab3ceae165a6c7e90d27 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 17 Mar 2016 16:51:08 +0000 Subject: [PATCH 0226/4859] Don't check for readline when setting autoindent Autoindent is not strictly tied to readline any more, and this warning was annoying me. --- IPython/core/interactiveshell.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3a053f7b003..357098ea04a 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -527,15 +527,9 @@ def _ipython_dir_changed(self, name, new): ensure_dir_exists(new) def set_autoindent(self,value=None): - """Set the autoindent flag, checking for readline support. + """Set the autoindent flag. If called with no arguments, it acts as a toggle.""" - - if value != 0 and not self.has_readline: - if os.name == 'posix': - warn("The auto-indent feature requires the readline library") - self.autoindent = 0 - return if value is None: self.autoindent = not self.autoindent else: From 446a6eddf43d3bf8e62858d9418dead92d7be3b7 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 18 Mar 2016 10:38:54 +0100 Subject: [PATCH 0227/4859] Get signatures directly from classes since we switched to signatures, we no longer need to reach into `Class.__init__` --- IPython/core/oinspect.py | 22 +++++++++++-------- IPython/core/tests/test_oinspect.py | 34 ++++++++++++++++------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 5258e4cc6bd..86e45eee141 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -420,7 +420,6 @@ def pdef(self, obj, oname=''): if inspect.isclass(obj): header = self.__head('Class constructor information:\n') - obj = obj.__init__ elif (not py3compat.PY3) and type(obj) is types.InstanceType: obj = obj.__call__ @@ -766,23 +765,28 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): # Constructor docstring for classes if inspect.isclass(obj): out['isclass'] = True - # reconstruct the function definition and print it: + + # get the function signature: + try: + init_def = self._getdef(obj, oname) + except AttributeError: + init_def = None + else: + out['init_definition'] = self.format(init_def) + + # get the __init__ docstring try: - obj_init = obj.__init__ + obj_init = obj.__init__ except AttributeError: init_def = init_ds = None else: - init_def = self._getdef(obj_init,oname) init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None - if init_def or init_ds: - if init_def: - out['init_definition'] = self.format(init_def) - if init_ds: - out['init_docstring'] = init_ds + if init_ds: + out['init_docstring'] = init_ds # and class docstring for instances: else: diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index c625a745779..e75c9da6d1e 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -1,27 +1,17 @@ """Tests for the object inspection functionality. """ -#----------------------------------------------------------------------------- -# Copyright (C) 2010-2011 The IPython Development Team. -# -# Distributed under the terms of the BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + from __future__ import print_function -# Stdlib imports import os import re import sys -# Third-party imports import nose.tools as nt -# Our own imports from .. import oinspect from IPython.core.magic import (Magics, magics_class, line_magic, cell_magic, line_cell_magic, @@ -32,6 +22,7 @@ from IPython.testing.tools import AssertPrints from IPython.utils.path import compress_user from IPython.utils import py3compat +from IPython.utils.signatures import Signature, Parameter #----------------------------------------------------------------------------- @@ -49,7 +40,7 @@ # defined, if any code is inserted above, the following line will need to be # updated. Do NOT insert any whitespace between the next line and the function # definition below. -THIS_LINE_NUMBER = 52 # Put here the actual number of this line +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) @@ -120,6 +111,14 @@ def __call__(self, *a, **kw): def method(self, x, z=2): """Some method's docstring""" +class HasSignature(object): + """This is the class docstring.""" + __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)]) + + def __init__(self, *args): + """This is the init docstring""" + + class SimpleClass(object): def method(self, x, z=2): """Some method's docstring""" @@ -282,7 +281,7 @@ def test_info(): nt.assert_equal(i['docstring'], Call.__doc__) nt.assert_equal(i['source'], None) nt.assert_true(i['isclass']) - nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n") + nt.assert_equal(i['init_definition'], "Call(x, y=1)\n") nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) i = inspector.info(Call, detail_level=1) @@ -307,6 +306,11 @@ def test_info(): nt.assert_equal(i['type_name'], 'instance') nt.assert_equal(i['docstring'], OldStyle.__doc__) +def test_class_signature(): + info = inspector.info(HasSignature, 'HasSignature') + nt.assert_equal(info['init_definition'], "HasSignature(test)\n") + nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__) + def test_info_awkward(): # Just test that this doesn't throw an error. i = inspector.info(Awkward()) From 27db08e7343ed8173c134f63ba3d413f31aa53dd Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 20 Mar 2016 13:46:40 +0000 Subject: [PATCH 0228/4859] Catch ValueError when filling readline history, and warn Closes gh-9329 --- IPython/terminal/interactiveshell.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index aa4a2602615..85f17af14b1 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -482,10 +482,12 @@ def refill_readline_hist(self): stdin_encoding)) last_cell = cell - except TypeError: + except (TypeError, ValueError) as e: # The history DB can get corrupted so it returns strings # containing null bytes, which readline objects to. - continue + warn(("Failed to add string to readline history.\n" + "Error: {}\n" + "Cell: {!r}").format(e, cell)) #------------------------------------------------------------------------- # Things related to the terminal From 1bafcb71dd74d3219a099fc9dcb871ea926d2c8a Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 21 Mar 2016 10:53:19 +0100 Subject: [PATCH 0229/4859] handle None for init_def --- IPython/core/oinspect.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 86e45eee141..52b701e3d7f 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -766,21 +766,22 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): if inspect.isclass(obj): out['isclass'] = True - # get the function signature: + # get the init signature: try: init_def = self._getdef(obj, oname) except AttributeError: init_def = None - else: + + if init_def: out['init_definition'] = self.format(init_def) # get the __init__ docstring try: obj_init = obj.__init__ except AttributeError: - init_def = init_ds = None + init_ds = None else: - init_ds = getdoc(obj_init) + init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None From 238ed9b8a473e6dbb0f515b8da7787bb7d0543f5 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 21 Mar 2016 10:54:33 +0100 Subject: [PATCH 0230/4859] python2 init signatures include self --- IPython/core/tests/test_oinspect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index e75c9da6d1e..ebb18026d8c 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -281,7 +281,8 @@ def test_info(): nt.assert_equal(i['docstring'], Call.__doc__) nt.assert_equal(i['source'], None) nt.assert_true(i['isclass']) - nt.assert_equal(i['init_definition'], "Call(x, y=1)\n") + _self_py2 = '' if py3compat.PY3 else 'self, ' + nt.assert_equal(i['init_definition'], "Call(%sx, y=1)\n" % _self_py2) nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) i = inspector.info(Call, detail_level=1) From d672c0ca9c6a2da6df57bcdc4685bf4e5d05ef1e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 22 Mar 2016 12:17:13 -0700 Subject: [PATCH 0231/4859] 'remove reference to install_ext' --- examples/IPython Kernel/Beyond Plain Python.ipynb | 3 +-- examples/IPython Kernel/Cell Magics.ipynb | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/IPython Kernel/Beyond Plain Python.ipynb b/examples/IPython Kernel/Beyond Plain Python.ipynb index b0ac28b4225..ec24fc6a974 100644 --- a/examples/IPython Kernel/Beyond Plain Python.ipynb +++ b/examples/IPython Kernel/Beyond Plain Python.ipynb @@ -888,7 +888,6 @@ "hist": "Other", "history": "HistoryMagics", "install_default_config": "DeprecatedMagics", - "install_ext": "ExtensionMagics", "install_profiles": "DeprecatedMagics", "killbgscripts": "ScriptMagics", "ldir": "Other", @@ -969,7 +968,7 @@ }, "text/plain": [ "Available line magics:\n", - "%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_config %install_ext %install_profiles %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %namespace %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %tic %time %timeit %toc %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n", + "%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_config %install_profiles %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %namespace %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %tic %time %timeit %toc %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n", "\n", "Available cell magics:\n", "%%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%latex %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile\n", diff --git a/examples/IPython Kernel/Cell Magics.ipynb b/examples/IPython Kernel/Cell Magics.ipynb index 9cc2c4b8e45..e9be41f5977 100644 --- a/examples/IPython Kernel/Cell Magics.ipynb +++ b/examples/IPython Kernel/Cell Magics.ipynb @@ -83,7 +83,6 @@ "hist": "Other", "history": "HistoryMagics", "install_default_config": "DeprecatedMagics", - "install_ext": "ExtensionMagics", "install_profiles": "DeprecatedMagics", "killbgscripts": "ScriptMagics", "ldir": "Other", @@ -161,7 +160,7 @@ }, "text/plain": [ "Available line magics:\n", - "%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_config %install_ext %install_profiles %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n", + "%alias %alias_magic %autocall %automagic %autosave %bookmark %cat %cd %clear %colors %config %connect_info %cp %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_config %install_profiles %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %qtconsole %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode\n", "\n", "Available cell magics:\n", "%%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%latex %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile\n", From 491f78817d33dec4fd1ddce70832b4e4c3107a33 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 23 Mar 2016 09:12:08 -0700 Subject: [PATCH 0232/4859] 'Update install instructions' --- docs/source/install/install.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index f119380c038..249aaa59254 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -81,7 +81,7 @@ grab the latest stable tarball of IPython `from PyPI $ tar -xzf ipython.tar.gz $ cd ipython - $ python setup.py install + $ pip install . 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`. @@ -96,9 +96,9 @@ need to have Git installed on your system. Then do: .. code-block:: bash - $ git clone --recursive https://github.com/ipython/ipython.git + $ git clone https://github.com/ipython/ipython.git $ cd ipython - $ python setup.py install + $ pip install . Some users want to be able to follow the development branch as it changes. If you have :mod:`pip`, you can replace the last step by: From f892472971a197a0e953a751e90385b79865451a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 23 Mar 2016 17:31:28 +0000 Subject: [PATCH 0233/4859] Inherit history machinery from LoggingConfigurable HistoryManager uses log (in an error case, which is why we didn't spot it before). Closes gh-9351 --- IPython/core/history.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/history.py b/IPython/core/history.py index 5272ab7f9bb..fc79642ea90 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -27,7 +27,7 @@ import threading # Our own packages -from traitlets.config.configurable import Configurable +from traitlets.config.configurable import LoggingConfigurable from decorator import decorator from IPython.utils.decorators import undoc from IPython.utils.path import locate_profile @@ -103,7 +103,7 @@ def catch_corrupt_db(f, self, *a, **kw): # The hist_file is probably :memory: or something else. raise -class HistoryAccessorBase(Configurable): +class HistoryAccessorBase(LoggingConfigurable): """An abstract class for History Accessors """ def get_tail(self, n=10, raw=True, output=False, include_latest=False): From 9dc4583254891bfa580aba7ada35255ce0718b25 Mon Sep 17 00:00:00 2001 From: Trevor Bekolay Date: Thu, 24 Mar 2016 17:51:46 -0400 Subject: [PATCH 0234/4859] Add test for disabling history manager --- IPython/core/tests/test_history.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/IPython/core/tests/test_history.py b/IPython/core/tests/test_history.py index bf8ab69a914..e4496d27a0f 100644 --- a/IPython/core/tests/test_history.py +++ b/IPython/core/tests/test_history.py @@ -186,3 +186,26 @@ def test_hist_file_config(): # delete it. I have no clue why pass +def test_histmanager_disabled(): + """Ensure that disabling the history manager doesn't create a database.""" + cfg = Config() + cfg.HistoryAccessor.enabled = False + + ip = get_ipython() + with TemporaryDirectory() as tmpdir: + hist_manager_ori = ip.history_manager + hist_file = os.path.join(tmpdir, 'history.sqlite') + cfg.HistoryManager.hist_file = hist_file + try: + ip.history_manager = HistoryManager(shell=ip, config=cfg) + hist = [u'a=1', u'def f():\n test = 1\n return test', u"b='€Æ¾÷ß'"] + for i, h in enumerate(hist, start=1): + ip.history_manager.store_inputs(i, h) + nt.assert_equal(ip.history_manager.input_hist_raw, [''] + hist) + ip.history_manager.reset() + ip.history_manager.end_session() + finally: + ip.history_manager = hist_manager_ori + + # hist_file should not be created + nt.assert_false(os.path.exists(hist_file)) From ce499a7d3e3016216bda1e91bcdeea93747e41d8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 27 Mar 2016 02:02:33 +0100 Subject: [PATCH 0235/4859] Add and use confirm_exit flag in prompt_toolkit shell Closes gh-9359 --- IPython/terminal/ptshell.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3e5216098c5..e9f4f6c541b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -8,7 +8,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 +from traitlets import Bool, CBool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER @@ -54,6 +54,12 @@ class TerminalInteractiveShell(InteractiveShell): pt_cli = None + confirm_exit = CBool(True, config=True, + help=""" + Set to confirm when you try to exit IPython with an EOF (Control-D + in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', + you can force a direct exit without any confirmation.""", + ) vi_mode = Bool(False, config=True, help="Use vi style keybindings at the prompt", ) @@ -257,7 +263,8 @@ def interact(self): try: code = self.prompt_for_code() except EOFError: - if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): + if (not self.confirm_exit) \ + or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): self.ask_exit() else: From ec77810376a51fbaf684771dc76d1c4e714d3fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6khan=20Karabulut?= Date: Mon, 28 Mar 2016 13:50:52 +0300 Subject: [PATCH 0236/4859] Fix a typo: plot_to_latex -> poly_to_latex It seems it is `poly_to_latex` function to be registered, not `plot_to_latex` --- examples/IPython Kernel/Custom Display Logic.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/IPython Kernel/Custom Display Logic.ipynb b/examples/IPython Kernel/Custom Display Logic.ipynb index aed4f2708ab..40d58baf7f8 100644 --- a/examples/IPython Kernel/Custom Display Logic.ipynb +++ b/examples/IPython Kernel/Custom Display Logic.ipynb @@ -1214,7 +1214,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "However, you can configure IPython to do this automatically by registering the `Polynomial` class and the `plot_to_latex` function with an IPython display formatter. Let's look at the default formatters provided by IPython:" + "However, you can configure IPython to do this automatically by registering the `Polynomial` class and the `poly_to_latex` function with an IPython display formatter. Let's look at the default formatters provided by IPython:" ] }, { From bcd13d71f7e3cbd6c0adba8bd32e2ace3fde9c9a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 28 Mar 2016 16:06:56 -0700 Subject: [PATCH 0237/4859] Show UsageError exception immediately Closes gh-9361 --- IPython/core/interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 357098ea04a..a78163c0733 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1771,7 +1771,7 @@ def show_usage_error(self, exc): These are special exceptions that shouldn't show a traceback. """ - self.write_err("UsageError: %s" % exc) + print("UsageError: %s" % exc, file=sys.stderr) def get_exception_only(self, exc_tuple=None): """ From f9a281d8fa066976849b0a9845e280dd4e0c5f57 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 29 Mar 2016 17:24:45 -0700 Subject: [PATCH 0238/4859] Deprecate io.{stdout,stderr} and shell.{write,write_err} I believe there is no longer any reason to use these --- IPython/core/debugger.py | 8 ++--- IPython/core/display.py | 10 +++--- IPython/core/displayhook.py | 11 +++---- IPython/core/displaypub.py | 13 ++++---- IPython/core/interactiveshell.py | 34 ++++++++++++--------- IPython/core/magics/history.py | 3 +- IPython/core/oinspect.py | 3 +- IPython/core/page.py | 15 +++++---- IPython/core/tests/test_interactiveshell.py | 30 +++++------------- IPython/core/ultratb.py | 3 +- IPython/lib/demo.py | 26 ++++++++-------- IPython/utils/io.py | 8 ++++- IPython/utils/warn.py | 7 ++--- 13 files changed, 81 insertions(+), 90 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 39abf9b12d4..0f0c78a81fc 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -33,7 +33,7 @@ from IPython import get_ipython from IPython.utils import PyColorize, ulinecache -from IPython.utils import coloransi, io, py3compat +from IPython.utils import coloransi, py3compat from IPython.core.excolors import exception_colors from IPython.testing.skipdoctest import skip_doctest @@ -221,7 +221,7 @@ def __init__(self,color_scheme='NoColor',completekey=None, raise ValueError("Context must be a positive integer") if has_pydb and completekey is None: - OldPdb.__init__(self,stdin=stdin,stdout=io.stdout) + OldPdb.__init__(self,stdin=stdin,stdout=sys.stdout) else: OldPdb.__init__(self,completekey,stdin,stdout) @@ -369,7 +369,7 @@ def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ', raise ValueError("Context must be a positive integer") except (TypeError, ValueError): raise ValueError("Context must be a positive integer") - print(self.format_stack_entry(frame_lineno, '', context), file=io.stdout) + print(self.format_stack_entry(frame_lineno, '', context)) # vds: >> frame, lineno = frame_lineno @@ -513,7 +513,7 @@ def print_list_lines(self, filename, first, last): src.append(line) self.lineno = lineno - print(''.join(src), file=io.stdout) + print(''.join(src)) except KeyboardInterrupt: pass diff --git a/IPython/core/display.py b/IPython/core/display.py index 458526a41f8..1db5d8ae73d 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -15,6 +15,7 @@ import mimetypes import os import struct +import sys import warnings from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode, @@ -938,11 +939,10 @@ def clear_output(wait=False): if InteractiveShell.initialized(): InteractiveShell.instance().display_pub.clear_output(wait) else: - from IPython.utils import io - print('\033[2K\r', file=io.stdout, end='') - io.stdout.flush() - print('\033[2K\r', file=io.stderr, end='') - io.stderr.flush() + print('\033[2K\r', end='') + sys.stdout.flush() + print('\033[2K\r', end='') + sys.stderr.flush() @skip_doctest diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 4d174085345..269ae1820b6 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -14,7 +14,6 @@ import tokenize from traitlets.config.configurable import Configurable -from IPython.utils import io from IPython.utils.py3compat import builtin_mod, cast_unicode_py2 from traitlets import Instance, Float from warnings import warn @@ -113,10 +112,10 @@ def write_output_prompt(self): ``io.stdout``. """ # Use write, not print which adds an extra space. - io.stdout.write(self.shell.separate_out) + sys.stdout.write(self.shell.separate_out) outprompt = self.shell.prompt_manager.render('out') if self.do_full_cache: - io.stdout.write(outprompt) + sys.stdout.write(outprompt) def compute_format_data(self, result): """Compute format data of the object to be displayed. @@ -185,7 +184,7 @@ def write_format_data(self, format_dict, md_dict=None): # But avoid extraneous empty lines. result_repr = '\n' + result_repr - print(result_repr, file=io.stdout) + print(result_repr) def update_user_ns(self, result): """Update user_ns with various things like _, __, _1, etc.""" @@ -229,8 +228,8 @@ def log_output(self, format_dict): def finish_displayhook(self): """Finish up all displayhook activities.""" - io.stdout.write(self.shell.separate_out2) - io.stdout.flush() + sys.stdout.write(self.shell.separate_out2) + sys.stdout.flush() def __call__(self, result=None): """Printing with history cache management. diff --git a/IPython/core/displaypub.py b/IPython/core/displaypub.py index 0fe03982973..0269b7585d6 100644 --- a/IPython/core/displaypub.py +++ b/IPython/core/displaypub.py @@ -17,8 +17,9 @@ from __future__ import print_function +import sys + from traitlets.config.configurable import Configurable -from IPython.utils import io from traitlets import List # This used to be defined here - it is imported for backwards compatibility @@ -92,14 +93,14 @@ def publish(self, data, metadata=None, source=None): # The default is to simply write the plain text data using io.stdout. if 'text/plain' in data: - print(data['text/plain'], file=io.stdout) + print(data['text/plain']) def clear_output(self, wait=False): """Clear the output of the cell receiving output.""" - print('\033[2K\r', file=io.stdout, end='') - io.stdout.flush() - print('\033[2K\r', file=io.stderr, end='') - io.stderr.flush() + print('\033[2K\r', end='') + sys.stdout.flush() + print('\033[2K\r', end='') + sys.stderr.flush() class CapturingDisplayPublisher(DisplayPublisher): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a78163c0733..738f1d4b86c 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1697,11 +1697,11 @@ def wrapped(self,etype,value,tb,tb_offset=None): except: # clear custom handler immediately self.set_custom_exc((), None) - print("Custom TB Handler failed, unregistering", file=io.stderr) + print("Custom TB Handler failed, unregistering", file=sys.stderr) # show the exception in handler first stb = self.InteractiveTB.structured_traceback(*sys.exc_info()) - print(self.InteractiveTB.stb2text(stb), file=io.stdout) - print("The original exception:", file=io.stdout) + print(self.InteractiveTB.stb2text(stb)) + print("The original exception:") stb = self.InteractiveTB.structured_traceback( (etype,value,tb), tb_offset=tb_offset ) @@ -1799,7 +1799,7 @@ def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None, try: etype, value, tb = self._get_exc_info(exc_tuple) except ValueError: - self.write_err('No traceback available to show.\n') + print('No traceback available to show.', file=sys.stderr) return if issubclass(etype, SyntaxError): @@ -1834,7 +1834,7 @@ def showtraceback(self, exc_tuple=None, filename=None, tb_offset=None, self._showtraceback(etype, value, stb) except KeyboardInterrupt: - self.write_err('\n' + self.get_exception_only()) + print('\n' + self.get_exception_only(), file=sys.stderr) def _showtraceback(self, etype, evalue, stb): """Actually show a traceback. @@ -1842,7 +1842,7 @@ def _showtraceback(self, etype, evalue, stb): Subclasses may override this method to put the traceback on a different place, like a side channel. """ - print(self.InteractiveTB.stb2text(stb), file=io.stdout) + print(self.InteractiveTB.stb2text(stb)) def showsyntaxerror(self, filename=None): """Display the syntax error that just occurred. @@ -2228,7 +2228,7 @@ def system_raw(self, cmd): try: ec = os.system(cmd) except KeyboardInterrupt: - self.write_err('\n' + self.get_exception_only()) + print('\n' + self.get_exception_only(), file=sys.stderr) ec = -2 else: cmd = py3compat.unicode_to_str(cmd) @@ -2247,7 +2247,7 @@ def system_raw(self, cmd): ec = subprocess.call(cmd, shell=True, executable=executable) except KeyboardInterrupt: # intercept control-C; a long traceback is not useful here - self.write_err('\n' + self.get_exception_only()) + print('\n' + self.get_exception_only(), file=sys.stderr) ec = 130 if ec > 128: ec = -(ec - 128) @@ -2351,7 +2351,7 @@ def auto_rewrite_input(self, cmd): # plain ascii works better w/ pyreadline, on some machines, so # we use it and only print uncolored rewrite if we have unicode rw = str(rw) - print(rw, file=io.stdout) + print(rw) except UnicodeEncodeError: print("------> " + cmd) @@ -3056,15 +3056,19 @@ def mktempfile(self, data=None, prefix='ipython_edit_'): tmp_file.close() return filename - # TODO: This should be removed when Term is refactored. + @undoc def write(self,data): - """Write a string to the default output""" - io.stdout.write(data) + """DEPRECATED: Write a string to the default output""" + warn('InteractiveShell.write() is deprecated, use sys.stdout instead', + DeprecationWarning, stacklevel=2) + sys.stdout.write(data) - # TODO: This should be removed when Term is refactored. + @undoc def write_err(self,data): - """Write a string to the default error output""" - io.stderr.write(data) + """DEPRECATED: Write a string to the default error output""" + warn('InteractiveShell.write_err() is deprecated, use sys.stderr instead', + DeprecationWarning, stacklevel=2) + sys.stderr.write(data) def ask_yes_no(self, prompt, default=None, interrupt=None): if self.quiet: diff --git a/IPython/core/magics/history.py b/IPython/core/magics/history.py index c21fa2f4e68..5967591394a 100644 --- a/IPython/core/magics/history.py +++ b/IPython/core/magics/history.py @@ -15,6 +15,7 @@ # Stdlib import os +import sys from io import open as io_open # Our own packages @@ -147,7 +148,7 @@ def _format_lineno(session, line): # Check if output to specific file was requested. outfname = args.filename if not outfname: - outfile = io.stdout # default + outfile = sys.stdout # default # We don't want to close stdout at the end! close_at_end = False else: diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 52b701e3d7f..d1a122e1bef 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -32,7 +32,6 @@ from IPython.lib.pretty import pretty from IPython.testing.skipdoctest import skip_doctest_py3 from IPython.utils import PyColorize -from IPython.utils import io from IPython.utils import openpy from IPython.utils import py3compat from IPython.utils.dir2 import safe_hasattr @@ -427,7 +426,7 @@ def pdef(self, obj, oname=''): if output is None: self.noinfo('definition header',oname) else: - print(header,self.format(output), end=' ', file=io.stdout) + print(header,self.format(output), end=' ') # In Python 3, all classes are new-style, so they all have __init__. @skip_doctest_py3 diff --git a/IPython/core/page.py b/IPython/core/page.py index 4b29faaf5f3..b3f06e618bf 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -26,7 +26,6 @@ from IPython.core.display import display from IPython.core.error import TryNext from IPython.utils.data import chop -from IPython.utils import io from IPython.utils.process import system from IPython.utils.terminal import get_terminal_size from IPython.utils import py3compat @@ -62,18 +61,18 @@ def page_dumb(strng, start=0, screen_lines=25): out_ln = strng.splitlines()[start:] screens = chop(out_ln,screen_lines-1) if len(screens) == 1: - print(os.linesep.join(screens[0]), file=io.stdout) + print(os.linesep.join(screens[0])) else: last_escape = "" for scr in screens[0:-1]: hunk = os.linesep.join(scr) - print(last_escape + hunk, file=io.stdout) + print(last_escape + hunk) if not page_more(): return esc_list = esc_re.findall(hunk) if len(esc_list) > 0: last_escape = esc_list[-1] - print(last_escape + os.linesep.join(screens[-1]), file=io.stdout) + print(last_escape + os.linesep.join(screens[-1])) def _detect_screen_size(screen_lines_def): """Attempt to work out the number of lines on the screen. @@ -191,13 +190,13 @@ def pager_page(strng, start=0, screen_lines=0, pager_cmd=None): try: screen_lines += _detect_screen_size(screen_lines_def) except (TypeError, UnsupportedOperation): - print(str_toprint, file=io.stdout) + print(str_toprint) return #print 'numlines',numlines,'screenlines',screen_lines # dbg if numlines <= screen_lines : #print '*** normal print' # dbg - print(str_toprint, file=io.stdout) + print(str_toprint) else: # Try to open pager and default to internal one if that fails. # All failure modes are tagged as 'retval=1', to match the return @@ -339,13 +338,13 @@ def page_more(): @return: True if need print more lines, False if quit """ - io.stdout.write('---Return to continue, q to quit--- ') + sys.stdout.write('---Return to continue, q to quit--- ') ans = msvcrt.getwch() if ans in ("q", "Q"): result = False else: result = True - io.stdout.write("\b"*37 + " "*37 + "\b"*37) + sys.stdout.write("\b"*37 + " "*37 + "\b"*37) return result else: def page_more(): diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index adc9cf05609..11164d47a5b 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -196,33 +196,19 @@ def test_global_ns(self): def test_bad_custom_tb(self): """Check that InteractiveShell is protected from bad custom exception handlers""" - from IPython.utils import io - save_stderr = io.stderr - try: - # capture stderr - io.stderr = StringIO() - ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0) - self.assertEqual(ip.custom_exceptions, (IOError,)) + ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0) + self.assertEqual(ip.custom_exceptions, (IOError,)) + with tt.AssertPrints("Custom TB Handler failed", channel='stderr'): ip.run_cell(u'raise IOError("foo")') - self.assertEqual(ip.custom_exceptions, ()) - self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue()) - finally: - io.stderr = save_stderr + self.assertEqual(ip.custom_exceptions, ()) def test_bad_custom_tb_return(self): """Check that InteractiveShell is protected from bad return types in custom exception handlers""" - from IPython.utils import io - save_stderr = io.stderr - try: - # capture stderr - io.stderr = StringIO() - ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1) - self.assertEqual(ip.custom_exceptions, (NameError,)) + ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1) + self.assertEqual(ip.custom_exceptions, (NameError,)) + with tt.AssertPrints("Custom TB Handler failed", channel='stderr'): ip.run_cell(u'a=abracadabra') - self.assertEqual(ip.custom_exceptions, ()) - self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue()) - finally: - io.stderr = save_stderr + self.assertEqual(ip.custom_exceptions, ()) def test_drop_by_id(self): myvars = {"a":object(), "b":object(), "c": object()} diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 8c4a8fc14ef..b41bf4ecff4 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -118,7 +118,6 @@ from IPython.core.display_trap import DisplayTrap from IPython.core.excolors import exception_colors from IPython.utils import PyColorize -from IPython.utils import io from IPython.utils import openpy from IPython.utils import path as util_path from IPython.utils import py3compat @@ -523,7 +522,7 @@ def _get_ostream(self): - Any object with 'write' and 'flush' attributes. """ - return io.stdout if self._ostream is None else self._ostream + return sys.stdout if self._ostream is None else self._ostream def _set_ostream(self, val): assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush')) diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index 435670dfaa0..3066722670c 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -326,7 +326,7 @@ def _get_index(self,index): if index is None: if self.finished: - print('Demo finished. Use .reset() if you want to rerun it.', file=io.stdout) + print('Demo finished. Use .reset() if you want to rerun it.') return None index = self.block_index else: @@ -397,8 +397,8 @@ def show(self,index=None): return print(self.marquee('<%s> block # %s (%s remaining)' % - (self.title,index,self.nblocks-index-1)), file=io.stdout) - print(self.src_blocks_colored[index], file=io.stdout) + (self.title,index,self.nblocks-index-1))) + print(self.src_blocks_colored[index]) sys.stdout.flush() def show_all(self): @@ -412,11 +412,11 @@ def show_all(self): for index,block in enumerate(self.src_blocks_colored): if silent[index]: print(marquee('<%s> SILENT block # %s (%s remaining)' % - (title,index,nblocks-index-1)), file=io.stdout) + (title,index,nblocks-index-1))) else: print(marquee('<%s> block # %s (%s remaining)' % - (title,index,nblocks-index-1)), file=io.stdout) - print(block, end=' ', file=io.stdout) + (title,index,nblocks-index-1))) + print(block, end=' ') sys.stdout.flush() def run_cell(self,source): @@ -442,17 +442,17 @@ def __call__(self,index=None): self.block_index += 1 if self._silent[index]: print(marquee('Executing silent block # %s (%s remaining)' % - (index,self.nblocks-index-1)), file=io.stdout) + (index,self.nblocks-index-1))) else: self.pre_cmd() self.show(index) if self.auto_all or self._auto[index]: - print(marquee('output:'), file=io.stdout) + print(marquee('output:')) else: - print(marquee('Press to quit, to execute...'), end=' ', file=io.stdout) + print(marquee('Press to quit, to execute...'), end=' ') ans = py3compat.input().strip() if ans: - print(marquee('Block NOT executed'), file=io.stdout) + print(marquee('Block NOT executed')) return try: save_argv = sys.argv @@ -471,9 +471,9 @@ def __call__(self,index=None): mq1 = self.marquee('END OF DEMO') if mq1: # avoid spurious print >>io.stdout,s if empty marquees are used - print(file=io.stdout) - print(mq1, file=io.stdout) - print(self.marquee('Use .reset() if you want to rerun it.'), file=io.stdout) + print() + print(mq1) + print(self.marquee('Use .reset() if you want to rerun it.')) self.finished = True # These methods are meant to be overridden by subclasses who may wish to diff --git a/IPython/utils/io.py b/IPython/utils/io.py index 2ba3fd5d023..826e3b2f237 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -15,10 +15,12 @@ import sys import tempfile from warnings import warn + +from IPython.utils.decorators import undoc from .capture import CapturedIO, capture_output from .py3compat import string_types, input, PY3 - +@undoc class IOStream: def __init__(self,stream, fallback=None): @@ -42,6 +44,8 @@ def __repr__(self): return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream) def write(self,data): + warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead', + DeprecationWarning, stacklevel=2) try: self._swrite(data) except: @@ -56,6 +60,8 @@ def write(self,data): file=sys.stderr) def writelines(self, lines): + warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead', + DeprecationWarning, stacklevel=2) if isinstance(lines, string_types): lines = [lines] for line in lines: diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index bb610ac3824..eee175bf41e 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -9,9 +9,6 @@ from __future__ import print_function import sys - -from IPython.utils import io - import warnings warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) @@ -36,9 +33,9 @@ def warn(msg,level=2,exit_val=1): warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) if level>0: header = ['','','WARNING: ','ERROR: ','FATAL ERROR: '] - print(header[level], msg, sep='', file=io.stderr) + print(header[level], msg, sep='', file=sys.stderr) if level == 4: - print('Exiting.\n', file=io.stderr) + print('Exiting.\n', file=sys.stderr) sys.exit(exit_val) From 8b3df6bb068db44c815747adee99b760eaee4a74 Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Fri, 1 Apr 2016 19:49:42 +0200 Subject: [PATCH 0239/4859] ControlZ should suspend IPython to the background. --- IPython/terminal/ptshell.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3e5216098c5..e7a8f476b8d 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -3,6 +3,7 @@ import os import sys +import signal from IPython.core.interactiveshell import InteractiveShell from IPython.utils.py3compat import PY3, cast_unicode_py2, input @@ -136,6 +137,12 @@ def _(event): def _(event): event.current_buffer.reset() + supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) + + @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) + def _(event): + event.cli.suspend_to_background() + @Condition def cursor_in_leading_ws(cli): before = cli.application.buffer.document.current_line_before_cursor From ccd17de55762933e90992e15a583bf8975eb774b Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Fri, 1 Apr 2016 19:54:34 +0200 Subject: [PATCH 0240/4859] Upgrade to at least prompt-toolkit 0.60 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 905b2b01e11..b9eb698db33 100755 --- a/setup.py +++ b/setup.py @@ -195,7 +195,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets', - 'prompt_toolkit>=0.58', + 'prompt_toolkit>=0.60', 'pygments', 'backports.shutil_get_terminal_size', ] From ca62107d0ceff5eb3765405fad2a399bd21ff668 Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Fri, 1 Apr 2016 19:58:58 +0200 Subject: [PATCH 0241/4859] Specify reserve_space_for_menu in create_prompt_application. --- IPython/terminal/ptshell.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3e5216098c5..7251d5cc3b7 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -194,6 +194,7 @@ def _(event): enable_history_search=True, style=style, mouse_support=self.mouse_support, + reserve_space_for_menu=6, ) self.pt_cli = CommandLineInterface(app, From 535591906b08c5a6ed94a33f954e5778b24e10cc Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Fri, 1 Apr 2016 20:12:06 +0200 Subject: [PATCH 0242/4859] Created IPythonPTLexer, which is a wrapper around BashLexer and PythonLexer. (When the input starts with an exclamation mark, use the BashLexer.) --- IPython/terminal/ptshell.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3e5216098c5..9a4e8eec3ae 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -20,11 +20,12 @@ from prompt_toolkit.key_binding.vi_state import InputMode from prompt_toolkit.key_binding.bindings.vi import ViStateFilter from prompt_toolkit.keys import Keys +from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer from prompt_toolkit.styles import PygmentsStyle from pygments.styles import get_style_by_name -from pygments.lexers import Python3Lexer, PythonLexer +from pygments.lexers import Python3Lexer, BashLexer, PythonLexer from pygments.token import Token from .pt_inputhooks import get_inputhook_func @@ -49,6 +50,22 @@ def get_completions(self, document, complete_event): for m in matches: yield Completion(m, start_position=start_pos) + +class IPythonPTLexer(Lexer): + """ + Wrapper around PythonLexer and BashLexer. + """ + def __init__(self): + self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer) + self.shell_lexer = PygmentsLexer(BashLexer) + + def lex_document(self, cli, document): + if document.text.startswith('!'): + return self.shell_lexer.lex_document(cli, document) + else: + return self.python_lexer.lex_document(cli, document) + + class TerminalInteractiveShell(InteractiveShell): colors_force = True @@ -185,7 +202,7 @@ def _(event): style_dict=style_overrides) app = create_prompt_application(multiline=True, - lexer=PygmentsLexer(Python3Lexer if PY3 else PythonLexer), + lexer=IPythonPTLexer(), get_prompt_tokens=self.get_prompt_tokens, get_continuation_tokens=self.get_continuation_tokens, key_bindings_registry=kbmanager.registry, From 9b5a293025d16868b88ad558070af349f3d9e841 Mon Sep 17 00:00:00 2001 From: Jonas Rauber Date: Mon, 4 Apr 2016 11:52:08 +0200 Subject: [PATCH 0243/4859] tiny documentation fix --- IPython/lib/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/lib/display.py b/IPython/lib/display.py index b0176ff47c0..63da80fb916 100644 --- a/IPython/lib/display.py +++ b/IPython/lib/display.py @@ -41,7 +41,7 @@ class Audio(DisplayObject): filename : unicode Path to a local file to load the data from. embed : boolean - Should the image data be embedded using a data URI (True) or should + Should the audio data be embedded using a data URI (True) or should the original source be referenced. Set this to True if you want the audio to playable later with no internet connection in the notebook. From 93f7b42ab5feddb3e00743722d3a66274eef276b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 4 Apr 2016 10:39:33 -0700 Subject: [PATCH 0244/4859] Restore option to auto-edit files on syntax error --- IPython/core/ultratb.py | 1 + IPython/terminal/ptshell.py | 69 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index b41bf4ecff4..f56ee615bd8 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -1432,6 +1432,7 @@ def structured_traceback(self, etype, value, elist, tb_offset=None, newtext = ulinecache.getline(value.filename, value.lineno) if newtext: value.text = newtext + self.last_syntax_error = value return super(SyntaxTB, self).structured_traceback(etype, value, elist, tb_offset=tb_offset, context=context) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 1a38806c4a6..3a5b1a324e0 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -4,7 +4,9 @@ import os import sys import signal +from warnings import warn +from IPython.core.error import TryNext from IPython.core.interactiveshell import InteractiveShell from IPython.utils.py3compat import PY3, cast_unicode_py2, input from IPython.utils.terminal import toggle_set_term_title, set_term_title @@ -72,6 +74,9 @@ class TerminalInteractiveShell(InteractiveShell): pt_cli = None + autoedit_syntax = CBool(False, config=True, + help="auto editing of files with syntax errors.") + confirm_exit = CBool(True, config=True, help=""" Set to confirm when you try to exit IPython with an EOF (Control-D @@ -295,6 +300,8 @@ def interact(self): else: if code: self.run_cell(code, store_history=True) + if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: + self.edit_syntax_error() def mainloop(self): # An extra layer of protection in case someone mashing Ctrl-C breaks @@ -317,5 +324,67 @@ def enable_gui(self, gui=None): else: self._inputhook = None + # Methods to support auto-editing of SyntaxErrors: + + def edit_syntax_error(self): + """The bottom half of the syntax error handler called in the main loop. + + Loop until syntax error is fixed or user cancels. + """ + + while self.SyntaxTB.last_syntax_error: + # copy and clear last_syntax_error + err = self.SyntaxTB.clear_err_state() + if not self._should_recompile(err): + return + try: + # may set last_syntax_error again if a SyntaxError is raised + self.safe_execfile(err.filename, self.user_ns) + except: + self.showtraceback() + else: + try: + f = open(err.filename) + try: + # This should be inside a display_trap block and I + # think it is. + sys.displayhook(f.read()) + finally: + f.close() + except: + self.showtraceback() + + def _should_recompile(self, e): + """Utility routine for edit_syntax_error""" + + if e.filename in ('', '', '', + '', '', + None): + return False + try: + if (self.autoedit_syntax and + not self.ask_yes_no( + 'Return to editor to correct syntax error? ' + '[Y/n] ', 'y')): + return False + except EOFError: + return False + + def int0(x): + try: + return int(x) + except TypeError: + return 0 + + # always pass integer line and offset values to editor hook + try: + self.hooks.fix_error_editor(e.filename, + int0(e.lineno), int0(e.offset), + e.msg) + except TryNext: + warn('Could not open editor') + return False + return True + if __name__ == '__main__': TerminalInteractiveShell.instance().interact() From 1932dc8078323a2793d2d9e5c3a4bc7af80747e3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 4 Apr 2016 11:00:17 -0700 Subject: [PATCH 0245/4859] Simplify code with a context manager --- IPython/terminal/ptshell.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3a5b1a324e0..0383b4ef12c 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -344,13 +344,10 @@ def edit_syntax_error(self): self.showtraceback() else: try: - f = open(err.filename) - try: + with open(err.filename) as f: # This should be inside a display_trap block and I # think it is. sys.displayhook(f.read()) - finally: - f.close() except: self.showtraceback() From 7844f106d9d72e3418ac63a964cd00207382c55f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 4 Apr 2016 14:04:39 -0700 Subject: [PATCH 0246/4859] 'remove unused import' --- IPython/testing/plugin/ipdoctest.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/IPython/testing/plugin/ipdoctest.py b/IPython/testing/plugin/ipdoctest.py index baebc8bcb4f..bc750e0efd1 100644 --- a/IPython/testing/plugin/ipdoctest.py +++ b/IPython/testing/plugin/ipdoctest.py @@ -25,8 +25,6 @@ import os import re import sys -import traceback -import unittest from testpath import modified_env @@ -41,10 +39,9 @@ linecache) # Third-party modules -import nose.core from nose.plugins import doctests, Plugin -from nose.util import anyp, getpackage, test_address, resolve_name, tolist +from nose.util import anyp, tolist # Our own imports from IPython.utils.py3compat import builtin_mod, PY3, getcwd @@ -143,7 +140,7 @@ def _find(self, tests, obj, name, module, source_lines, globs, seen): # doctests in extension modules. # Local shorthands - from inspect import isroutine, isclass, ismodule + from inspect import isroutine, isclass # Look for tests in a module's contained objects. if inspect.ismodule(obj) and self._recurse: From e0b3f110803ba16d9bacc1e37659f2e2a8f24ebd Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Wed, 6 Apr 2016 22:31:38 +0200 Subject: [PATCH 0247/4859] Bugfix: when doing \dot completion. Compose unicode character from completion. --- IPython/terminal/ptshell.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 0383b4ef12c..114aac80329 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -4,7 +4,9 @@ import os import sys import signal +import unicodedata from warnings import warn +from wcwidth import wcwidth from IPython.core.error import TryNext from IPython.core.interactiveshell import InteractiveShell @@ -35,7 +37,6 @@ from .interactiveshell import get_default_editor, TerminalMagics - class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" def __init__(self, ipy_completer): @@ -51,6 +52,22 @@ def get_completions(self, document, complete_event): ) start_pos = -len(used) for m in matches: + m = unicodedata.normalize('NFC', m) + + # When the first character of the completion has a zero length, + # then it's probably a decomposed unicode character. E.g. caused by + # the "\dot" completion. Try to compose again with the previous + # character. + if wcwidth(m[0]) == 0: + if document.cursor_position + start_pos > 0: + char_before = document.text[document.cursor_position + start_pos - 1] + m = unicodedata.normalize('NFC', char_before + m) + + # Yield the modified completion instead, if this worked. + if wcwidth(m[0:1]) == 1: + yield Completion(m, start_position=start_pos - 1) + continue + yield Completion(m, start_position=start_pos) From 31bf5e8bb3faf93b88df1022383e50bceb8fc100 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 7 Apr 2016 18:10:49 -0700 Subject: [PATCH 0248/4859] Switch embedded IPython over to prompt_toolkit shell Manually tested with the checks in tools/tests/embed/ --- IPython/terminal/embed.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 85dc9d1cb36..f78aa2aba60 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -15,7 +15,7 @@ from IPython.core.magic import Magics, magics_class, line_magic from IPython.core.interactiveshell import DummyMod from IPython.core.interactiveshell import InteractiveShell -from IPython.terminal.interactiveshell import TerminalInteractiveShell +from IPython.terminal.ptshell import TerminalInteractiveShell from IPython.terminal.ipapp import load_default_config from traitlets import Bool, CBool, Unicode @@ -136,6 +136,9 @@ def __call__(self, header='', local_ns=None, module=None, dummy=None, else: self.old_banner2 = '' + if self.display_banner: + self.show_banner() + # Call the embedding code with a stack depth of 1 so it can skip over # our call and get the original caller's namespaces. self.mainloop(local_ns, module, stack_depth=stack_depth, @@ -182,6 +185,9 @@ def mainloop(self, local_ns=None, module=None, stack_depth=0, module = DummyMod() module.__dict__ = global_ns + if (display_banner is not None): + warnings.warn("The display_banner parameter is deprecated.", DeprecationWarning) + # Get locals and globals from caller if ((local_ns is None or module is None or compile_flags is None) and self.default_user_namespaces): @@ -226,7 +232,7 @@ def mainloop(self, local_ns=None, module=None, stack_depth=0, self.set_completer_frame() with self.builtin_trap, self.display_trap: - self.interact(display_banner=display_banner) + self.interact() # now, purge out the local namespace of IPython's hidden variables. if local_ns is not None: From bc7757eddf330ea94703f54064934f83c9752c13 Mon Sep 17 00:00:00 2001 From: Justin Zymbaluk Date: Fri, 8 Apr 2016 06:40:38 -0600 Subject: [PATCH 0249/4859] Minor spelling changes to the docstring of TimeitResult --- IPython/core/magics/execution.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 4dd208b96f3..4edadc9ce70 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -61,12 +61,12 @@ class TimeitResult(object): """ Object returned by the timeit magic with info about the run. - Contain the following attributes : + Contains the following attributes : - loops: (int) number of loop done per measurement - repeat: (int) number of time the mesurement has been repeated - best: (float) best execusion time / number - all_runs: (list of float) execusion time of each run (in s) + loops: (int) number of loops done per measurement + repeat: (int) number of times the measurement has been repeated + best: (float) best execution time / number + all_runs: (list of float) execution time of each run (in s) compile_time: (float) time of statement compilation (s) """ From 9529e8ddd805d4cbb34814d163b5ba408f09c8f3 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 8 Apr 2016 12:18:18 -0700 Subject: [PATCH 0250/4859] Require path.py for tests This was previously hidden because pickleshare was pulling in path.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b9eb698db33..04e414948e4 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'path.py'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], From 92a216e798f83d1c3e4cd318bc8e61876980c4d7 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 13 Apr 2016 11:01:35 +0200 Subject: [PATCH 0251/4859] handle failure to get module for globals I ran into this learning alembic, which creates dummy modules and apparently doesn't put them in sys.modules. --- IPython/terminal/embed.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index f78aa2aba60..aa43ca451be 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -197,7 +197,14 @@ def mainloop(self, local_ns=None, module=None, stack_depth=0, local_ns = call_frame.f_locals if module is None: global_ns = call_frame.f_globals - module = sys.modules[global_ns['__name__']] + try: + module = sys.modules[global_ns['__name__']] + except KeyError: + warnings.warn("Failed to get module %s" % \ + global_ns.get('__name__', 'unknown module') + ) + module = DummyMod() + module.__dict__ = global_ns if compile_flags is None: compile_flags = (call_frame.f_code.co_flags & compilerop.PyCF_MASK) From a8c7f0578f8dd9a410c9785543d1fd1efb9be8e7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 13 Apr 2016 15:57:44 +0200 Subject: [PATCH 0252/4859] Add completion tests. --- IPython/core/tests/test_completer.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 8d6f4f06f1f..777cf1e49f4 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -783,6 +783,13 @@ def test_aimport_module_completer(): nt.assert_in('io', matches) nt.assert_not_in('int', matches) +def test_nested_import_module_completer(): + ip = get_ipython() + _, matches = ip.complete(None, 'import IPython.co', 17) + nt.assert_in('IPython.core', matches) + nt.assert_not_in('import IPython.core', matches) + nt.assert_not_in('IPython.display', matches) + def test_import_module_completer(): ip = get_ipython() _, matches = ip.complete('i', 'import i') From 8398a36f13660a041234e7f25c46e2065edfea0a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 14 Apr 2016 15:31:03 +0100 Subject: [PATCH 0253/4859] Use system_raw in ptshell Closes gh-9391 We were using system_piped, which runs processes through pexpect. Within the terminal, we can use system_raw, which lets the child processes interact directly with the terminal we're running in. --- IPython/terminal/ptshell.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 114aac80329..0ae89badfea 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -400,5 +400,10 @@ def int0(x): return False return True + # Run !system commands directly, not through pipes, so terminal programs + # work correctly. + system = InteractiveShell.system_raw + + if __name__ == '__main__': TerminalInteractiveShell.instance().interact() From 1b13f699344cbb6c979f284b3bec8f05e30ef378 Mon Sep 17 00:00:00 2001 From: Gil Forsyth Date: Thu, 14 Apr 2016 12:15:10 -0400 Subject: [PATCH 0254/4859] Have Ctrl-C in search mode clear query, if present As suggested in ipython/ipython#9314, when pressing Ctrl-C within the search-bar, the current search terms will be cleared but the search buffer will remain focused. Pressing Ctrl-C when the search buffer is empty will return focus to the default buffer. --- IPython/terminal/ptshell.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 0ae89badfea..a5625021de0 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -16,7 +16,7 @@ from traitlets import Bool, CBool, Unicode, Dict from prompt_toolkit.completion import Completer, Completion -from prompt_toolkit.enums import DEFAULT_BUFFER +from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER from prompt_toolkit.filters import HasFocus, HasSelection, Condition from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop @@ -182,6 +182,13 @@ def _(event): def _(event): event.current_buffer.reset() + @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) + def _(event): + if event.current_buffer.document.text: + event.current_buffer.reset() + else: + event.cli.push_focus(DEFAULT_BUFFER) + supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) From d9cf8f3a47f0ba26f713ec04513f75092299572e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 15 Apr 2016 11:02:56 +0200 Subject: [PATCH 0255/4859] Force completion results to be unicode. Should fix some of #9379 --- IPython/core/completer.py | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 86ba87e77cc..486ec4adee6 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -69,11 +69,10 @@ from IPython.core.inputsplitter import ESC_MAGIC from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol from IPython.utils import generics -from IPython.utils import io from IPython.utils.decorators import undoc from IPython.utils.dir2 import dir2, get_real_method from IPython.utils.process import arg_split -from IPython.utils.py3compat import builtin_mod, string_types, PY3 +from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 from traitlets import CBool, Enum #----------------------------------------------------------------------------- @@ -348,7 +347,7 @@ def global_matches(self, text): for word in lst: if word[:n] == text and word != "__builtins__": match_append(word) - return matches + return [cast_unicode_py2(m) for m in matches] def attr_matches(self, text): """Compute matches when text contains a dot. @@ -401,8 +400,7 @@ def attr_matches(self, text): pass # Build match list to return n = len(attr) - res = ["%s.%s" % (expr, w) for w in words if w[:n] == attr ] - return res + return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ] def get__all__entries(obj): @@ -412,7 +410,7 @@ def get__all__entries(obj): except: return [] - return [w for w in words if isinstance(w, string_types)] + return [cast_unicode_py2(w) for w in words if isinstance(w, string_types)] def match_dict_keys(keys, prefix, delims): @@ -682,9 +680,9 @@ def file_matches(self, text): # when escaped with backslash if text.startswith('!'): text = text[1:] - text_prefix = '!' + text_prefix = u'!' else: - text_prefix = '' + text_prefix = u'' text_until_cursor = self.text_until_cursor # track strings with open quotes @@ -715,7 +713,7 @@ def file_matches(self, text): text = os.path.expanduser(text) if text == "": - return [text_prefix + protect_filename(f) for f in self.glob("*")] + return [cast_unicode_py2(text_prefix + protect_filename(f)) for f in self.glob("*")] # Compute the matches from the filesystem m0 = self.clean_glob(text.replace('\\','')) @@ -737,11 +735,8 @@ def file_matches(self, text): matches = [text_prefix + protect_filename(f) for f in m0] - #io.rprint('mm', matches) # dbg - # Mark directories in input list by appending '/' to their names. - matches = [x+'/' if os.path.isdir(x) else x for x in matches] - return matches + return [cast_unicode_py2(x+'/') if os.path.isdir(x) else x for x in matches] def magic_matches(self, text): """Match magics""" @@ -763,9 +758,9 @@ def magic_matches(self, text): comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] if not text.startswith(pre2): comp += [ pre+m for m in line_magics if m.startswith(bare_text)] - return comp + return [cast_unicode_py2(c) for c in comp] - def python_matches(self,text): + def python_matches(self, text): """Match attributes or global python names""" #io.rprint('Completer->python_matches, txt=%r' % text) # dbg @@ -787,7 +782,6 @@ def python_matches(self,text): matches = [] else: matches = self.global_matches(text) - return matches def _default_arguments_from_docstring(self, doc): @@ -916,7 +910,7 @@ def python_func_kw_matches(self,text): for namedArg in namedArgs: if namedArg.startswith(text): - argMatches.append("%s=" %namedArg) + argMatches.append(u"%s=" %namedArg) return argMatches def dict_key_matches(self, text): @@ -1075,7 +1069,6 @@ def latex_matches(self, text): return u'', [] def dispatch_custom_completer(self, text): - #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg line = self.line_buffer if not line.strip(): return None @@ -1101,17 +1094,16 @@ def dispatch_custom_completer(self, text): for c in itertools.chain(self.custom_completers.s_matches(cmd), try_magic, self.custom_completers.flat_matches(self.text_until_cursor)): - #print "try",c # dbg try: res = c(event) if res: # first, try case sensitive match - withcase = [r for r in res if r.startswith(text)] + withcase = [cast_unicode_py2(r) for r in res if r.startswith(text)] if withcase: return withcase # if none, then case insensitive ones are ok too text_low = text.lower() - return [r for r in res if r.lower().startswith(text_low)] + return [cast_unicode_py2(r) for r in res if r.lower().startswith(text_low)] except TryNext: pass From bea40ef5d21467a86df9380c0059ee040e9962ac Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 15 Apr 2016 12:03:47 +0200 Subject: [PATCH 0256/4859] Fix casting --- 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 486ec4adee6..5a5c51e40e2 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -713,7 +713,7 @@ def file_matches(self, text): text = os.path.expanduser(text) if text == "": - return [cast_unicode_py2(text_prefix + protect_filename(f)) for f in self.glob("*")] + return [text_prefix + cast_unicode_py2(protect_filename(f)) for f in self.glob("*")] # Compute the matches from the filesystem m0 = self.clean_glob(text.replace('\\','')) From c1b830295e66fcc673f5250b7ceb479c297d18ad Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 15 Apr 2016 12:12:56 +0200 Subject: [PATCH 0257/4859] fix test --- IPython/core/interactiveshell.py | 3 ++- IPython/testing/skipdoctest.py | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 738f1d4b86c..04536a9641e 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -57,7 +57,7 @@ from IPython.core.profiledir import ProfileDir from IPython.core.prompts import PromptManager from IPython.core.usage import default_banner -from IPython.testing.skipdoctest import skip_doctest +from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest from IPython.utils import PyColorize from IPython.utils import io from IPython.utils import py3compat @@ -1939,6 +1939,7 @@ def init_completer(self): self.set_hook('complete_command', reset_completer, str_key = '%reset') + @skip_doctest_py2 def complete(self, text, line=None, cursor_pos=None): """Return the completed text and a list of completions. diff --git a/IPython/testing/skipdoctest.py b/IPython/testing/skipdoctest.py index c055f43f7c4..564ca540272 100644 --- a/IPython/testing/skipdoctest.py +++ b/IPython/testing/skipdoctest.py @@ -36,3 +36,8 @@ def skip_doctest_py3(f): """Decorator - skip the doctest under Python 3.""" f.skip_doctest = (sys.version_info[0] >= 3) return f + +def skip_doctest_py2(f): + """Decorator - skip the doctest under Python 3.""" + f.skip_doctest = (sys.version_info[0] < 3) + return f From 65475b72cd9215b9dfbb6f0bc150ee7b3197e68a Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 15 Apr 2016 14:48:43 +0200 Subject: [PATCH 0258/4859] add missing `project` arg in github_stats --- tools/github_stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/github_stats.py b/tools/github_stats.py index fe76affdc94..efe34a84699 100755 --- a/tools/github_stats.py +++ b/tools/github_stats.py @@ -168,7 +168,7 @@ def report(issues, show_urls=False): state='closed', auth=True, ) - issues, pulls = split_pulls(issues_and_pulls) + issues, pulls = split_pulls(issues_and_pulls, project=project) else: issues = issues_closed_since(since, project=project, pulls=False) pulls = issues_closed_since(since, project=project, pulls=True) From cf3101a4f0da338b5fbce61c0bf02dec8539be0f Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 19 Apr 2016 12:12:08 +0200 Subject: [PATCH 0259/4859] use pathlib for utils.text.paths instead of path.py --- IPython/utils/tests/test_text.py | 8 ++++++-- IPython/utils/text.py | 11 +++++++---- setup.py | 3 ++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/IPython/utils/tests/test_text.py b/IPython/utils/tests/test_text.py index fd2c64f6e21..57171a984e3 100644 --- a/IPython/utils/tests/test_text.py +++ b/IPython/utils/tests/test_text.py @@ -19,7 +19,11 @@ import sys import nose.tools as nt -import path +try: + from pathlib import Path +except ImportError: + # Python 2 backport + from pathlib2 import Path from IPython.utils import text @@ -207,7 +211,7 @@ def test_LSString(): nt.assert_equal(lss.l, ['abc', 'def']) nt.assert_equal(lss.s, 'abc def') lss = text.LSString(os.getcwd()) - nt.assert_is_instance(lss.p[0], path.path) + nt.assert_is_instance(lss.p[0], Path) def test_SList(): sl = text.SList(['a 11', 'b 1', 'a 2']) diff --git a/IPython/utils/text.py b/IPython/utils/text.py index 6766abba21f..5ed1a845e35 100644 --- a/IPython/utils/text.py +++ b/IPython/utils/text.py @@ -14,6 +14,11 @@ import sys import textwrap from string import Formatter +try: + from pathlib import Path +except ImportError: + # Python 2 backport + from pathlib2 import Path from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest from IPython.utils import py3compat @@ -64,11 +69,10 @@ def get_nlstr(self): n = nlstr = property(get_nlstr) def get_paths(self): - from path import path try: return self.__paths except AttributeError: - self.__paths = [path(p) for p in self.split('\n') if os.path.exists(p)] + self.__paths = [Path(p) for p in self.split('\n') if os.path.exists(p)] return self.__paths p = paths = property(get_paths) @@ -123,11 +127,10 @@ def get_nlstr(self): n = nlstr = property(get_nlstr) def get_paths(self): - from path import path try: return self.__paths except AttributeError: - self.__paths = [path(p) for p in self if os.path.exists(p)] + self.__paths = [Path(p) for p in self if os.path.exists(p)] return self.__paths p = paths = property(get_paths) diff --git a/setup.py b/setup.py index 04e414948e4..7fae9ef0535 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'path.py'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], @@ -205,6 +205,7 @@ def run(self): # but requires pip >= 6. pip < 6 ignores these. extras_require.update({ + ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'], ':sys_platform != "win32"': ['pexpect'], ':sys_platform == "darwin"': ['appnope'], ':sys_platform == "win32"': ['colorama'], From a0adb30b87d51c967c8a90b3d51ded2a47b808a9 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Apr 2016 12:48:51 +0100 Subject: [PATCH 0260/4859] Return value from format_display_data I guess nothing was using this ;-) --- IPython/core/formatters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 700a90395b5..62d296f6716 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -944,7 +944,7 @@ def format_display_data(obj, include=None, exclude=None): """ from IPython.core.interactiveshell import InteractiveShell - InteractiveShell.instance().display_formatter.format( + return InteractiveShell.instance().display_formatter.format( obj, include, exclude From 9c6b377ab0ef7ffd5afd1289f4719cb3602ba999 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 19 Apr 2016 13:57:02 +0200 Subject: [PATCH 0261/4859] bump intersphinx python ref to py3 --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index cdf39f95921..0f689a487e2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -201,7 +201,7 @@ # Output file base name for HTML help builder. htmlhelp_basename = 'ipythondoc' -intersphinx_mapping = {'python': ('http://docs.python.org/2/', None), +intersphinx_mapping = {'python': ('http://docs.python.org/3/', None), 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), 'traitlets': ('http://traitlets.readthedocs.org/en/latest/', None), 'jupyterclient': ('http://jupyter-client.readthedocs.org/en/latest/', None), From 92b70113d0b33a586f1457d93634d90c03fa8d45 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 19 Apr 2016 13:57:07 +0200 Subject: [PATCH 0262/4859] changelog for 4.2 --- docs/source/whatsnew/version4.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/source/whatsnew/version4.rst b/docs/source/whatsnew/version4.rst index a7fc23c45c5..d8ec8dc7a46 100644 --- a/docs/source/whatsnew/version4.rst +++ b/docs/source/whatsnew/version4.rst @@ -2,6 +2,19 @@ 4.x Series ============ +IPython 4.2 +=========== + +IPython 4.2 (April, 2016) includes various bugfixes and improvements over 4.1. + +- Fix ``ipython -i`` on errors, which was broken in 4.1. +- The delay meant to highlight deprecated commands that have moved to jupyter has been removed. +- Improve compatibility with future versions of traitlets and matplotlib. +- Use stdlib :func:`python:shutil.get_terminal_size` to measure terminal width when displaying tracebacks + (provided by ``backports.shutil_get_terminal_size`` on Python 2). + +You can see the rest `on GitHub `__. + IPython 4.1 =========== From 54d60477b4c420bd6a1279a5569b5f1ffcd94d9f Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 20 Apr 2016 14:02:07 +0200 Subject: [PATCH 0263/4859] github stats for 4.2 --- docs/source/whatsnew/github-stats-4.rst | 26 ++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/docs/source/whatsnew/github-stats-4.rst b/docs/source/whatsnew/github-stats-4.rst index 480ddc2540d..32d49d315dd 100644 --- a/docs/source/whatsnew/github-stats-4.rst +++ b/docs/source/whatsnew/github-stats-4.rst @@ -3,9 +3,33 @@ Issues closed in the 4.x development cycle ========================================== -Issues closed in 4.1 + +Issues closed in 4.2 -------------------- +GitHub stats for 2015/02/02 - 2016/04/20 (since 4.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 10 issues and merged 22 pull requests. +The full list can be seen `on GitHub `__ + +The following 10 authors contributed 27 commits. + +* Benjamin Ragan-Kelley +* Carlos Cordoba +* Gökhan Karabulut +* Jonas Rauber +* Matthias Bussonnier +* Paul Ivanov +* Sebastian Bank +* Thomas A Caswell +* Thomas Kluyver +* Vincent Woo + + +Issues closed in 4.1 +-------------------- GitHub stats for 2015/08/12 - 2016/02/02 (since 4.0.0) From 48a882d6b54b0df7f6f82020455133e2aa0a9273 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 20 Apr 2016 17:13:58 +0200 Subject: [PATCH 0264/4859] Fix #9406 --- IPython/core/page.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index b3f06e618bf..3f0312fffdc 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -298,7 +298,7 @@ def get_pager_cmd(pager_cmd=None): Makes some attempts at finding an OS-correct one. """ if os.name == 'posix': - default_pager_cmd = 'less -r' # -r for color control sequences + default_pager_cmd = 'less -R' # -r for color control sequences elif os.name in ['nt','dos']: default_pager_cmd = 'type' @@ -308,8 +308,8 @@ def get_pager_cmd(pager_cmd=None): except: pager_cmd = default_pager_cmd - if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): - pager_cmd += ' -r' + if pager_cmd == 'less' and not os.environ.get('LESS', ''): + pager_cmd += ' -R' return pager_cmd From 422d42ee9639107fdc11ec9f5864ae63e1858b5f Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Wed, 20 Apr 2016 21:03:32 +0200 Subject: [PATCH 0265/4859] Thomas fix --- IPython/core/page.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index 3f0312fffdc..b0f4a7f366f 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -298,7 +298,7 @@ def get_pager_cmd(pager_cmd=None): Makes some attempts at finding an OS-correct one. """ if os.name == 'posix': - default_pager_cmd = 'less -R' # -r for color control sequences + default_pager_cmd = 'less -R' # -R for color control sequences elif os.name in ['nt','dos']: default_pager_cmd = 'type' @@ -308,7 +308,7 @@ def get_pager_cmd(pager_cmd=None): except: pager_cmd = default_pager_cmd - if pager_cmd == 'less' and not os.environ.get('LESS', ''): + if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): pager_cmd += ' -R' return pager_cmd From 7cd4bd7a430bdd8cb550c11da61e31e5e9bd4798 Mon Sep 17 00:00:00 2001 From: Min RK Date: Thu, 21 Apr 2016 14:25:01 +0200 Subject: [PATCH 0266/4859] log history db failure before calling init_db if init_db is where the failure occurs, we will never see the message due to infinite recursion. This does not fix the infinite recursion itself. --- IPython/core/history.py | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/IPython/core/history.py b/IPython/core/history.py index fc79642ea90..7db39a27b51 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -1,18 +1,10 @@ """ History related magics and functionality """ -#----------------------------------------------------------------------------- -# Copyright (C) 2010-2011 The IPython Development Team. -# -# Distributed under the terms of the BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + from __future__ import print_function -# Stdlib imports import atexit import datetime import os @@ -24,9 +16,9 @@ from pysqlite2 import dbapi2 as sqlite3 except ImportError: sqlite3 = None +import sys import threading -# Our own packages from traitlets.config.configurable import LoggingConfigurable from decorator import decorator from IPython.utils.decorators import undoc @@ -88,15 +80,15 @@ def catch_corrupt_db(f, self, *a, **kw): """ try: return f(self, *a, **kw) - except (DatabaseError, OperationalError): + except (DatabaseError, OperationalError) as e: if os.path.isfile(self.hist_file): # Try to move the file out of the way base,ext = os.path.splitext(self.hist_file) newpath = base + '-corrupt' + ext os.rename(self.hist_file, newpath) + print("ERROR! History file wasn't a valid SQLite database (%s)." % e, + "It was moved to %s" % newpath, "and a new file created.", file=sys.stderr) self.init_db() - print("ERROR! History file wasn't a valid SQLite database.", - "It was moved to %s" % newpath, "and a new file created.") return [] else: From 05edbcc6dc9f9052f1f7255df83a6794ee4d582c Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 22 Apr 2016 13:30:53 +0200 Subject: [PATCH 0267/4859] only use backports.shutil_get_terminal_size on Python 2 removes the backport dependency on Python 3, where it's not needed. --- IPython/utils/terminal.py | 20 ++++++++------------ setup.py | 2 +- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/IPython/utils/terminal.py b/IPython/utils/terminal.py index 9e7be2a6da7..a1f0f73308e 100644 --- a/IPython/utils/terminal.py +++ b/IPython/utils/terminal.py @@ -9,22 +9,18 @@ * Alexander Belchenko (e-mail: bialix AT ukr.net) """ -#----------------------------------------------------------------------------- -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import os import struct import sys import warnings -import backports.shutil_get_terminal_size +try: + from shutil import get_terminal_size as _get_terminal_size +except ImportError: + # use backport on Python 2 + from backports.shutil_get_terminal_size import get_terminal_size as _get_terminal_size from . import py3compat @@ -122,4 +118,4 @@ def freeze_term_title(): def get_terminal_size(defaultx=80, defaulty=25): - return backports.shutil_get_terminal_size.get_terminal_size((defaultx, defaulty)) + return _get_terminal_size((defaultx, defaulty)) diff --git a/setup.py b/setup.py index 7fae9ef0535..7e129a1ce2f 100755 --- a/setup.py +++ b/setup.py @@ -197,7 +197,6 @@ def run(self): 'traitlets', 'prompt_toolkit>=0.60', 'pygments', - 'backports.shutil_get_terminal_size', ] # Platform-specific dependencies: @@ -205,6 +204,7 @@ def run(self): # but requires pip >= 6. pip < 6 ignores these. extras_require.update({ + ':python_version == "2.7"': ['backports.shutil_get_terminal_size'], ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'], ':sys_platform != "win32"': ['pexpect'], ':sys_platform == "darwin"': ['appnope'], From ac8365ce6fc9071527b16cd1404d05b6c4db2e32 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 22 Apr 2016 16:30:19 +0200 Subject: [PATCH 0268/4859] test nonascii exceptions --- IPython/core/tests/test_ultratb.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/IPython/core/tests/test_ultratb.py b/IPython/core/tests/test_ultratb.py index 9d1f26a1fcb..27b6fc43fd9 100644 --- a/IPython/core/tests/test_ultratb.py +++ b/IPython/core/tests/test_ultratb.py @@ -99,6 +99,21 @@ def test_iso8859_5(self): with tt.AssertPrints("ZeroDivisionError"): with tt.AssertPrints(u'дбИЖ', suppress=False): ip.run_cell('fail()') + + def test_nonascii_msg(self): + cell = u"raise Exception('é')" + expected = u"Exception('é')" + ip.run_cell("%xmode plain") + with tt.AssertPrints(expected): + ip.run_cell(cell) + + ip.run_cell("%xmode verbose") + with tt.AssertPrints(expected): + ip.run_cell(cell) + + ip.run_cell("%xmode context") + with tt.AssertPrints(expected): + ip.run_cell(cell) class NestedGenExprTestCase(unittest.TestCase): From 71c18b6854bbff6bb41b8c6c239f24afaeba0f88 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 22 Apr 2016 16:32:50 +0200 Subject: [PATCH 0269/4859] handle unicode exception messages in xmode plain --- IPython/core/ultratb.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index f56ee615bd8..4ba08ba502f 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -709,10 +709,10 @@ def _format_exception_only(self, etype, value): have_filedata = False Colors = self.Colors list = [] - stype = Colors.excName + etype.__name__ + Colors.Normal + stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal) if value is None: # Not sure if this can still happen in Python 2.6 and above - list.append(py3compat.cast_unicode(stype) + '\n') + list.append(stype + '\n') else: if issubclass(etype, SyntaxError): have_filedata = True @@ -752,10 +752,10 @@ def _format_exception_only(self, etype, value): except Exception: s = self._some_str(value) if s: - list.append('%s%s:%s %s\n' % (str(stype), Colors.excName, + list.append('%s%s:%s %s\n' % (stype, Colors.excName, Colors.Normal, s)) else: - list.append('%s\n' % str(stype)) + list.append('%s\n' % stype) # sync with user hooks if have_filedata: @@ -793,9 +793,9 @@ def show_exception_only(self, etype, evalue): def _some_str(self, value): # Lifted from traceback.py try: - return str(value) + return py3compat.cast_unicode(str(value)) except: - return '' % type(value).__name__ + return u'' % type(value).__name__ #---------------------------------------------------------------------------- From 1706eb849d470a83a7e0d39b5af73efbfc820f5b Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 22 Apr 2016 14:32:12 +0200 Subject: [PATCH 0270/4859] Fallback to :memory: on repeated failure to load history two consecutive failures to load history will result in falling back on :memory: --- IPython/core/history.py | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/IPython/core/history.py b/IPython/core/history.py index 7db39a27b51..ab32e83f0d3 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -16,7 +16,6 @@ from pysqlite2 import dbapi2 as sqlite3 except ImportError: sqlite3 = None -import sys import threading from traitlets.config.configurable import LoggingConfigurable @@ -81,18 +80,29 @@ def catch_corrupt_db(f, self, *a, **kw): try: return f(self, *a, **kw) except (DatabaseError, OperationalError) as e: - if os.path.isfile(self.hist_file): - # Try to move the file out of the way - base,ext = os.path.splitext(self.hist_file) - newpath = base + '-corrupt' + ext - os.rename(self.hist_file, newpath) - print("ERROR! History file wasn't a valid SQLite database (%s)." % e, - "It was moved to %s" % newpath, "and a new file created.", file=sys.stderr) + self._corrupt_db_counter += 1 + self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e) + if self.hist_file != ':memory:': + if self._corrupt_db_counter > self._corrupt_db_limit: + self.hist_file = ':memory:' + self.log.error("Failed to load history too many times, history will not be saved.") + elif os.path.isfile(self.hist_file): + # Try to move the file out of the way + base,ext = os.path.splitext(self.hist_file) + now = datetime.datetime.now().isoformat().replace(':', '.') + newpath = base + '-corrupt-' + now + ext + # don't clobber previous corrupt backups + for i in range(100): + if not os.path.isfile(newpath): + break + else: + newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext + os.rename(self.hist_file, newpath) + self.log.error("History file was moved to %s and a new file created.", newpath) self.init_db() return [] - else: - # The hist_file is probably :memory: or something else. + # Failed with :memory:, something serious is wrong raise class HistoryAccessorBase(LoggingConfigurable): @@ -118,6 +128,11 @@ class HistoryAccessor(HistoryAccessorBase): This is intended for use by standalone history tools. IPython shells use HistoryManager, below, which is a subclass of this.""" + # counter for init_db retries, so we don't keep trying over and over + _corrupt_db_counter = 0 + # after two failures, fallback on :memory: + _corrupt_db_limit = 2 + # String holding the path to the history file hist_file = Unicode(config=True, help="""Path to file to use for SQLite history database. @@ -231,6 +246,8 @@ def init_db(self): (session integer, line integer, output text, PRIMARY KEY (session, line))""") self.db.commit() + # success! reset corrupt db count + self._corrupt_db_counter = 0 def writeout_cache(self): """Overridden by HistoryManager to dump the cache before certain From 05e6b192ad81a88625bb243738ad94e5ea1c0962 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 22 Apr 2016 16:59:52 +0200 Subject: [PATCH 0271/4859] only avoid clobbering corrupt dbs that have some content this logic can be triggered by connection failures that do not mean the file is corrupt, so we don't want to lose data unnecessarily. --- IPython/core/history.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/IPython/core/history.py b/IPython/core/history.py index ab32e83f0d3..be0afc2d633 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -71,11 +71,18 @@ class DatabaseError(Exception): class OperationalError(Exception): "Dummy exception when sqlite could not be imported. Should never occur." +# use 16kB as threshold for whether a corrupt history db should be saved +# that should be at least 100 entries or so +_SAVE_DB_SIZE = 16384 + @decorator def catch_corrupt_db(f, self, *a, **kw): """A decorator which wraps HistoryAccessor method calls to catch errors from a corrupt SQLite database, move the old database out of the way, and create a new one. + + We avoid clobbering larger databases because this may be triggered due to filesystem issues, + not just a corrupt file. """ try: return f(self, *a, **kw) @@ -87,16 +94,23 @@ def catch_corrupt_db(f, self, *a, **kw): self.hist_file = ':memory:' self.log.error("Failed to load history too many times, history will not be saved.") elif os.path.isfile(self.hist_file): - # Try to move the file out of the way - base,ext = os.path.splitext(self.hist_file) - now = datetime.datetime.now().isoformat().replace(':', '.') - newpath = base + '-corrupt-' + now + ext - # don't clobber previous corrupt backups - for i in range(100): - if not os.path.isfile(newpath): - break - else: - newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext + # move the file out of the way + base, ext = os.path.splitext(self.hist_file) + size = os.stat(self.hist_file).st_size + if size >= _SAVE_DB_SIZE: + # if there's significant content, avoid clobbering + now = datetime.datetime.now().isoformat().replace(':', '.') + newpath = base + '-corrupt-' + now + ext + # don't clobber previous corrupt backups + for i in range(100): + if not os.path.isfile(newpath): + break + else: + newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext + else: + # not much content, possibly empty; don't worry about clobbering + # maybe we should just delete it? + newpath = base + '-corrupt' + ext os.rename(self.hist_file, newpath) self.log.error("History file was moved to %s and a new file created.", newpath) self.init_db() From fc23da03ce99e5c250e606f0fc9e4de6066e5028 Mon Sep 17 00:00:00 2001 From: Pierre Gerold Date: Sat, 23 Apr 2016 10:55:41 +0200 Subject: [PATCH 0272/4859] Check '-r' or '-R' and add '-R' if both absent --- IPython/core/page.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index b0f4a7f366f..ec2e07744e0 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -308,7 +308,7 @@ def get_pager_cmd(pager_cmd=None): except: pager_cmd = default_pager_cmd - if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): + if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower(): pager_cmd += ' -R' return pager_cmd From 4dc72dc6d01c31512e7b8d6ae9427f55913b8409 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Apr 2016 16:46:07 +0200 Subject: [PATCH 0273/4859] Make "reserve_space_for_menu" configurable. If would be nice to have that dynamic, especially since it already appear to be configurable when using the `%config` magic. Though it does not seem to be obvious to do in PTK, unless we recalculate the full layout for the application, and reset it. --- IPython/terminal/ptshell.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index a5625021de0..eb2ee257bd3 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -13,7 +13,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from traitlets import Bool, CBool, Unicode, Dict +from traitlets import Bool, CBool, Unicode, Dict, Integer from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER @@ -89,6 +89,9 @@ def lex_document(self, cli, document): class TerminalInteractiveShell(InteractiveShell): colors_force = True + space_for_menu = Integer(6, config=True, help='space at the bottom of the screen to reserve for' + 'the completion menu') + pt_cli = None autoedit_syntax = CBool(False, config=True, @@ -253,7 +256,7 @@ def _(event): enable_history_search=True, style=style, mouse_support=self.mouse_support, - reserve_space_for_menu=6, + reserve_space_for_menu=self.space_for_menu, ) self.pt_cli = CommandLineInterface(app, From 3aa7df64b1fedb5693c322877623984a3543b569 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Apr 2016 09:19:58 -0700 Subject: [PATCH 0274/4859] Make style and layout dynamic. Recompute the lout of the application when the number of required line for the completion change. Use Prompt Toolkit to provide Dynamic colors when using the `config` Magic. --- IPython/terminal/ptshell.py | 76 ++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index eb2ee257bd3..cade2e33c7e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -19,7 +19,7 @@ from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER from prompt_toolkit.filters import HasFocus, HasSelection, Condition from prompt_toolkit.history import InMemoryHistory -from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop +from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager from prompt_toolkit.key_binding.vi_state import InputMode @@ -27,9 +27,9 @@ from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer -from prompt_toolkit.styles import PygmentsStyle +from prompt_toolkit.styles import PygmentsStyle, DynamicStyle -from pygments.styles import get_style_by_name +from pygments.styles import get_style_by_name, get_all_styles from pygments.lexers import Python3Lexer, BashLexer, PythonLexer from pygments.token import Token @@ -92,6 +92,9 @@ class TerminalInteractiveShell(InteractiveShell): space_for_menu = Integer(6, config=True, help='space at the bottom of the screen to reserve for' 'the completion menu') + def _space_for_menu_changed(self, old, new): + self.relayout() + pt_cli = None autoedit_syntax = CBool(False, config=True, @@ -111,10 +114,13 @@ class TerminalInteractiveShell(InteractiveShell): help="Enable mouse support in the prompt" ) - highlighting_style = Unicode('', config=True, - help="The name of a Pygments style to use for syntax highlighting" + highlighting_style = Unicode('default', config=True, + help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) ) + def _highlighting_style_changed(self, old, new): + self._style = self._make_style_from_name(self.highlighting_style) + highlighting_style_overrides = Dict(config=True, help="Override highlighting format for specific tokens" ) @@ -223,13 +229,33 @@ def _(event): if cell and (cell != last_cell): history.append(cell) + self._style = self._make_style_from_name(self.highlighting_style) + style = DynamicStyle(lambda: self._style) + + self._app = create_prompt_application( + key_bindings_registry=kbmanager.registry, + history=history, + completer=IPythonPTCompleter(self.Completer), + enable_history_search=True, + style=style, + mouse_support=self.mouse_support, + **self._layout_options() + ) + self.pt_cli = CommandLineInterface(self._app, + eventloop=create_eventloop(self.inputhook)) + + def _make_style_from_name(self, name): + """ + Small wrapper that make an IPython compatible style from a style name + + We need that to add style for prompt ... etc. + """ + style_cls = get_style_by_name(name) style_overrides = { Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', } - if self.highlighting_style: - style_cls = get_style_by_name(self.highlighting_style) - else: + if name is 'default': style_cls = get_style_by_name('default') # The default theme needs to be visible on both a dark background # and a light background, because we can't tell what the terminal @@ -246,21 +272,27 @@ def _(event): style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, style_dict=style_overrides) - app = create_prompt_application(multiline=True, - lexer=IPythonPTLexer(), - get_prompt_tokens=self.get_prompt_tokens, - get_continuation_tokens=self.get_continuation_tokens, - key_bindings_registry=kbmanager.registry, - history=history, - completer=IPythonPTCompleter(self.Completer), - enable_history_search=True, - style=style, - mouse_support=self.mouse_support, - reserve_space_for_menu=self.space_for_menu, - ) + return style - self.pt_cli = CommandLineInterface(app, - eventloop=create_eventloop(self.inputhook)) + def _layout_options(self): + """ + Return the current layout option for the current Terminal InteractiveShell + """ + return { + 'lexer':IPythonPTLexer(), + 'reserve_space_for_menu':self.space_for_menu, + 'get_prompt_tokens':self.get_prompt_tokens, + 'get_continuation_tokens':self.get_continuation_tokens, + 'multiline':False, + } + + + def _relayout(self): + """ + Ask for a re computation of the application layout, if for example , + some configuration options have changed. + """ + self._app.layout = create_prompt_layout(**self._layout_options()) def prompt_for_code(self): document = self.pt_cli.run(pre_run=self.pre_prompt) From 0e2d09b143c034ed0f82d653857949912e731a6a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Apr 2016 09:36:22 -0700 Subject: [PATCH 0275/4859] Pick default prompt colors form already existing Tokens if possible. This allow a more uniform theme when changing color scheme for highlighting. --- IPython/terminal/ptshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index cade2e33c7e..c4ea11af541 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -252,8 +252,8 @@ def _make_style_from_name(self, name): """ style_cls = get_style_by_name(name) style_overrides = { - Token.Prompt: '#009900', - Token.PromptNum: '#00ff00 bold', + Token.Prompt: style_cls.styles.get( Token.Keyword, '#009900'), + Token.PromptNum: style_cls.styles.get( Token.Literal.Number, '#00ff00 bold') } if name is 'default': style_cls = get_style_by_name('default') From 0b3951cba45b5767c27ce39ddcd75e30f82d2fa1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Apr 2016 16:05:37 -0700 Subject: [PATCH 0276/4859] Rename relayout to _update_layout --- IPython/terminal/ptshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c4ea11af541..332edcc88ce 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -93,7 +93,7 @@ class TerminalInteractiveShell(InteractiveShell): 'the completion menu') def _space_for_menu_changed(self, old, new): - self.relayout() + self._update_layout() pt_cli = None @@ -287,7 +287,7 @@ def _layout_options(self): } - def _relayout(self): + def _update_layout(self): """ Ask for a re computation of the application layout, if for example , some configuration options have changed. From 5a6a38375486fd10444a6b1062d56eb351f8fc16 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Apr 2016 16:53:51 -0700 Subject: [PATCH 0277/4859] 'fix help string' --- IPython/terminal/ptshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 332edcc88ce..450ba4fdbac 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -89,8 +89,8 @@ def lex_document(self, cli, document): class TerminalInteractiveShell(InteractiveShell): colors_force = True - space_for_menu = Integer(6, config=True, help='space at the bottom of the screen to reserve for' - 'the completion menu') + space_for_menu = Integer(6, config=True, help='Number of line at the bottom of the screen ' + 'to reserve for the completion menu') def _space_for_menu_changed(self, old, new): self._update_layout() From acaa21368f704a1fb09e95cdfcda4ade27e27b1b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Apr 2016 14:23:56 -0700 Subject: [PATCH 0278/4859] Promote keywords arguments completion. Mostly when you are completing in a function call, it seem logical that if keywords are available, they are the ones you are interested in. --- IPython/core/completer.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 5a5c51e40e2..bee864fcc6a 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -190,6 +190,9 @@ def completions_sorting_key(word): elif word.startswith('_'): prio1 = 1 + if word.endswith('='): + prio1 = -1 + if word.startswith('%%'): # If there's another % in there, this is something else, so leave it alone if not "%" in word[2:]: From c69d93ae55b19f421c255134dfc7919f1685103e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 29 Apr 2016 16:30:54 -0700 Subject: [PATCH 0279/4859] Re enable multi line in PT-TerminalInteractiveShell Made it to false by mistake (mine) in #9423 Note that it "just" removed continuation prompt as "multiline" is just a hint for prompt_toolkit. --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 450ba4fdbac..6b12485098b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -283,7 +283,7 @@ def _layout_options(self): 'reserve_space_for_menu':self.space_for_menu, 'get_prompt_tokens':self.get_prompt_tokens, 'get_continuation_tokens':self.get_continuation_tokens, - 'multiline':False, + 'multiline':True, } From 7243b34e4110128051d0a9f3d6cbbf7da3790289 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 1 May 2016 13:20:54 +0100 Subject: [PATCH 0280/4859] Back to explicit styles for the prompt tokens I didn't notice these had changed in Carreau's PR. The prompt number in particular was looking horrible with the default settings. I have reverted back to what we had before. --- IPython/terminal/ptshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 450ba4fdbac..9f1288fa60a 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -252,8 +252,8 @@ def _make_style_from_name(self, name): """ style_cls = get_style_by_name(name) style_overrides = { - Token.Prompt: style_cls.styles.get( Token.Keyword, '#009900'), - Token.PromptNum: style_cls.styles.get( Token.Literal.Number, '#00ff00 bold') + Token.Prompt: '#009900', + Token.PromptNum: '#00ff00 bold', } if name is 'default': style_cls = get_style_by_name('default') From 87a0a70dc9cf3a3b083eeba897e30a0e34a44e97 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 2 May 2016 11:49:49 -0700 Subject: [PATCH 0281/4859] Readthedocs documentation is now on RTD.io not .com --- docs/source/development/index.rst | 2 +- docs/source/development/wrapperkernels.rst | 2 +- docs/source/index.rst | 4 ++-- docs/source/install/install.rst | 2 +- docs/source/interactive/index.rst | 2 +- docs/source/overview.rst | 2 +- docs/source/whatsnew/github-stats-1.0.rst | 2 +- docs/source/whatsnew/version4.rst | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/development/index.rst b/docs/source/development/index.rst index a94562555f4..389fdea96ad 100644 --- a/docs/source/development/index.rst +++ b/docs/source/development/index.rst @@ -19,4 +19,4 @@ Developer's guide for third party tools and libraries lexer pycompat config - inputhook_app \ No newline at end of file + inputhook_app diff --git a/docs/source/development/wrapperkernels.rst b/docs/source/development/wrapperkernels.rst index f6e308bdf47..65f3a1e10c3 100644 --- a/docs/source/development/wrapperkernels.rst +++ b/docs/source/development/wrapperkernels.rst @@ -7,7 +7,7 @@ You can now re-use the kernel machinery in IPython to easily make new kernels. This is useful for languages that have Python bindings, such as `Octave `_ (via `Oct2Py `_), or languages -where the REPL can be controlled in a tty using `pexpect `_, +where the REPL can be controlled in a tty using `pexpect `_, such as bash. .. seealso:: diff --git a/docs/source/index.rst b/docs/source/index.rst index fc948f13fed..7b4625eeccf 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -27,10 +27,10 @@ Contents .. seealso:: - `Jupyter documentation `__ + `Jupyter documentation `__ The Notebook code and many other pieces formerly in IPython are now parts of Project Jupyter. - `ipyparallel documentation `__ + `ipyparallel documentation `__ Formerly ``IPython.parallel``. diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index 249aaa59254..c2895f61ced 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -2,7 +2,7 @@ IPython requires Python 2.7 or ≥ 3.3. .. seealso:: - `Installing Jupyter `__ + `Installing Jupyter `__ The Notebook, nbconvert, and many other former pieces of IPython are now part of Project Jupyter. diff --git a/docs/source/interactive/index.rst b/docs/source/interactive/index.rst index 3441c705f92..26c393d0595 100644 --- a/docs/source/interactive/index.rst +++ b/docs/source/interactive/index.rst @@ -15,4 +15,4 @@ Using IPython for interactive work .. seealso:: `A Qt Console for Jupyter `__ - `The Jupyter Notebook `__ + `The Jupyter Notebook `__ diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 7d4b8b0e93c..a81604d23cf 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -219,7 +219,7 @@ different numbers which correspond to the Process ID of the kernel. You can read more about using `ipython qtconsole `_, and -`ipython notebook `_. There +`ipython notebook `_. There is also a :ref:`message spec ` which documents the protocol for communication between kernels and clients. diff --git a/docs/source/whatsnew/github-stats-1.0.rst b/docs/source/whatsnew/github-stats-1.0.rst index 05bdbde6f44..d0b1ae18d6a 100644 --- a/docs/source/whatsnew/github-stats-1.0.rst +++ b/docs/source/whatsnew/github-stats-1.0.rst @@ -1000,7 +1000,7 @@ Pull Requests (793): * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. * :ghpull:`2270`: SSHLauncher tweaks * :ghpull:`2269`: add missing location when disambiguating controller IP -* :ghpull:`2263`: Allow docs to build on http://readthedocs.org/ +* :ghpull:`2263`: Allow docs to build on http://readthedocs.io/ * :ghpull:`2256`: Adding data publication example notebook. * :ghpull:`2255`: better flush iopub with AsyncResults * :ghpull:`2261`: Fix: longest_substr([]) -> '' diff --git a/docs/source/whatsnew/version4.rst b/docs/source/whatsnew/version4.rst index d8ec8dc7a46..6150a8668cd 100644 --- a/docs/source/whatsnew/version4.rst +++ b/docs/source/whatsnew/version4.rst @@ -47,8 +47,8 @@ Released August, 2015 IPython 4.0 is the first major release after the Big Split. IPython no longer contains the notebook, qtconsole, etc. which have moved to -`jupyter `_. -IPython subprojects, such as `IPython.parallel `_ and `widgets `_ have moved to their own repos as well. +`jupyter `_. +IPython subprojects, such as `IPython.parallel `_ and `widgets `_ have moved to their own repos as well. The following subpackages are deprecated: From ad08d53e531c41b9252fc928a2035553c338f8f4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 2 May 2016 13:04:34 -0700 Subject: [PATCH 0282/4859] Update conf.py, in particular intersphinx too. --- docs/source/conf.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 0f689a487e2..6b7a5fb5a1e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ if ON_RTD: # Mock the presence of matplotlib, which we don't have on RTD # see - # http://read-the-docs.readthedocs.org/en/latest/faq.html + # http://read-the-docs.readthedocs.io/en/latest/faq.html tags.add('rtd') # RTD doesn't use the Makefile, so re-run autogen_{things}.py here. @@ -203,10 +203,10 @@ intersphinx_mapping = {'python': ('http://docs.python.org/3/', None), 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), - 'traitlets': ('http://traitlets.readthedocs.org/en/latest/', None), - 'jupyterclient': ('http://jupyter-client.readthedocs.org/en/latest/', None), - 'ipyparallel': ('http://ipyparallel.readthedocs.org/en/latest/', None), - 'jupyter': ('http://jupyter.readthedocs.org/en/latest/', None), + 'traitlets': ('http://traitlets.readthedocs.io/en/latest/', None), + 'jupyterclient': ('http://jupyter-client.readthedocs.io/en/latest/', None), + 'ipyparallel': ('http://ipyparallel.readthedocs.io/en/latest/', None), + 'jupyter': ('http://jupyter.readthedocs.io/en/latest/', None), } # Options for LaTeX output From 97a71f80d63924f60faff7eac1bc91cf3c41a926 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 2 May 2016 13:08:56 -0700 Subject: [PATCH 0283/4859] Also update .ipynb examples and Readme --- README.rst | 2 +- examples/IPython Kernel/Third Party Rich Output.ipynb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2ba75a49998..9da53f02b44 100644 --- a/README.rst +++ b/README.rst @@ -28,7 +28,7 @@ these manuals. If you have Sphinx installed, you can build them by typing See the `install page `__ to install IPython. The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*. -See the `Jupyter installation docs `__ +See the `Jupyter installation docs `__ if you want to use these. Officially, IPython requires Python version 2.7, or 3.3 and above. diff --git a/examples/IPython Kernel/Third Party Rich Output.ipynb b/examples/IPython Kernel/Third Party Rich Output.ipynb index a0a137c4bec..e0403107c1e 100644 --- a/examples/IPython Kernel/Third Party Rich Output.ipynb +++ b/examples/IPython Kernel/Third Party Rich Output.ipynb @@ -354,7 +354,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "[Vincent](https://vincent.readthedocs.org/en/latest/) is a visualization library that uses the [Vega](http://trifacta.github.io/vega/) visualization grammar to build [d3.js](http://d3js.org/) based visualizations in the Notebook and on http://nbviewer.ipython.org. `Visualization` objects in Vincetn have rich HTML and JavaSrcript representations." + "[Vincent](https://vincent.readthedocs.io/en/latest/) is a visualization library that uses the [Vega](http://trifacta.github.io/vega/) visualization grammar to build [d3.js](http://d3js.org/) based visualizations in the Notebook and on http://nbviewer.ipython.org. `Visualization` objects in Vincetn have rich HTML and JavaSrcript representations." ] }, { From f8225dae558653f4d04a55283493757e9bcbf297 Mon Sep 17 00:00:00 2001 From: Kelly Liu Date: Mon, 4 Apr 2016 15:51:39 -0700 Subject: [PATCH 0284/4859] Initial patch with Jedi completion (no function header description). Handle case when Jedi is not importable. Fix print statement vs function discrepancy. Add two-column display for function and description, remove sys.path manipulation. cleanup comments, add matcher APi instead of checking every time (#1) * Improve completion a bit to take care of what was previously "greedy" This is a bit hackins because of how IPython decides what is going to be replaced, and because completions need to strart with `text`. Add a few test cases. * require path.py * Add completion tests. * Fix some completion, in particular imports. Also completion after assignments. Add TODO about how to using Completions with Jedi. --- IPython/core/completer.py | 100 +++++++++++++++++++++------ IPython/core/tests/test_completer.py | 50 ++++++++------ IPython/terminal/ptshell.py | 6 +- setup.py | 3 +- 4 files changed, 114 insertions(+), 45 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 86ba87e77cc..97a8d446ed8 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -53,6 +53,8 @@ # Some of this code originated from rlcompleter in the Python standard library # Copyright (C) 2001 Python Software Foundation, www.python.org +from __future__ import print_function + import __main__ import glob import inspect @@ -76,6 +78,14 @@ from IPython.utils.py3compat import builtin_mod, string_types, PY3 from traitlets import CBool, Enum +try: + import jedi + import jedi.api.helpers + import jedi.parser.user_context + JEDI_INSTALLED = True +except ImportError: + JEDI_INSTALLED = False + #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -267,6 +277,7 @@ class Completer(Configurable): greedy = CBool(False, config=True, help="""Activate greedy completion + PENDING DEPRECTION. this is now mostly taken care of with Jedi. This will enable completion on elements of lists, results of function calls, etc., but can be unsafe because the code is actually evaluated on TAB. @@ -277,7 +288,7 @@ class Completer(Configurable): def __init__(self, namespace=None, global_namespace=None, **kwargs): """Create a new completer for the command line. - Completer(namespace=ns,global_namespace=ns2) -> completer instance. + Completer(namespace=ns, global_namespace=ns2) -> completer instance. If unspecified, the default namespace where completions are performed is __main__ (technically, __main__.__dict__). Namespaces should be @@ -337,7 +348,6 @@ def global_matches(self, text): defined in self.namespace or self.global_namespace that match. """ - #print 'Completer->global_matches, txt=%r' % text # dbg matches = [] match_append = matches.append n = len(text) @@ -364,7 +374,6 @@ def attr_matches(self, text): """ - #io.rprint('Completer->attr_matches, txt=%r' % text) # dbg # Another option, seems to work great. Catches things like ''. m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text) @@ -564,7 +573,10 @@ def _greedy_changed(self, name, old, new): """ ) limit_to__all__ = CBool(default_value=False, config=True, - help="""Instruct the completer to use __all__ for the completion + help=""" + DEPRECATED as of version 5.0. + + Instruct the completer to use __all__ for the completion Specifically, when completing on ``object.``. @@ -573,6 +585,9 @@ def _greedy_changed(self, name, old, new): When False [default]: the __all__ attribute is ignored """ ) + use_jedi_completions = CBool(default_value=JEDI_INSTALLED, config=True, + help="""Use Jedi to generate autocompletions. + """) def __init__(self, shell=None, namespace=None, global_namespace=None, use_readline=True, config=None, **kwargs): @@ -639,7 +654,7 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, #= re.compile(r'[\s|\[]*(\w+)(?:\s*=?\s*.*)') # All active matcher routines for completion - self.matchers = [self.python_matches, + self.matchers = [ self.file_matches, self.magic_matches, self.python_func_kw_matches, @@ -653,7 +668,7 @@ def all_completions(self, text): """ return self.complete(text)[1] - def _clean_glob(self,text): + def _clean_glob(self, text): return self.glob("%s*" % text) def _clean_glob_win32(self,text): @@ -674,8 +689,6 @@ def file_matches(self, text): current (as of Python 2.3) Python readline it's possible to do better.""" - #io.rprint('Completer->file_matches: <%r>' % text) # dbg - # chars that require escaping with backslash - i.e. chars # that readline treats incorrectly as delimiters, but we # don't want to treat as delimiters in filename matching @@ -737,15 +750,12 @@ def file_matches(self, text): matches = [text_prefix + protect_filename(f) for f in m0] - #io.rprint('mm', matches) # dbg - # Mark directories in input list by appending '/' to their names. matches = [x+'/' if os.path.isdir(x) else x for x in matches] return matches def magic_matches(self, text): """Match magics""" - #print 'Completer->magic_matches:',text,'lb',self.text_until_cursor # dbg # Get all shell magics now rather than statically, so magics loaded at # runtime show up too. lsm = self.shell.magics_manager.lsmagic() @@ -765,10 +775,62 @@ def magic_matches(self, text): comp += [ pre+m for m in line_magics if m.startswith(bare_text)] return comp - def python_matches(self,text): - """Match attributes or global python names""" + def python_jedi_matches(self, text, line_buffer, cursor_pos): + """Match attributes or global Python names using Jedi.""" + if line_buffer.startswith('aimport ') or line_buffer.startswith('%aimport '): + return () + namespaces = [] + if self.namespace is None: + import __main__ + namespaces.append(__main__.__dict__) + else: + namespaces.append(self.namespace) + if self.global_namespace is not None: + namespaces.append(self.global_namespace) + + # cursor_pos is an it, jedi wants line and column + + interpreter = jedi.Interpreter(line_buffer, namespaces, column=cursor_pos) + path = jedi.parser.user_context.UserContext(line_buffer, \ + (1, len(line_buffer))).get_path_until_cursor() + path, dot, like = jedi.api.helpers.completion_parts(path) + if text.startswith('.'): + # text will be `.` on completions like `a[0].` + before = dot + else: + before = line_buffer[:len(line_buffer) - len(like)] + + + def trim_start(completion): + """completions need to start with `text`, trim the beginning until it does""" + if text in completion and not (completion.startswith(text)): + start_index = completion.index(text) + if cursor_pos: + assert start_index < cursor_pos + return completion[start_index:] + return completion - #io.rprint('Completer->python_matches, txt=%r' % text) # dbg + completions = interpreter.completions() + + completion_text = [c.name_with_symbols for c in completions] + + if self.omit__names: + if self.omit__names == 1: + # true if txt is _not_ a __ name, false otherwise: + no__name = lambda txt: not txt.startswith('__') + else: + # true if txt is _not_ a _ name, false otherwise: + no__name = lambda txt: not txt.startswith('_') + completion_text = filter(no__name, completion_text) + + + return [trim_start(before + c_text) for c_text in completion_text] + + + def python_matches(self, text): + """Match attributes or global python names""" + # Jedi completion + if "." in text: try: matches = self.attr_matches(text) @@ -1075,7 +1137,6 @@ def latex_matches(self, text): return u'', [] def dispatch_custom_completer(self, text): - #io.rprint("Custom! '%s' %s" % (text, self.custom_completers)) # dbg line = self.line_buffer if not line.strip(): return None @@ -1089,8 +1150,6 @@ def dispatch_custom_completer(self, text): event.command = cmd event.text_until_cursor = self.text_until_cursor - #print "\ncustom:{%s]\n" % event # dbg - # for foo etc, try also to find completer for %foo if not cmd.startswith(self.magic_escape): try_magic = self.custom_completers.s_matches( @@ -1101,7 +1160,6 @@ def dispatch_custom_completer(self, text): for c in itertools.chain(self.custom_completers.s_matches(cmd), try_magic, self.custom_completers.flat_matches(self.text_until_cursor)): - #print "try",c # dbg try: res = c(event) if res: @@ -1147,8 +1205,6 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): matches : list A list of completion matches. """ - # io.rprint('\nCOMP1 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg - # if the cursor position isn't given, the only sane assumption we can # make is that it's at the end of the line (the common case) if cursor_pos is None: @@ -1177,7 +1233,6 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): self.line_buffer = line_buffer self.text_until_cursor = self.line_buffer[:cursor_pos] - # io.rprint('COMP2 %r %r %r' % (text, line_buffer, cursor_pos)) # dbg # Start with a clean slate of completions self.matches[:] = [] @@ -1207,10 +1262,11 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): # different types of objects. The rlcomplete() method could then # simply collapse the dict into a list for readline, but we'd have # richer completion semantics in other evironments. + if self.use_jedi_completions: + self.matches.extend(self.python_jedi_matches(text, line_buffer, cursor_pos)) self.matches = sorted(set(self.matches), key=completions_sorting_key) - #io.rprint('COMP TEXT, MATCHES: %r, %r' % (text, self.matches)) # dbg return text, self.matches def rlcomplete(self, text, state): diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 8d6f4f06f1f..91f06dd85af 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -181,7 +181,7 @@ def test_no_ascii_back_completion(): ip = get_ipython() with TemporaryWorkingDirectory(): # Avoid any filename completions # single ascii letter that don't have yet completions - for letter in 'fjqyJMQVWY' : + for letter in 'jJ' : name, matches = ip.complete('\\'+letter) nt.assert_equal(matches, []) @@ -264,19 +264,36 @@ def test_local_file_completions(): # Now check with a function call cmd = 'a = f("%s' % prefix c = ip.complete(prefix, cmd)[1] - comp = [prefix+s for s in suffixes] - nt.assert_equal(c, comp) + comp = set(prefix+s for s in suffixes) + nt.assert_true(comp.issubset(set(c))) def test_greedy_completions(): ip = get_ipython() ip.ex('a=list(range(5))') _,c = ip.complete('.',line='a[0].') - nt.assert_false('a[0].real' in c, + nt.assert_false('.real' in c, "Shouldn't have completed on a[0]: %s"%c) with greedy_completion(): - _,c = ip.complete('.',line='a[0].') - nt.assert_true('a[0].real' in c, "Should have completed on a[0]: %s"%c) + def _(line, cursor_pos, expect, message): + _,c = ip.complete('.', line=line, cursor_pos=cursor_pos) + nt.assert_in(expect, c, message%c) + + yield _, 'a[0].', 5, '.real', "Should have completed on a[0].: %s" + yield _, 'a[0].r', 6, '.real', "Should have completed on a[0].r: %s" + + if sys.version_info > (3,4): + yield _, 'a[0].from_', 10, '.from_bytes', "Should have completed on a[0].from_: %s" + + + def _2(): + # jedi bug, this will be empty, makeitfail for now, + # once jedi is fixed, switch to assert_in + # https://github.com/davidhalter/jedi/issues/718 + _,c = ip.complete('.',line='a[0].from', cursor_pos=9) + nt.assert_not_in('.from_bytes', c, "Should not have completed on a[0].from (jedi bug), if fails, update test to assert_in: %s"%c) + yield _2 + def test_omit__names(): @@ -321,20 +338,6 @@ def test_limit_to__all__False_ok(): nt.assert_in('d.x', matches) -def test_limit_to__all__True_ok(): - ip = get_ipython() - c = ip.Completer - ip.ex('class D: x=24') - ip.ex('d=D()') - ip.ex("d.__all__=['z']") - cfg = Config() - cfg.IPCompleter.limit_to__all__ = True - c.update_config(cfg) - s, matches = c.complete('d.') - nt.assert_in('d.z', matches) - nt.assert_not_in('d.x', matches) - - def test_get__all__entries_ok(): class A(object): __all__ = ['x', 1] @@ -366,7 +369,6 @@ def test_func_kw_completions(): def test_default_arguments_from_docstring(): - doc = min.__doc__ ip = get_ipython() c = ip.Completer kwd = c._default_arguments_from_docstring( @@ -783,6 +785,12 @@ def test_aimport_module_completer(): nt.assert_in('io', matches) nt.assert_not_in('int', matches) +def test_nested_import_module_completer(): + ip = get_ipython() + _, matches = ip.complete(None, 'import IPython.co', 17) + nt.assert_in('IPython.core', matches) + nt.assert_not_in('import IPython.core', matches) + def test_import_module_completer(): ip = get_ipython() _, matches = ip.complete('i', 'import i') diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4fe61886e1c..822029b74d6 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -49,9 +49,13 @@ def get_completions(self, document, complete_event): ) start_pos = -len(used) for m in matches: + # TODO: Use Jedi to determine meta_text + # (Jedi currently has a bug that results in incorrect information.) + # meta_text = '' + # yield Completion(m, start_position=start_pos, + # display_meta=meta_text) yield Completion(m, start_position=start_pos) - class IPythonPTLexer(Lexer): """ Wrapper around PythonLexer and BashLexer. diff --git a/setup.py b/setup.py index b9eb698db33..b9293b18714 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'path.py'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], @@ -191,6 +191,7 @@ def run(self): ) install_requires = [ 'setuptools>=18.5', + 'jedi', 'decorator', 'pickleshare', 'simplegeneric>0.8', From 57f4bce64e78558e3ca44524d462d013961e1217 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 2 May 2016 16:16:06 -0700 Subject: [PATCH 0285/4859] Restore `%kill_embedded` for multiple IPython embed call. Closes #9063. Inspect frame and store the current file & line reference of the current call. Calling kill_embed subsequently store this in a set of deactivated reference. --- IPython/terminal/embed.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index aa43ca451be..d893c48be15 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -39,8 +39,7 @@ def kill_embedded(self, parameter_s=''): interfering again. """ - kill = ask_yes_no("Are you sure you want to kill this embedded instance " - "(y/n)? [y/N] ",'n') + kill = ask_yes_no("Are you sure you want to kill this embedded instance? [y/N] ",'n') if kill: self.shell.embedded_active = False print ("This embedded IPython will not reactivate anymore " @@ -66,13 +65,25 @@ class InteractiveShellEmbed(TerminalInteractiveShell): dummy_mode = Bool(False) exit_msg = Unicode('') embedded = CBool(True) - embedded_active = CBool(True) should_raise = CBool(False) # Like the base class display_banner is not configurable, but here it # is True by default. display_banner = CBool(True) exit_msg = Unicode() - + + _inactive_locations = set() + + @property + def embedded_active(self): + return self._call_location_id not in InteractiveShellEmbed._inactive_locations + + @embedded_active.setter + def embedded_active(self, value): + if value : + if self._call_location_id in InteractiveShellEmbed._inactive_locations: + InteractiveShellEmbed._inactive_locations.remove(self._call_location_id) + else: + InteractiveShellEmbed._inactive_locations.add(self._call_location_id) def __init__(self, **kw): @@ -81,8 +92,13 @@ def __init__(self, **kw): warnings.warn("user_global_ns has been replaced by user_module. The\ parameter will be ignored, and removed in IPython 5.0", DeprecationWarning) + self._call_location_id = kw.pop('_call_location_id', None) + super(InteractiveShellEmbed,self).__init__(**kw) + if not self._call_location_id: + frame = sys._getframe(1) + self._call_location_id = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) # don't use the ipython crash handler so that user exceptions aren't # trapped sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, @@ -298,7 +314,8 @@ def embed(**kwargs): if saved_shell_instance is not None: cls = type(saved_shell_instance) cls.clear_instance() - shell = InteractiveShellEmbed.instance(**kwargs) + frame = sys._getframe(1) + shell = InteractiveShellEmbed.instance(_call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno), **kwargs) shell(header=header, stack_depth=2, compile_flags=compile_flags) InteractiveShellEmbed.clear_instance() #restore previous instance From 74c08c9cf3d8b61b88a32a98ce622fb621fd546b Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Thu, 5 May 2016 17:07:06 +0200 Subject: [PATCH 0286/4859] Upgrade to prompt_toolkit 1.0.0. --- IPython/terminal/ptshell.py | 16 +++++++++------- setup.py | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index ba4fa669496..12b3f1f901d 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -16,14 +16,12 @@ from traitlets import Bool, CBool, Unicode, Dict, Integer from prompt_toolkit.completion import Completer, Completion -from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER -from prompt_toolkit.filters import HasFocus, HasSelection, Condition +from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode +from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager -from prompt_toolkit.key_binding.vi_state import InputMode -from prompt_toolkit.key_binding.bindings.vi import ViStateFilter from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer @@ -164,8 +162,8 @@ def prompt(): self.prompt_for_code = prompt return - kbmanager = KeyBindingManager.for_prompt(enable_vi_mode=self.vi_mode) - insert_mode = ViStateFilter(kbmanager.get_vi_state, InputMode.INSERT) + kbmanager = KeyBindingManager.for_prompt() + insert_mode = ViInsertMode() | EmacsInsertMode() # Ctrl+J == Enter, seemingly @kbmanager.registry.add_binding(Keys.ControlJ, filter=(HasFocus(DEFAULT_BUFFER) @@ -232,7 +230,10 @@ def _(event): self._style = self._make_style_from_name(self.highlighting_style) style = DynamicStyle(lambda: self._style) + editing_mode = EditingMode.VI if self.vi_mode else EditingMode.EMACS + self._app = create_prompt_application( + editing_mode=editing_mode, key_bindings_registry=kbmanager.registry, history=history, completer=IPythonPTCompleter(self.Completer), @@ -295,7 +296,8 @@ def _update_layout(self): self._app.layout = create_prompt_layout(**self._layout_options()) def prompt_for_code(self): - document = self.pt_cli.run(pre_run=self.pre_prompt) + document = self.pt_cli.run( + pre_run=self.pre_prompt, reset_current_buffer=True) return document.text def init_io(self): diff --git a/setup.py b/setup.py index 7e129a1ce2f..4aaaf6245b7 100755 --- a/setup.py +++ b/setup.py @@ -195,7 +195,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets', - 'prompt_toolkit>=0.60', + 'prompt_toolkit>=1.0.0,<2.0.0', 'pygments', ] From b67379d754695af5a7d0d21fcf2eff391675824e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 5 May 2016 09:10:14 -0700 Subject: [PATCH 0287/4859] Remove unnecessary test dependency. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e4d0c0387a5..2e2be855772 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'path.py'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], From 77528f4f29d2406c95c058b84a925e299d7c502b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 5 May 2016 18:18:54 +0100 Subject: [PATCH 0288/4859] Configure editing_mode instead of vi_mode This makes life easier if prompt_toolkit gains any extra modes. --- IPython/terminal/ptshell.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c451846cc31..2c9deb7638f 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -108,8 +108,8 @@ def _space_for_menu_changed(self, old, new): in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", ) - vi_mode = Bool(False, config=True, - help="Use vi style keybindings at the prompt", + editing_mode = Unicode('emacs', config=True, + help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", ) mouse_support = Bool(False, config=True, @@ -234,7 +234,7 @@ def _(event): self._style = self._make_style_from_name(self.highlighting_style) style = DynamicStyle(lambda: self._style) - editing_mode = EditingMode.VI if self.vi_mode else EditingMode.EMACS + editing_mode = getattr(EditingMode, self.editing_mode.upper()) self._app = create_prompt_application( editing_mode=editing_mode, From df2541f86a98f14c36092c7dac8e3b6789d03b77 Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Thu, 5 May 2016 19:25:37 +0200 Subject: [PATCH 0289/4859] Added display_completions_in_columns option. --- IPython/terminal/ptshell.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c451846cc31..f19bf00f3bf 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -134,6 +134,11 @@ def _highlighting_style_changed(self, old, new): term_title = Bool(True, config=True, help="Automatically set the terminal title" ) + + display_completions_in_columns = Bool(False, config=True, + help="Display a multi column completion menu.", + ) + def _term_title_changed(self, name, new_value): self.init_term_title() @@ -289,9 +294,9 @@ def _layout_options(self): 'get_prompt_tokens':self.get_prompt_tokens, 'get_continuation_tokens':self.get_continuation_tokens, 'multiline':True, + 'display_completions_in_columns': self.display_completions_in_columns, } - def _update_layout(self): """ Ask for a re computation of the application layout, if for example , From bd25cb0cc66c5ff23fa7cc66cf0893513ac4b2bc Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 5 May 2016 13:52:49 -0700 Subject: [PATCH 0290/4859] Fix completions for PTK 1.0 --- IPython/core/completer.py | 9 ++++++--- IPython/core/tests/test_completer.py | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 8e3ecc7ef9c..1f612d54a7b 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -803,10 +803,13 @@ def python_jedi_matches(self, text, line_buffer, cursor_pos): def trim_start(completion): """completions need to start with `text`, trim the beginning until it does""" - if text in completion and not (completion.startswith(text)): - start_index = completion.index(text) + ltext = text.lower() + lcomp = completion.lower() + if ltext in lcomp and not (lcomp.startswith(ltext)): + start_index = lcomp.index(ltext) if cursor_pos: - assert start_index < cursor_pos + if start_index >= cursor_pos: + start_index = min(start_index, cursor_pos) return completion[start_index:] return completion diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index b0f90eca5ac..1ef7d3f4c9d 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -800,6 +800,6 @@ def test_import_module_completer(): def test_from_module_completer(): ip = get_ipython() - _, matches = ip.complete('B', 'from io import B') + _, matches = ip.complete('B', 'from io import B', 16) nt.assert_in('BytesIO', matches) nt.assert_not_in('BaseException', matches) From af70652321c64a743b856f8f5e7da2cc2ee8198b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 5 May 2016 15:44:39 -0700 Subject: [PATCH 0291/4859] Require recent enough traitlets so we can start to force the new `.tag()` syntax. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8902e8ab913..b0c015184a8 100755 --- a/setup.py +++ b/setup.py @@ -195,7 +195,7 @@ def run(self): 'decorator', 'pickleshare', 'simplegeneric>0.8', - 'traitlets', + 'traitlets>=4.2', 'prompt_toolkit>=1.0.0,<2.0.0', 'pygments', ] From ad6971090fae56c8584c97e7cf86f98f61685dad Mon Sep 17 00:00:00 2001 From: Jonathan Frederic Date: Fri, 6 May 2016 08:35:15 -0700 Subject: [PATCH 0292/4859] Add %%js alias for %%javascript --- IPython/core/magics/display.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/IPython/core/magics/display.py b/IPython/core/magics/display.py index d9eacb2274f..e08fef304ca 100644 --- a/IPython/core/magics/display.py +++ b/IPython/core/magics/display.py @@ -25,24 +25,29 @@ @magics_class class DisplayMagics(Magics): """Magics for displaying various output types with literals - - Defines javascript/latex/svg/html cell magics for writing + + Defines javascript/latex/svg/html cell magics for writing blocks in those languages, to be rendered in the frontend. """ - + + @cell_magic + def js(self, line, cell): + """Run the cell block of Javascript code""" + self.javascript(line, cell) + @cell_magic def javascript(self, line, cell): """Run the cell block of Javascript code""" display(Javascript(cell)) - - + + @cell_magic def latex(self, line, cell): """Render the cell as a block of latex - + The subset of latex which is support depends on the implementation in - the client. In the Jupyter Notebook, this magic only renders the subset - of latex defined by MathJax + the client. In the Jupyter Notebook, this magic only renders the subset + of latex defined by MathJax [here](https://docs.mathjax.org/en/v2.5-latest/tex.html).""" display(Latex(cell)) From b51ccffc66ceb05fe21e2e4aa9880fb3e565a02a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 6 May 2016 11:10:05 -0700 Subject: [PATCH 0293/4859] Precise that %%js is an alias of %%javascript --- IPython/core/magics/display.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/core/magics/display.py b/IPython/core/magics/display.py index e08fef304ca..c4a8f44d9ab 100644 --- a/IPython/core/magics/display.py +++ b/IPython/core/magics/display.py @@ -32,7 +32,10 @@ class DisplayMagics(Magics): @cell_magic def js(self, line, cell): - """Run the cell block of Javascript code""" + """Run the cell block of Javascript code + + Alias of `%%javascript` + """ self.javascript(line, cell) @cell_magic From 85820d34555eef610d3a08e3b3b1d32c53804dcd Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 9 May 2016 13:33:09 -0700 Subject: [PATCH 0294/4859] "smart command mode" for ipdb (like pdb++). If e.g. "c" is a variable currently visible, then "c" should print it instead of running the "continue" Pdb command. This idea was first implemented by pdb++. It is possible to force the standard pdb behavior (bypass variable checking) by prefixing the command with "!!", e.g. "!!c" to continue. --- IPython/core/debugger.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 0f0c78a81fc..29770ce7e9e 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -311,6 +311,17 @@ def interaction(self, frame, traceback): if self.shell.readline is not None: self.shell.readline.set_completer_delims(self.shell.readline_delims) + def parseline(self, line): + if line.startswith("!!"): + # Force standard behavior. + return super(Pdb, self).parseline(line[2:]) + # "Smart command mode" from pdb++: don't execute commands if a variable + # with the same name exists. + cmd, arg, newline = super(Pdb, self).parseline(line) + if cmd in self.curframe.f_globals or cmd in self.curframe.f_locals: + return super(Pdb, self).parseline("!" + line) + return super(Pdb, self).parseline(line) + def new_do_up(self, arg): OldPdb.do_up(self, arg) self.shell.set_completer_frame(self.curframe) From 7b8ae1d31a805ebc7bb0f9a6ac6803a9535088fb Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 10 May 2016 08:24:24 -0700 Subject: [PATCH 0295/4859] Make Pdb a new-style class... --- IPython/core/debugger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 29770ce7e9e..cc3b3fbb28e 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -206,7 +206,7 @@ def _file_lines(fname): return out -class Pdb(OldPdb): +class Pdb(OldPdb, object): """Modified Pdb class, does not load readline.""" def __init__(self,color_scheme='NoColor',completekey=None, From 01b33dc418e455832b2352be22a024fd6e0c91db Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Tue, 10 May 2016 11:46:20 -0400 Subject: [PATCH 0296/4859] MNT: only try to use mpl.use if safe If the library you are documenting sets the backend and imports mpl this `use` will spam the doc build with warnings. This guards the call the same way it is done above. --- IPython/sphinxext/ipython_directive.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index cde36cf4829..eb1219fe01d 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -881,10 +881,8 @@ def setup(self): # EmbeddedSphinxShell is created, its interactive shell member # is the same for each instance. - if mplbackend: + if mplbackend and 'matplotlib.backends' not in sys.modules: import matplotlib - # Repeated calls to use() will not hurt us since `mplbackend` - # is the same each time. matplotlib.use(mplbackend) # Must be called after (potentially) importing matplotlib and From 68860ee51dbd7504abae05c4031eed5146a677e5 Mon Sep 17 00:00:00 2001 From: Craig Citro Date: Tue, 10 May 2016 17:25:12 -0700 Subject: [PATCH 0297/4859] Make event triggering robust to (un)registration. Event callbacks can register or unregister new callbacks for the same event while executing, and the previous triggering implementation allowed for event callbacks to be inadvertently skipped. The fix is to make a copy of the list of callbacks before executing any of them. With this change, the resulting semantics are simple: any callbacks registered before triggering are executed, and any new callbacks registered are only visible at the next triggering of the event. Note that this could potentially break existing callers who expected newly-appended callbacks were immediately executed. Fixes #9447. Originally based on a patch by @marksandler2. --- IPython/core/events.py | 2 +- IPython/core/tests/test_events.py | 22 +++++++++++++++++++ .../whatsnew/pr/incompat-event-triggering.rst | 7 ++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 docs/source/whatsnew/pr/incompat-event-triggering.rst diff --git a/IPython/core/events.py b/IPython/core/events.py index 798ef01124c..bfd09fec6a7 100644 --- a/IPython/core/events.py +++ b/IPython/core/events.py @@ -69,7 +69,7 @@ def trigger(self, event, *args, **kwargs): Any additional arguments are passed to all callbacks registered for this event. Exceptions raised by callbacks are caught, and a message printed. """ - for func in self.callbacks[event]: + for func in self.callbacks[event][:]: try: func(*args, **kwargs) except Exception: diff --git a/IPython/core/tests/test_events.py b/IPython/core/tests/test_events.py index 8e8402c364d..3053a705a7f 100644 --- a/IPython/core/tests/test_events.py +++ b/IPython/core/tests/test_events.py @@ -30,3 +30,25 @@ def test_cb_error(self): self.em.register('ping_received', cb) with tt.AssertPrints("Error in callback"): self.em.trigger('ping_received') + + def test_unregister_during_callback(self): + invoked = [False] * 3 + + def func1(*_): + invoked[0] = True + self.em.unregister('ping_received', func1) + self.em.register('ping_received', func3) + + def func2(*_): + invoked[1] = True + self.em.unregister('ping_received', func2) + + def func3(*_): + invoked[2] = True + + self.em.register('ping_received', func1) + self.em.register('ping_received', func2) + + self.em.trigger('ping_received') + self.assertEqual([True, True, False], invoked) + self.assertEqual([func3], self.em.callbacks['ping_received']) diff --git a/docs/source/whatsnew/pr/incompat-event-triggering.rst b/docs/source/whatsnew/pr/incompat-event-triggering.rst new file mode 100644 index 00000000000..432af687df5 --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-event-triggering.rst @@ -0,0 +1,7 @@ +Update IPython event triggering to ensure callback registration and +unregistration only affects the set of callbacks the *next* time that event is +triggered. See :ghissue:`9447` and :ghpull:`9453`. + +This is a change to the existing semantics, wherein one callback registering a +second callback when triggered for an event would previously be invoked for +that same event. From 970a08d5acd69882873c3b6d0462261701cd098b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 12 May 2016 13:36:34 +0100 Subject: [PATCH 0298/4859] Explicitly close prompt_toolkit event loop after running This is recommended, see jonathanslenders/python-prompt-toolkit#287. Normally it won't matter, because we close it just before the process exits, but if someone is embedding it repeatedly it could leave pipes lingering. --- IPython/terminal/ptshell.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3a7e9a6f3d8..7751a055065 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -251,8 +251,8 @@ def _(event): mouse_support=self.mouse_support, **self._layout_options() ) - self.pt_cli = CommandLineInterface(self._app, - eventloop=create_eventloop(self.inputhook)) + self._eventloop = create_eventloop(self.inputhook) + self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop) def _make_style_from_name(self, name): """ @@ -383,6 +383,8 @@ def mainloop(self): except KeyboardInterrupt: print("\nKeyboardInterrupt escaped interact()\n") + self._eventloop.close() + _inputhook = None def inputhook(self, context): if self._inputhook is not None: From 3c4b9cd08d8a3471e66a974219331b15085fde87 Mon Sep 17 00:00:00 2001 From: Adrian Date: Thu, 12 May 2016 17:34:53 +0200 Subject: [PATCH 0299/4859] Do not use `is` for string comparison --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3a7e9a6f3d8..ee8048ff102 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -265,7 +265,7 @@ def _make_style_from_name(self, name): Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', } - if name is 'default': + if name == 'default': style_cls = get_style_by_name('default') # The default theme needs to be visible on both a dark background # and a light background, because we can't tell what the terminal From cbab6e8863b09fde88f43dc2bb0265e8b2e575eb Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 16 May 2016 15:55:50 +0100 Subject: [PATCH 0300/4859] Don't catch failure to import Jedi Jedi is a dependency now - if it isn't installed, we should fail clearly rather than silently skipping completions. --- IPython/core/completer.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 1f612d54a7b..74d007a095a 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -77,13 +77,9 @@ from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 from traitlets import CBool, Enum -try: - import jedi - import jedi.api.helpers - import jedi.parser.user_context - JEDI_INSTALLED = True -except ImportError: - JEDI_INSTALLED = False +import jedi +import jedi.api.helpers +import jedi.parser.user_context #----------------------------------------------------------------------------- # Globals @@ -586,9 +582,6 @@ def _greedy_changed(self, name, old, new): When False [default]: the __all__ attribute is ignored """ ) - use_jedi_completions = CBool(default_value=JEDI_INSTALLED, config=True, - help="""Use Jedi to generate autocompletions. - """) def __init__(self, shell=None, namespace=None, global_namespace=None, use_readline=True, config=None, **kwargs): @@ -832,8 +825,6 @@ def trim_start(completion): def python_matches(self, text): """Match attributes or global python names""" - # Jedi completion - if "." in text: try: matches = self.attr_matches(text) @@ -1264,8 +1255,7 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): # different types of objects. The rlcomplete() method could then # simply collapse the dict into a list for readline, but we'd have # richer completion semantics in other evironments. - if self.use_jedi_completions: - self.matches.extend(self.python_jedi_matches(text, line_buffer, cursor_pos)) + self.matches.extend(self.python_jedi_matches(text, line_buffer, cursor_pos)) self.matches = sorted(set(self.matches), key=completions_sorting_key) From 2567fbb7e7832a3014d0990e1d7ec26ed308ff38 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 09:22:24 -0700 Subject: [PATCH 0301/4859] Update IPython/core/prompts.py to traitlets 4.2 API --- IPython/core/prompts.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index ffde2a0e2f5..0704f7f262c 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -31,7 +31,7 @@ from traitlets.config.configurable import Configurable from IPython.core import release from IPython.utils import coloransi, py3compat -from traitlets import (Unicode, Instance, Dict, Bool, Int) +from traitlets import Unicode, Instance, Dict, Bool, Int, observe from IPython.utils.PyColorize import LightBGColors, LinuxColors, NoColor @@ -256,9 +256,11 @@ class PromptManager(Configurable): shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) color_scheme_table = Instance(coloransi.ColorSchemeTable, allow_none=True) - color_scheme = Unicode('Linux', config=True) - def _color_scheme_changed(self, name, new_value): - self.color_scheme_table.set_active_scheme(new_value) + color_scheme = Unicode('Linux').tag(config=True) + + @observe('color_scheme') + def _color_scheme_changed(self, change): + self.color_scheme_table.set_active_scheme(change['new']) for pname in ['in', 'in2', 'out', 'rewrite']: # We need to recalculate the number of invisible characters self.update_prompt(pname) @@ -271,14 +273,14 @@ def _color_scheme_changed(self, name, new_value): """) def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() - in_template = Unicode('In [\\#]: ', config=True, + in_template = Unicode('In [\\#]: ').tag(config=True, help="Input prompt. '\\#' will be transformed to the prompt number") - in2_template = Unicode(' .\\D.: ', config=True, + in2_template = Unicode(' .\\D.: ').tag(config=True, help="Continuation prompt.") - out_template = Unicode('Out[\\#]: ', config=True, + out_template = Unicode('Out[\\#]: ').tag(config=True, help="Output prompt. '\\#' will be transformed to the prompt number") - justify = Bool(True, config=True, help=""" + justify = Bool(True).tag(config=True, help=""" If True (default), each prompt will be right-aligned with the preceding one. """) From 4fa9a27efe6bc6466f1ded18d0b88f7ee442d136 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 09:46:32 -0700 Subject: [PATCH 0302/4859] Update IPython/core/extensions.py to the new traitlets API --- IPython/core/extensions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/core/extensions.py b/IPython/core/extensions.py index cd1dd594a45..5c05d46254d 100644 --- a/IPython/core/extensions.py +++ b/IPython/core/extensions.py @@ -49,13 +49,13 @@ def load_ipython_extension(ipython): is added to ``sys.path`` automatically. """ - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC').tag( allow_none=True) def __init__(self, shell=None, **kwargs): super(ExtensionManager, self).__init__(shell=shell, **kwargs) - self.shell.on_trait_change( - self._on_ipython_dir_changed, 'ipython_dir' + self.shell.observe( + self._on_ipython_dir_changed, names=('ipython_dir',) ) self.loaded = set() @@ -63,7 +63,7 @@ def __init__(self, shell=None, **kwargs): def ipython_extension_dir(self): return os.path.join(self.shell.ipython_dir, u'extensions') - def _on_ipython_dir_changed(self): + def _on_ipython_dir_changed(self, change): ensure_dir_exists(self.ipython_extension_dir) def load_extension(self, module_str): From 45354c1f3d405dd4a5692af4490ab5e072ba2569 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 10:12:32 -0700 Subject: [PATCH 0303/4859] Update IPython/core/historyapp.py to use the new traitlets API. --- IPython/core/historyapp.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/IPython/core/historyapp.py b/IPython/core/historyapp.py index 5f61eac8ceb..7a4bd32f90d 100644 --- a/IPython/core/historyapp.py +++ b/IPython/core/historyapp.py @@ -34,15 +34,15 @@ class HistoryTrim(BaseIPythonApplication): description = trim_hist_help - backup = Bool(False, config=True, + backup = Bool(False).tag(config=True, help="Keep the old history file as history.sqlite.") - keep = Int(1000, config=True, + keep = Int(1000).tag(config=True, help="Number of recent lines to keep in the database.") flags = Dict(dict( backup = ({'HistoryTrim' : {'backup' : True}}, - backup.get_metadata('help') + backup.help ) )) @@ -118,17 +118,17 @@ def start(self): class HistoryClear(HistoryTrim): description = clear_hist_help - keep = Int(0, config=False, + keep = Int(0).tag(config=False, help="Number of recent lines to keep in the database.") - force = Bool(False, config=True, + force = Bool(False).tag(config=True, help="Don't prompt user for confirmation") flags = Dict(dict( force = ({'HistoryClear' : {'force' : True}}, - force.get_metadata('help')), + force.help), f = ({'HistoryTrim' : {'force' : True}}, - force.get_metadata('help') + force.help ) )) aliases = Dict() From b2876b642a34c904392d8c859ad74a737ec0bf78 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 18:12:26 -0700 Subject: [PATCH 0304/4859] Update IPython/core/prefilter to new traitlets API. also remove an unused variable. --- IPython/core/prefilter.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 16032d0c53b..7f01addc3d2 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -129,7 +129,7 @@ class PrefilterManager(Configurable): or :meth:`sort_transformers` method after changing the priority. """ - multi_line_specials = CBool(True, config=True) + multi_line_specials = CBool(True).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): @@ -359,12 +359,12 @@ def prefilter_lines(self, lines, continue_prompt=False): class PrefilterTransformer(Configurable): """Transform a line of user input.""" - priority = Integer(100, config=True) + priority = Integer(100).tag(config=True) # Transformers don't currently use shell or prefilter_manager, but as we # move away from checkers and handlers, they will need them. shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True) - enabled = Bool(True, config=True) + enabled = Bool(True).tag(config=True) def __init__(self, shell=None, prefilter_manager=None, **kwargs): super(PrefilterTransformer, self).__init__( @@ -389,10 +389,10 @@ def __repr__(self): class PrefilterChecker(Configurable): """Inspect an input line and return a handler for that line.""" - priority = Integer(100, config=True) + priority = Integer(100).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) prefilter_manager = Instance('IPython.core.prefilter.PrefilterManager', allow_none=True) - enabled = Bool(True, config=True) + enabled = Bool(True).tag(config=True) def __init__(self, shell=None, prefilter_manager=None, **kwargs): super(PrefilterChecker, self).__init__( @@ -411,8 +411,8 @@ def __repr__(self): class EmacsChecker(PrefilterChecker): - priority = Integer(100, config=True) - enabled = Bool(False, config=True) + priority = Integer(100).tag(config=True) + enabled = Bool(False).tag(config=True) def check(self, line_info): "Emacs ipython-mode tags certain input lines." @@ -424,7 +424,7 @@ def check(self, line_info): class MacroChecker(PrefilterChecker): - priority = Integer(250, config=True) + priority = Integer(250).tag(config=True) def check(self, line_info): obj = self.shell.user_ns.get(line_info.ifun) @@ -436,7 +436,7 @@ def check(self, line_info): class IPyAutocallChecker(PrefilterChecker): - priority = Integer(300, config=True) + priority = Integer(300).tag(config=True) def check(self, line_info): "Instances of IPyAutocall in user_ns get autocalled immediately" @@ -450,7 +450,7 @@ def check(self, line_info): class AssignmentChecker(PrefilterChecker): - priority = Integer(600, config=True) + priority = Integer(600).tag(config=True) def check(self, line_info): """Check to see if user is assigning to a var for the first time, in @@ -468,7 +468,7 @@ def check(self, line_info): class AutoMagicChecker(PrefilterChecker): - priority = Integer(700, config=True) + priority = Integer(700).tag(config=True) def check(self, line_info): """If the ifun is magic, and automagic is on, run it. Note: normal, @@ -492,7 +492,7 @@ def check(self, line_info): class PythonOpsChecker(PrefilterChecker): - priority = Integer(900, config=True) + priority = Integer(900).tag(config=True) def check(self, line_info): """If the 'rest' of the line begins with a function call or pretty much @@ -507,11 +507,11 @@ def check(self, line_info): class AutocallChecker(PrefilterChecker): - priority = Integer(1000, config=True) + priority = Integer(1000).tag(config=True) - function_name_regexp = CRegExp(re_fun_name, config=True, + function_name_regexp = CRegExp(re_fun_name).tag(config=True, help="RegExp to identify potential function names.") - exclude_regexp = CRegExp(re_exclude_auto, config=True, + exclude_regexp = CRegExp(re_exclude_auto).tag(config=True, help="RegExp to exclude strings with this start from autocalling.") def check(self, line_info): @@ -611,11 +611,9 @@ def handle(self, line_info): line = line_info.line ifun = line_info.ifun the_rest = line_info.the_rest - pre = line_info.pre esc = line_info.esc continue_prompt = line_info.continue_prompt obj = line_info.ofind(self.shell)['obj'] - #print 'pre <%s> ifun <%s> rest <%s>' % (pre,ifun,the_rest) # dbg # This should only be active for single-line input! if continue_prompt: From 1cb3dbb25871e6ba4af1195723fc4190af489ee6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 18:17:07 -0700 Subject: [PATCH 0305/4859] Update IPython/core/formatters.py to use new traitlets API. Also remove an unused import. --- IPython/core/formatters.py | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 62d296f6716..237a2d713c1 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -11,7 +11,6 @@ # Distributed under the terms of the Modified BSD License. import abc -import inspect import json import sys import traceback @@ -36,7 +35,7 @@ class DisplayFormatter(Configurable): # When set to true only the default plain text formatter will be used. - plain_text_only = Bool(False, config=True) + plain_text_only = Bool(False).tag(config=True) def _plain_text_only_changed(self, name, old, new): warnings.warn("""DisplayFormatter.plain_text_only is deprecated. @@ -50,7 +49,7 @@ def _plain_text_only_changed(self, name, old, new): else: self.active_types = self.format_types - active_types = List(Unicode(), config=True, + active_types = List(Unicode()).tag(config=True, help="""List of currently active mime-types to display. You can use this to set a white-list for formats to display. @@ -288,21 +287,21 @@ class BaseFormatter(Configurable): format_type = Unicode('text/plain') _return_type = string_types - enabled = Bool(True, config=True) + enabled = Bool(True).tag(config=True) print_method = ObjectName('__repr__') # The singleton printers. # Maps the IDs of the builtin singleton objects to the format functions. - singleton_printers = Dict(config=True) + singleton_printers = Dict().tag(config=True) # The type-specific printers. # Map type objects to the format functions. - type_printers = Dict(config=True) + type_printers = Dict().tag(config=True) # The deferred-import type-specific printers. # Map (modulename, classname) pairs to the format functions. - deferred_printers = Dict(config=True) + deferred_printers = Dict().tag(config=True) @catch_format_error def __call__(self, obj): @@ -569,9 +568,9 @@ def dtype_pprinter(obj, p, cycle): # This subclass ignores this attribute as it always need to return # something. - enabled = Bool(True, config=False) + enabled = Bool(True).tag(config=False) - max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, config=True, + max_seq_length = Integer(pretty.MAX_SEQ_LENGTH).tag(config=True, help="""Truncate large collections (lists, dicts, tuples, sets) to this size. Set to 0 to disable truncation. @@ -582,21 +581,21 @@ def dtype_pprinter(obj, p, cycle): print_method = ObjectName('_repr_pretty_') # Whether to pretty-print or not. - pprint = Bool(True, config=True) + pprint = Bool(True).tag(config=True) # Whether to be verbose or not. - verbose = Bool(False, config=True) + verbose = Bool(False).tag(config=True) # The maximum width. - max_width = Integer(79, config=True) + max_width = Integer(79).tag(config=True) # The newline character. - newline = Unicode('\n', config=True) + newline = Unicode('\n').tag(config=True) # format-string for pprinting floats float_format = Unicode('%r') # setter for float precision, either int or direct format-string - float_precision = CUnicode('', config=True) + float_precision = CUnicode('').tag(config=True) def _float_precision_changed(self, name, old, new): """float_precision changed, set float_format accordingly. From ed6c2203f55c974dc687ae4e5a2adfc282afa510 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 18:21:39 -0700 Subject: [PATCH 0306/4859] Do not redefine _, linter complain. It also confuse me as I search for `def _(` and there is no cost of being explicit. --- IPython/terminal/ptshell.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index ee8048ff102..8e2b93f0e67 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -195,11 +195,11 @@ def _(event): b.insert_text('\n' + (' ' * (indent or 0))) @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) - def _(event): + def _reset_buffer(event): event.current_buffer.reset() @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) - def _(event): + def _reset_search_buffer(event): if event.current_buffer.document.text: event.current_buffer.reset() else: @@ -208,7 +208,7 @@ def _(event): supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) - def _(event): + def _suspend_to_bg(event): event.cli.suspend_to_background() @Condition @@ -223,13 +223,13 @@ def cursor_in_leading_ws(cli): & insert_mode & cursor_in_leading_ws )) - def _(event): + def _indent_buffer(event): event.current_buffer.insert_text(' ' * 4) # Pre-populate history from IPython's history database history = InMemoryHistory() last_cell = u"" - for _, _, cell in self.history_manager.get_tail(self.history_load_length, + for __, ___, cell in self.history_manager.get_tail(self.history_load_length, include_latest=True): # Ignore blank lines and consecutive duplicates cell = cell.rstrip() From 12d304f48296a2566dbe711472707824baccd22e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 16 May 2016 18:24:59 -0700 Subject: [PATCH 0307/4859] Update `ptshell.py` to use new traitlets API. --- IPython/terminal/ptshell.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 8e2b93f0e67..9c12e57f00a 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -13,7 +13,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from traitlets import Bool, CBool, Unicode, Dict, Integer +from traitlets import Bool, CBool, Unicode, Dict, Integer, observe from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode @@ -91,7 +91,7 @@ def lex_document(self, cli, document): class TerminalInteractiveShell(InteractiveShell): colors_force = True - space_for_menu = Integer(6, config=True, help='Number of line at the bottom of the screen ' + space_for_menu = Integer(6).tag(config=True, help='Number of line at the bottom of the screen ' 'to reserve for the completion menu') def _space_for_menu_changed(self, old, new): @@ -99,47 +99,48 @@ def _space_for_menu_changed(self, old, new): pt_cli = None - autoedit_syntax = CBool(False, config=True, + autoedit_syntax = CBool(False).tag(config=True, help="auto editing of files with syntax errors.") - confirm_exit = CBool(True, config=True, + confirm_exit = CBool(True).tag(config=True, help=""" Set to confirm when you try to exit IPython with an EOF (Control-D in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", ) - editing_mode = Unicode('emacs', config=True, + editing_mode = Unicode('emacs').tag(config=True, help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", ) - mouse_support = Bool(False, config=True, + mouse_support = Bool(False).tag(config=True, help="Enable mouse support in the prompt" ) - highlighting_style = Unicode('default', config=True, + highlighting_style = Unicode('default').tag(config=True, help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) ) def _highlighting_style_changed(self, old, new): self._style = self._make_style_from_name(self.highlighting_style) - highlighting_style_overrides = Dict(config=True, + highlighting_style_overrides = Dict().tag(config=True, help="Override highlighting format for specific tokens" ) - editor = Unicode(get_default_editor(), config=True, + editor = Unicode(get_default_editor()).tag(config=True, help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ) - term_title = Bool(True, config=True, + term_title = Bool(True).tag(config=True, help="Automatically set the terminal title" ) - display_completions_in_columns = Bool(False, config=True, + display_completions_in_columns = Bool(False).tag(config=True, help="Display a multi column completion menu.", ) - def _term_title_changed(self, name, new_value): + @observe('term_title') + def _term_title_changed(self, change): self.init_term_title() def init_term_title(self): From 58799824be6629568ffe2983ff89b2fa4c0a2c75 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 09:18:07 -0700 Subject: [PATCH 0308/4859] Fix Traitlets API 42. Help is in constructor, not tag. --- IPython/core/historyapp.py | 17 ++++++++++------- IPython/core/prompts.py | 20 +++++++++++--------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/IPython/core/historyapp.py b/IPython/core/historyapp.py index 7a4bd32f90d..d51426d2ca3 100644 --- a/IPython/core/historyapp.py +++ b/IPython/core/historyapp.py @@ -34,11 +34,13 @@ class HistoryTrim(BaseIPythonApplication): description = trim_hist_help - backup = Bool(False).tag(config=True, - help="Keep the old history file as history.sqlite.") + backup = Bool(False, + help="Keep the old history file as history.sqlite." + ).tag(config=True) - keep = Int(1000).tag(config=True, - help="Number of recent lines to keep in the database.") + keep = Int(1000, + help="Number of recent lines to keep in the database." + ).tag(config=True) flags = Dict(dict( backup = ({'HistoryTrim' : {'backup' : True}}, @@ -118,11 +120,12 @@ def start(self): class HistoryClear(HistoryTrim): description = clear_hist_help - keep = Int(0).tag(config=False, + keep = Int(0, help="Number of recent lines to keep in the database.") - force = Bool(False).tag(config=True, - help="Don't prompt user for confirmation") + force = Bool(False, + help="Don't prompt user for confirmation" + ).tag(config=True) flags = Dict(dict( force = ({'HistoryClear' : {'force' : True}}, diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index 0704f7f262c..eeb2e3fe286 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -273,17 +273,19 @@ def _color_scheme_changed(self, change): """) def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() - in_template = Unicode('In [\\#]: ').tag(config=True, - help="Input prompt. '\\#' will be transformed to the prompt number") - in2_template = Unicode(' .\\D.: ').tag(config=True, - help="Continuation prompt.") - out_template = Unicode('Out[\\#]: ').tag(config=True, - help="Output prompt. '\\#' will be transformed to the prompt number") - - justify = Bool(True).tag(config=True, help=""" + in_template = Unicode('In [\\#]: ', + help="Input prompt. '\\#' will be transformed to the prompt number" + ).tag(config=True) + in2_template = Unicode(' .\\D.: ', + help="Continuation prompt.").tag(config=True) + out_template = Unicode('Out[\\#]: ', + help="Output prompt. '\\#' will be transformed to the prompt number" + ).tag(config=True) + + justify = Bool(True, help=""" If True (default), each prompt will be right-aligned with the preceding one. - """) + """).tag(config=True) # We actually store the expanded templates here: templates = Dict() From 507bdb38daa337cbf74513b0076335921c82b5dd Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 09:26:21 -0700 Subject: [PATCH 0309/4859] Fix `help=` is a Constructor arg, not a metadata. --- IPython/core/prefilter.py | 10 ++++++---- IPython/terminal/ptshell.py | 33 +++++++++++++++++---------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index 7f01addc3d2..af6d44e04d5 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -509,10 +509,12 @@ class AutocallChecker(PrefilterChecker): priority = Integer(1000).tag(config=True) - function_name_regexp = CRegExp(re_fun_name).tag(config=True, - help="RegExp to identify potential function names.") - exclude_regexp = CRegExp(re_exclude_auto).tag(config=True, - help="RegExp to exclude strings with this start from autocalling.") + function_name_regexp = CRegExp(re_fun_name, + help="RegExp to identify potential function names." + ).tag(config=True) + exclude_regexp = CRegExp(re_exclude_auto, + help="RegExp to exclude strings with this start from autocalling." + ).tag(config=True) def check(self, line_info): "Check if the initial word/function is callable and autocall is on." diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 9c12e57f00a..85dbe22bfd8 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -91,8 +91,9 @@ def lex_document(self, cli, document): class TerminalInteractiveShell(InteractiveShell): colors_force = True - space_for_menu = Integer(6).tag(config=True, help='Number of line at the bottom of the screen ' - 'to reserve for the completion menu') + space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' + 'to reserve for the completion menu' + ).tag(config=True) def _space_for_menu_changed(self, old, new): self._update_layout() @@ -108,36 +109,36 @@ def _space_for_menu_changed(self, old, new): in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", ) - editing_mode = Unicode('emacs').tag(config=True, + editing_mode = Unicode('emacs', help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", - ) + ).tag(config=True) - mouse_support = Bool(False).tag(config=True, + mouse_support = Bool(False, help="Enable mouse support in the prompt" - ) + ).tag(config=True) - highlighting_style = Unicode('default').tag(config=True, + highlighting_style = Unicode('default', help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) - ) + ).tag(config=True) def _highlighting_style_changed(self, old, new): self._style = self._make_style_from_name(self.highlighting_style) - highlighting_style_overrides = Dict().tag(config=True, + highlighting_style_overrides = Dict( help="Override highlighting format for specific tokens" - ) + ).tag(config=True) - editor = Unicode(get_default_editor()).tag(config=True, + editor = Unicode(get_default_editor(), help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." - ) + ).tag(config=True) - term_title = Bool(True).tag(config=True, + term_title = Bool(True, help="Automatically set the terminal title" - ) + ).tag(config=True) - display_completions_in_columns = Bool(False).tag(config=True, + display_completions_in_columns = Bool(False, help="Display a multi column completion menu.", - ) + ).tag(config=True) @observe('term_title') def _term_title_changed(self, change): From 04d48146a88457646da14da547e1efa0fc5e497d Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 13 May 2016 17:23:05 +0200 Subject: [PATCH 0310/4859] adopt traitlets 4.2 API - `.tag(config=True)` - `@default` - `@observe` --- IPython/core/alias.py | 4 +- IPython/core/application.py | 73 +++++++++----- IPython/core/completer.py | 36 +++---- IPython/core/formatters.py | 25 +++-- IPython/core/history.py | 26 +++-- IPython/core/interactiveshell.py | 167 ++++++++++++++++--------------- IPython/core/magic.py | 18 ++-- IPython/core/magics/script.py | 26 ++--- IPython/core/prefilter.py | 23 +---- IPython/core/profiledir.py | 44 ++++---- IPython/core/prompts.py | 35 +++---- IPython/core/shellapp.py | 65 ++++++------ IPython/extensions/storemagic.py | 25 ++--- IPython/terminal/ipapp.py | 37 +++---- IPython/terminal/ptshell.py | 23 +++-- IPython/utils/colorable.py | 2 +- 16 files changed, 304 insertions(+), 325 deletions(-) diff --git a/IPython/core/alias.py b/IPython/core/alias.py index 7dc81c71f7e..28a9ccb00d6 100644 --- a/IPython/core/alias.py +++ b/IPython/core/alias.py @@ -192,8 +192,8 @@ def __call__(self, rest=''): class AliasManager(Configurable): - default_aliases = List(default_aliases(), config=True) - user_aliases = List(default_value=[], config=True) + default_aliases = List(default_aliases()).tag(config=True) + user_aliases = List(default_value=[]).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): diff --git a/IPython/core/application.py b/IPython/core/application.py index 6374b7f709f..0c9f0a63c3f 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -26,7 +26,10 @@ from IPython.paths import get_ipython_dir, get_ipython_package_dir from IPython.utils.path import ensure_dir_exists from IPython.utils import py3compat -from traitlets import List, Unicode, Type, Bool, Dict, Set, Instance, Undefined +from traitlets import ( + List, Unicode, Type, Bool, Dict, Set, Instance, Undefined, + default, observe, +) if os.name == 'nt': programdata = os.environ.get('PROGRAMDATA', None) @@ -96,11 +99,13 @@ class BaseIPythonApplication(Application): config_file_specified = Set() config_file_name = Unicode() + @default('config_file_name') def _config_file_name_default(self): return self.name.replace('-','_') + u'_config.py' - def _config_file_name_changed(self, name, old, new): - if new != old: - self.config_file_specified.add(new) + @observe('config_file_name') + def _config_file_name_changed(self, change): + if change['new'] != change['old']: + self.config_file_specified.add(change['new']) # The directory that contains IPython's builtin profiles. builtin_profile_dir = Unicode( @@ -108,15 +113,19 @@ def _config_file_name_changed(self, name, old, new): ) config_file_paths = List(Unicode()) + @default('config_file_paths') def _config_file_paths_default(self): return [py3compat.getcwd()] - extra_config_file = Unicode(config=True, + extra_config_file = Unicode( help="""Path to an extra config file to load. If specified, load this config file in addition to any other IPython config. - """) - def _extra_config_file_changed(self, name, old, new): + """).tag(config=True) + @observe('extra_config_file') + def _extra_config_file_changed(self, change): + old = change['old'] + new = change['new'] try: self.config_files.remove(old) except ValueError: @@ -124,30 +133,37 @@ def _extra_config_file_changed(self, name, old, new): self.config_file_specified.add(new) self.config_files.append(new) - profile = Unicode(u'default', config=True, + profile = Unicode(u'default', help="""The IPython profile to use.""" - ) - - def _profile_changed(self, name, old, new): + ).tag(config=True) + + @observe('profile') + def _profile_changed(self, change): self.builtin_profile_dir = os.path.join( - get_ipython_package_dir(), u'config', u'profile', new + get_ipython_package_dir(), u'config', u'profile', change['new'] ) - ipython_dir = Unicode(config=True, + ipython_dir = Unicode( help=""" The name of the IPython directory. This directory is used for logging configuration (through profiles), history storage, etc. The default is usually $HOME/.ipython. This option can also be specified through the environment variable IPYTHONDIR. """ - ) + ).tag(config=True) + @default('ipython_dir') def _ipython_dir_default(self): d = get_ipython_dir() - self._ipython_dir_changed('ipython_dir', d, d) + self._ipython_dir_changed({ + 'name': 'ipython_dir', + 'old': d, + 'new': d, + }) return d _in_init_profile_dir = False profile_dir = Instance(ProfileDir, allow_none=True) + @default('profile_dir') def _profile_dir_default(self): # avoid recursion if self._in_init_profile_dir: @@ -156,26 +172,29 @@ def _profile_dir_default(self): self.init_profile_dir() return self.profile_dir - overwrite = Bool(False, config=True, - help="""Whether to overwrite existing config files when copying""") - auto_create = Bool(False, config=True, - help="""Whether to create profile dir if it doesn't exist""") + overwrite = Bool(False, + help="""Whether to overwrite existing config files when copying""" + ).tag(config=True) + auto_create = Bool(False, + help="""Whether to create profile dir if it doesn't exist""" + ).tag(config=True) config_files = List(Unicode()) + @default('config_files') def _config_files_default(self): return [self.config_file_name] - copy_config_files = Bool(False, config=True, + copy_config_files = Bool(False, help="""Whether to install the default config files into the profile dir. If a new profile is being created, and IPython contains config files for that profile, then they will be staged into the new directory. Otherwise, default config files will be automatically generated. - """) + """).tag(config=True) - verbose_crash = Bool(False, config=True, + verbose_crash = Bool(False, help="""Create a massive crash report when IPython encounters what may be an internal error. The default is to append a short message to the - usual traceback""") + usual traceback""").tag(config=True) # The class to use as the crash handler. crash_handler_class = Type(crashhandler.CrashHandler) @@ -199,7 +218,6 @@ def __init__(self, **kwargs): def initialize_subcommand(self, subc, argv=None): if subc in self.deprecated_subcommands: - import time self.log.warning("Subcommand `ipython {sub}` is deprecated and will be removed " "in future versions.".format(sub=subc)) self.log.warning("You likely want to use `jupyter {sub}` in the " @@ -225,8 +243,11 @@ def excepthook(self, etype, evalue, tb): return self.crash_handler(etype, evalue, tb) else: return crashhandler.crash_handler_lite(etype, evalue, tb) - - def _ipython_dir_changed(self, name, old, new): + + @observe('ipython_dir') + def _ipython_dir_changed(self, change): + old = change['old'] + new = change['new'] if old is not Undefined: str_old = py3compat.cast_bytes_py2(os.path.abspath(old), sys.getfilesystemencoding() diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 74d007a095a..21c9110a942 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -66,7 +66,7 @@ import unicodedata import string -from traitlets.config.configurable import Configurable +from traitlets.config.configurable import Configurable from IPython.core.error import TryNext from IPython.core.inputsplitter import ESC_MAGIC from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol @@ -75,7 +75,7 @@ from IPython.utils.dir2 import dir2, get_real_method from IPython.utils.process import arg_split from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 -from traitlets import CBool, Enum +from traitlets import Bool, Enum, observe import jedi import jedi.api.helpers @@ -174,7 +174,6 @@ def compress_user(path, tilde_expand, tilde_val): return path - def completions_sorting_key(word): """key for sorting completions @@ -273,14 +272,14 @@ def split_line(self, line, cursor_pos=None): class Completer(Configurable): - greedy = CBool(False, config=True, + greedy = Bool(False, help="""Activate greedy completion PENDING DEPRECTION. this is now mostly taken care of with Jedi. This will enable completion on elements of lists, results of function calls, etc., but can be unsafe because the code is actually evaluated on TAB. """ - ) + ).tag(config=True) def __init__(self, namespace=None, global_namespace=None, **kwargs): @@ -505,7 +504,7 @@ def back_unicode_name_matches(text): try : unic = unicodedata.name(char) return '\\'+char,['\\'+unic] - except KeyError as e: + except KeyError: pass return u'', () @@ -532,17 +531,18 @@ def back_latex_name_matches(text): latex = reverse_latex_symbol[char] # '\\' replace the \ as well return '\\'+char,[latex] - except KeyError as e: + except KeyError: pass return u'', () class IPCompleter(Completer): """Extension of the completer class with IPython-specific features""" - - def _greedy_changed(self, name, old, new): + + @observe('greedy') + def _greedy_changed(self, change): """update the splitter and readline delims when greedy is changed""" - if new: + if change['new']: self.splitter.delims = GREEDY_DELIMS else: self.splitter.delims = DELIMS @@ -550,14 +550,14 @@ def _greedy_changed(self, name, old, new): if self.readline: self.readline.set_completer_delims(self.splitter.delims) - merge_completions = CBool(True, config=True, + merge_completions = Bool(True, help="""Whether to merge completion results into a single list If False, only the completion results from the first non-empty completer will be returned. """ - ) - omit__names = Enum((0,1,2), default_value=2, config=True, + ).tag(config=True) + omit__names = Enum((0,1,2), default_value=2, help="""Instruct the completer to omit private method names Specifically, when completing on ``object.``. @@ -568,8 +568,8 @@ def _greedy_changed(self, name, old, new): When 0: nothing will be excluded. """ - ) - limit_to__all__ = CBool(default_value=False, config=True, + ).tag(config=True) + limit_to__all__ = Bool(False, help=""" DEPRECATED as of version 5.0. @@ -580,8 +580,8 @@ def _greedy_changed(self, name, old, new): When True: only those names in obj.__all__ will be included. When False [default]: the __all__ attribute is ignored - """ - ) + """, + ).tag(config=True) def __init__(self, shell=None, namespace=None, global_namespace=None, use_readline=True, config=None, **kwargs): @@ -1101,7 +1101,7 @@ def unicode_name_matches(self, text): # allow combining chars if ('a'+unic).isidentifier(): return '\\'+s,[unic] - except KeyError as e: + except KeyError: pass return u'', [] diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 237a2d713c1..72659893348 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -26,6 +26,7 @@ from traitlets import ( Bool, Dict, Integer, Unicode, CUnicode, ObjectName, List, ForwardDeclaredInstance, + default, observe, ) from IPython.utils.py3compat import ( with_metaclass, string_types, unicode_type, @@ -49,29 +50,34 @@ def _plain_text_only_changed(self, name, old, new): else: self.active_types = self.format_types - active_types = List(Unicode()).tag(config=True, + active_types = List(Unicode(), help="""List of currently active mime-types to display. You can use this to set a white-list for formats to display. Most users will not need to change this value. - """) + """).tag(config=True) + + @default('active_types') def _active_types_default(self): return self.format_types - - def _active_types_changed(self, name, old, new): + + @observe('active_types') + def _active_types_changed(self, change): for key, formatter in self.formatters.items(): - if key in new: + if key in change['new']: formatter.enabled = True else: formatter.enabled = False ipython_display_formatter = ForwardDeclaredInstance('FormatterABC') - def _ipython_display_formatter_default(self): + @default('ipython_display_formatter') + def _default_formatter(self): return IPythonDisplayFormatter(parent=self) # A dict of formatter whose keys are format types (MIME types) and whose # values are subclasses of BaseFormatter. formatters = Dict() + @default('formatters') def _formatters_default(self): """Activate the default formatters.""" formatter_classes = [ @@ -570,12 +576,12 @@ def dtype_pprinter(obj, p, cycle): # something. enabled = Bool(True).tag(config=False) - max_seq_length = Integer(pretty.MAX_SEQ_LENGTH).tag(config=True, + max_seq_length = Integer(pretty.MAX_SEQ_LENGTH, help="""Truncate large collections (lists, dicts, tuples, sets) to this size. Set to 0 to disable truncation. """ - ) + ).tag(config=True) # Look for a _repr_pretty_ methods to use for pretty printing. print_method = ObjectName('_repr_pretty_') @@ -643,14 +649,17 @@ def _float_precision_changed(self, name, old, new): self.float_format = fmt # Use the default pretty printers from IPython.lib.pretty. + @default('singleton_printers') def _singleton_printers_default(self): return pretty._singleton_pprinters.copy() + @default('type_printers') def _type_printers_default(self): d = pretty._type_pprinters.copy() d[float] = lambda obj,p,cycle: p.text(self.float_format%obj) return d + @default('deferred_printers') def _deferred_printers_default(self): return pretty._deferred_type_pprinters.copy() diff --git a/IPython/core/history.py b/IPython/core/history.py index be0afc2d633..5147ad9352a 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -25,6 +25,7 @@ from IPython.utils import py3compat from traitlets import ( Any, Bool, Dict, Instance, Integer, List, Unicode, TraitError, + default, observe, ) from warnings import warn @@ -148,7 +149,7 @@ class HistoryAccessor(HistoryAccessorBase): _corrupt_db_limit = 2 # String holding the path to the history file - hist_file = Unicode(config=True, + hist_file = Unicode( help="""Path to file to use for SQLite history database. By default, IPython will put the history database in the IPython @@ -161,9 +162,9 @@ class HistoryAccessor(HistoryAccessorBase): ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite - """) + """).tag(config=True) - enabled = Bool(True, config=True, + enabled = Bool(True, help="""enable the SQLite history set enabled=False to disable the SQLite history, @@ -171,20 +172,22 @@ class HistoryAccessor(HistoryAccessorBase): and no background saving thread. This may be necessary in some threaded environments where IPython is embedded. """ - ) + ).tag(config=True) - connection_options = Dict(config=True, + connection_options = Dict( help="""Options for configuring the SQLite connection These options are passed as keyword args to sqlite3.connect when establishing database conenctions. """ - ) + ).tag(config=True) # The SQLite database db = Any() - def _db_changed(self, name, old, new): + @observe('db') + def _db_changed(self, change): """validate the db, since it can be an Instance of two different types""" + new = change['new'] connection_types = (DummyDB,) if sqlite3 is not None: connection_types = (DummyDB, sqlite3.Connection) @@ -479,6 +482,7 @@ class HistoryManager(HistoryAccessor): input_hist_raw = List([""]) # A list of directories visited during session dir_hist = List() + @default('dir_hist') def _dir_hist_default(self): try: return [py3compat.getcwd()] @@ -494,13 +498,13 @@ def _dir_hist_default(self): # The number of the current session in the history database session_number = Integer() - db_log_output = Bool(False, config=True, + db_log_output = Bool(False, help="Should the history database include output? (default: no)" - ) - db_cache_size = Integer(0, config=True, + ).tag(config=True) + db_cache_size = Integer(0, help="Write to database every x commands (higher values save disk access & power).\n" "Values of 1 or less effectively disable caching." - ) + ).tag(config=True) # The input and output caches db_input_cache = List() db_output_cache = List() diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 04536a9641e..6a18ecd48c0 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -49,7 +49,7 @@ from IPython.core.extensions import ExtensionManager from IPython.core.formatters import DisplayFormatter from IPython.core.history import HistoryManager -from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC, ESC_MAGIC2 +from IPython.core.inputsplitter import ESC_MAGIC, ESC_MAGIC2 from IPython.core.logger import Logger from IPython.core.macro import Macro from IPython.core.payload import PayloadManager @@ -75,8 +75,10 @@ from IPython.utils.syspathcontext import prepended_to_syspath from IPython.utils.text import (format_screen, LSString, SList, DollarFormatter) -from traitlets import (Integer, Bool, CBool, CaselessStrEnum, Enum, - List, Dict, Unicode, Instance, Type) +from traitlets import ( + Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type, + observe, default, +) from warnings import warn from logging import error import IPython.core.hooks @@ -114,9 +116,6 @@ def no_op(*a, **kw): pass class SpaceInInput(Exception): pass -@undoc -class Bunch: pass - def get_default_colors(): if sys.platform=='darwin': @@ -173,14 +172,14 @@ class InteractiveShell(SingletonConfigurable): _instance = None - ast_transformers = List([], config=True, help= + ast_transformers = List([], help= """ A list of ast.NodeTransformer subclass instances, which will be applied to user input before code is run. """ - ) + ).tag(config=True) - autocall = Enum((0,1,2), default_value=0, config=True, help= + autocall = Enum((0,1,2), default_value=0, help= """ Make IPython automatically call any callable object even if you didn't type explicit parentheses. For example, 'str 43' becomes 'str(43)' @@ -189,28 +188,28 @@ class InteractiveShell(SingletonConfigurable): arguments on the line, and '2' for 'full' autocall, where all callable objects are automatically called (even if no arguments are present). """ - ) + ).tag(config=True) # TODO: remove all autoindent logic and put into frontends. # We can't do this yet because even runlines uses the autoindent. - autoindent = CBool(True, config=True, help= + autoindent = Bool(True, help= """ Autoindent IPython code entered interactively. """ - ) - automagic = CBool(True, config=True, help= + ).tag(config=True) + automagic = Bool(True, help= """ Enable magic commands to be called without the leading %. """ - ) + ).tag(config=True) - banner1 = Unicode(default_banner, config=True, + banner1 = Unicode(default_banner, help="""The part of the banner to be printed before the profile""" - ) - banner2 = Unicode('', config=True, + ).tag(config=True) + banner2 = Unicode('', help="""The part of the banner to be printed after the profile""" - ) + ).tag(config=True) - cache_size = Integer(1000, config=True, help= + cache_size = Integer(1000, help= """ Set the size of the output cache. The default is 1000, you can change it permanently in your config file. Setting it to 0 completely @@ -219,19 +218,19 @@ class InteractiveShell(SingletonConfigurable): issued). This limit is defined because otherwise you'll spend more time re-flushing a too small cache than working """ - ) - color_info = CBool(True, config=True, help= + ).tag(config=True) + color_info = Bool(True, help= """ Use colors for displaying information about objects. Because this information is passed through a pager (like 'less'), and some pagers get confused with color codes, this capability can be turned off. """ - ) + ).tag(config=True) colors = CaselessStrEnum(('NoColor','LightBG','Linux'), - default_value=get_default_colors(), config=True, + default_value=get_default_colors(), help="Set the color scheme (NoColor, Linux, or LightBG)." - ) - colors_force = CBool(False, help= + ).tag(config=True) + colors_force = Bool(False, help= """ Force use of ANSI color codes, regardless of OS and readline availability. @@ -240,8 +239,8 @@ class InteractiveShell(SingletonConfigurable): # without readline on Win32. When the ZMQ formatting system is # refactored, this should be removed. ) - debug = CBool(False, config=True) - deep_reload = CBool(False, config=True, help= + debug = Bool(False).tag(config=True) + deep_reload = Bool(False, help= """ **Deprecated** @@ -255,23 +254,24 @@ class InteractiveShell(SingletonConfigurable): deep_reload is off, IPython will use the normal reload(), but deep_reload will still be available as dreload(). """ - ) - disable_failing_post_execute = CBool(False, config=True, + ).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) display_formatter = Instance(DisplayFormatter, allow_none=True) displayhook_class = Type(DisplayHook) display_pub_class = Type(DisplayPublisher) data_pub_class = None - exit_now = CBool(False) + exit_now = Bool(False) exiter = Instance(ExitAutocall) + @default('exiter') def _exiter_default(self): return ExitAutocall(self) # Monotonically increasing execution counter execution_count = Integer(1) filename = Unicode("") - ipython_dir= Unicode('', config=True) # Set to get_ipython_dir() in __init__ + ipython_dir= Unicode('').tag(config=True) # Set to get_ipython_dir() in __init__ # Input splitter, to transform input line by line and detect when a block # is ready to be executed. @@ -283,88 +283,91 @@ def _exiter_default(self): input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter', (), {'line_input_checker': False}) - logstart = CBool(False, config=True, help= + logstart = Bool(False, help= """ Start logging to the default log file in overwrite mode. Use `logappend` to specify a log file to **append** logs to. """ - ) - logfile = Unicode('', config=True, help= + ).tag(config=True) + logfile = Unicode('', help= """ The name of the logfile to use. """ - ) - logappend = Unicode('', config=True, help= + ).tag(config=True) + logappend = Unicode('', help= """ Start logging to the given file in append mode. Use `logfile` to specify a log file to **overwrite** logs to. """ - ) + ).tag(config=True) object_info_string_level = Enum((0,1,2), default_value=0, - config=True) - pdb = CBool(False, config=True, help= + ).tag(config=True) + pdb = Bool(False, help= """ Automatically call the pdb debugger after every exception. """ - ) - multiline_history = CBool(sys.platform != 'win32', config=True, + ).tag(config=True) + multiline_history = Bool(sys.platform != 'win32', help="Save multi-line entries as one entry in readline history" - ) - display_page = Bool(False, config=True, + ).tag(config=True) + display_page = Bool(False, help="""If True, anything that would be passed to the pager will be displayed as regular output instead.""" - ) + ).tag(config=True) # deprecated prompt traits: - prompt_in1 = Unicode('In [\\#]: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template") - prompt_in2 = Unicode(' .\\D.: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template") - prompt_out = Unicode('Out[\\#]: ', config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template") - prompts_pad_left = CBool(True, config=True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify") + prompt_in1 = Unicode('In [\\#]: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template" + ).tag(config=True) + prompt_in2 = Unicode(' .\\D.: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template" + ).tag(config=True) + prompt_out = Unicode('Out[\\#]: ', + help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template" + ).tag(config=True) + prompts_pad_left = Bool(True, + help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify" + ).tag(config=True) - def _prompt_trait_changed(self, name, old, new): + @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left') + def _prompt_trait_changed(self, change): table = { 'prompt_in1' : 'in_template', 'prompt_in2' : 'in2_template', 'prompt_out' : 'out_template', 'prompts_pad_left' : 'justify', } + name = change['name'] warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format( name=name, newname=table[name]) ) # protect against weird cases where self.config may not exist: if self.config is not None: # propagate to corresponding PromptManager trait - setattr(self.config.PromptManager, table[name], new) - - _prompt_in1_changed = _prompt_trait_changed - _prompt_in2_changed = _prompt_trait_changed - _prompt_out_changed = _prompt_trait_changed - _prompt_pad_left_changed = _prompt_trait_changed + setattr(self.config.PromptManager, table[name], change['new']) - show_rewritten_input = CBool(True, config=True, + show_rewritten_input = Bool(True, help="Show rewritten input, e.g. for autocall." - ) + ).tag(config=True) - quiet = CBool(False, config=True) + quiet = Bool(False).tag(config=True) - history_length = Integer(10000, config=True) + history_length = Integer(10000, + help='Total length of command history' + ).tag(config=True) - history_load_length = Integer(1000, config=True, help= + history_load_length = Integer(1000, help= """ The number of saved history entries to be loaded into the readline buffer at startup. """ - ) + ).tag(config=True) # The readline stuff will eventually be moved to the terminal subclass # but for now, we can't do that as readline is welded in everywhere. - readline_use = CBool(True, config=True) - readline_remove_delims = Unicode('-/~', config=True) + readline_use = Bool(True).tag(config=True) + readline_remove_delims = Unicode('-/~').tag(config=True) readline_delims = Unicode() # set by init_readline() # don't use \M- bindings by default, because they # conflict with 8-bit encodings. See gh-58,gh-88 @@ -381,29 +384,31 @@ def _prompt_trait_changed(self, name, old, new): '"\e[B": history-search-forward', '"\C-k": kill-line', '"\C-u": unix-line-discard', - ], config=True) + ]).tag(config=True) _custom_readline_config = False - def _readline_parse_and_bind_changed(self, name, old, new): + @observe('readline_parse_and_bind') + def _readline_parse_and_bind_changed(self, change): # notice that readline config is customized # indicates that it should have higher priority than inputrc self._custom_readline_config = True ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'], - default_value='last_expr', config=True, + default_value='last_expr', help=""" 'all', 'last', 'last_expr' or 'none', specifying which nodes should be - run interactively (displaying output from expressions).""") + run interactively (displaying output from expressions).""" + ).tag(config=True) # TODO: this part of prompt management should be moved to the frontends. # Use custom TraitTypes that convert '0'->'' and '\\n'->'\n' - separate_in = SeparateUnicode('\n', config=True) - separate_out = SeparateUnicode('', config=True) - separate_out2 = SeparateUnicode('', config=True) - wildcards_case_sensitive = CBool(True, config=True) + separate_in = SeparateUnicode('\n').tag(config=True) + separate_out = SeparateUnicode('').tag(config=True) + separate_out2 = SeparateUnicode('').tag(config=True) + wildcards_case_sensitive = Bool(True).tag(config=True) xmode = CaselessStrEnum(('Context','Plain', 'Verbose'), - default_value='Context', config=True) + default_value='Context').tag(config=True) # Subcomponents of InteractiveShell alias_manager = Instance('IPython.core.alias.AliasManager', allow_none=True) @@ -522,9 +527,9 @@ def get_ipython(self): #------------------------------------------------------------------------- # Trait changed handlers #------------------------------------------------------------------------- - - def _ipython_dir_changed(self, name, new): - ensure_dir_exists(new) + @observe('ipython_dir') + def _ipython_dir_changed(self, change): + ensure_dir_exists(change['new']) def set_autoindent(self,value=None): """Set the autoindent flag. @@ -785,7 +790,7 @@ def banner(self): def show_banner(self, banner=None): if banner is None: banner = self.banner - self.write(banner) + sys.stdout.write(banner) #------------------------------------------------------------------------- # Things related to hooks diff --git a/IPython/core/magic.py b/IPython/core/magic.py index 47d5ad0d915..c68160634da 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -12,17 +12,12 @@ # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -# Stdlib import os import re import sys import types from getopt import getopt, GetoptError -# Our own from traitlets.config.configurable import Configurable from IPython.core import oinspect from IPython.core.error import UsageError @@ -32,7 +27,7 @@ from IPython.utils.process import arg_split from IPython.utils.py3compat import string_types, iteritems from IPython.utils.text import dedent -from traitlets import Bool, Dict, Instance +from traitlets import Bool, Dict, Instance, observe from logging import error #----------------------------------------------------------------------------- @@ -303,11 +298,12 @@ class MagicsManager(Configurable): shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) - auto_magic = Bool(True, config=True, help= - "Automatically call line magics without requiring explicit % prefix") - - def _auto_magic_changed(self, name, value): - self.shell.automagic = value + auto_magic = Bool(True, help= + "Automatically call line magics without requiring explicit % prefix" + ).tag(config=True) + @observe('auto_magic') + def _auto_magic_changed(self, change): + self.shell.automagic = change['new'] _auto_status = [ 'Automagic is OFF, % prefix IS needed for line magics.', diff --git a/IPython/core/magics/script.py b/IPython/core/magics/script.py index 5dff1a33368..be8fa941b62 100644 --- a/IPython/core/magics/script.py +++ b/IPython/core/magics/script.py @@ -1,18 +1,9 @@ """Magic functions for running cells in various scripts.""" from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012 The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. -# Stdlib import errno import os import sys @@ -21,8 +12,6 @@ from subprocess import Popen, PIPE import atexit -# Our own packages -from traitlets.config.configurable import Configurable from IPython.core import magic_arguments from IPython.core.magic import ( Magics, magics_class, line_magic, cell_magic @@ -30,7 +19,7 @@ from IPython.lib.backgroundjobs import BackgroundJobManager from IPython.utils import py3compat from IPython.utils.process import arg_split -from traitlets import List, Dict +from traitlets import List, Dict, default #----------------------------------------------------------------------------- # Magic implementation classes @@ -79,7 +68,7 @@ class ScriptMagics(Magics): with a program in a subprocess, and registers a few top-level magics that call %%script with common interpreters. """ - script_magics = List(config=True, + script_magics = List( help="""Extra script cell magics to define This generates simple wrappers of `%%script foo` as `%%foo`. @@ -87,7 +76,8 @@ class ScriptMagics(Magics): If you want to add script magics that aren't on your path, specify them in script_paths """, - ) + ).tag(config=True) + @default('script_magics') def _script_magics_default(self): """default to a common list of programs""" @@ -108,13 +98,13 @@ def _script_magics_default(self): return defaults - script_paths = Dict(config=True, + script_paths = Dict( help="""Dict mapping short 'ruby' names to full paths, such as '/opt/secret/bin/ruby' Only necessary for items in script_magics where the default path will not find the right interpreter. """ - ) + ).tag(config=True) def __init__(self, shell=None): super(ScriptMagics, self).__init__(shell=shell) diff --git a/IPython/core/prefilter.py b/IPython/core/prefilter.py index af6d44e04d5..cbed3fd80a4 100644 --- a/IPython/core/prefilter.py +++ b/IPython/core/prefilter.py @@ -4,25 +4,10 @@ Prefilters transform user input before it is exec'd by Python. These transforms are used to implement additional syntax such as !ls and %magic. - -Authors: - -* Brian Granger -* Fernando Perez -* Dan Milstein -* Ville Vainio """ -#----------------------------------------------------------------------------- -# 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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. from keyword import iskeyword import re @@ -39,7 +24,7 @@ from IPython.core.splitinput import LineInfo from traitlets import ( - List, Integer, Unicode, CBool, Bool, Instance, CRegExp + List, Integer, Unicode, Bool, Instance, CRegExp ) #----------------------------------------------------------------------------- @@ -129,7 +114,7 @@ class PrefilterManager(Configurable): or :meth:`sort_transformers` method after changing the priority. """ - multi_line_specials = CBool(True).tag(config=True) + multi_line_specials = Bool(True).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): diff --git a/IPython/core/profiledir.py b/IPython/core/profiledir.py index d8559309038..9c9e99ca0c4 100644 --- a/IPython/core/profiledir.py +++ b/IPython/core/profiledir.py @@ -12,7 +12,7 @@ from IPython.paths import get_ipython_package_dir from IPython.utils.path import expand_path, ensure_dir_exists from IPython.utils import py3compat -from traitlets import Unicode, Bool +from traitlets import Unicode, Bool, observe #----------------------------------------------------------------------------- # Module errors @@ -47,17 +47,18 @@ class ProfileDir(LoggingConfigurable): pid_dir = Unicode(u'') static_dir = Unicode(u'') - location = Unicode(u'', config=True, + location = Unicode(u'', help="""Set the profile location directly. This overrides the logic used by the `profile` option.""", - ) + ).tag(config=True) _location_isset = Bool(False) # flag for detecting multiply set location - - def _location_changed(self, name, old, new): + @observe('location') + def _location_changed(self, change): if self._location_isset: raise RuntimeError("Cannot set profile location more than once.") self._location_isset = True + new = change['new'] ensure_dir_exists(new) # ensure config files exist: @@ -67,10 +68,7 @@ def _location_changed(self, name, old, new): self.pid_dir = os.path.join(new, self.pid_dir_name) self.static_dir = os.path.join(new, self.static_dir_name) self.check_dirs() - - def _log_dir_changed(self, name, old, new): - self.check_log_dir() - + def _mkdir(self, path, mode=None): """ensure a directory exists at a given path @@ -104,14 +102,13 @@ def _mkdir(self, path, mode=None): raise return True - - def check_log_dir(self): + + @observe('log_dir') + def check_log_dir(self, change=None): self._mkdir(self.log_dir) - - def _startup_dir_changed(self, name, old, new): - self.check_startup_dir() - - def check_startup_dir(self): + + @observe('startup_dir') + def check_startup_dir(self, change=None): self._mkdir(self.startup_dir) readme = os.path.join(self.startup_dir, 'README') @@ -123,21 +120,14 @@ def check_startup_dir(self): if os.path.exists(src) and not os.path.exists(readme): shutil.copy(src, readme) - def _security_dir_changed(self, name, old, new): - self.check_security_dir() - - def check_security_dir(self): + @observe('security_dir') + def check_security_dir(self, change=None): self._mkdir(self.security_dir, 0o40700) - def _pid_dir_changed(self, name, old, new): - self.check_pid_dir() - - def check_pid_dir(self): + @observe('pid_dir') + def check_pid_dir(self, change=None): self._mkdir(self.pid_dir, 0o40700) - def _static_dir_changed(self, name, old, new): - self.check_startup_dir() - def check_dirs(self): self.check_security_dir() self.check_log_dir() diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index eeb2e3fe286..70f2e3036ca 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -1,24 +1,9 @@ # -*- coding: utf-8 -*- -"""Classes for handling input/output prompts. +"""Classes for handling input/output prompts.""" -Authors: - -* Fernando Perez -* Brian Granger -* Thomas Kluyver -""" - -#----------------------------------------------------------------------------- -# Copyright (C) 2008-2011 The IPython Development Team -# Copyright (C) 2001-2007 Fernando Perez -# -# Distributed under the terms of the BSD License. The full license is in -# the file COPYING, distributed as part of this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) 2001-2007 Fernando Perez +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import os import re @@ -31,7 +16,7 @@ from traitlets.config.configurable import Configurable from IPython.core import release from IPython.utils import coloransi, py3compat -from traitlets import Unicode, Instance, Dict, Bool, Int, observe +from traitlets import Unicode, Instance, Dict, Bool, Int, observe, default from IPython.utils.PyColorize import LightBGColors, LinuxColors, NoColor @@ -271,7 +256,6 @@ def _color_scheme_changed(self, change): things like the current time in the prompts. Functions are only called if they are used in the prompt. """) - def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() in_template = Unicode('In [\\#]: ', help="Input prompt. '\\#' will be transformed to the prompt number" @@ -282,6 +266,10 @@ def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() help="Output prompt. '\\#' will be transformed to the prompt number" ).tag(config=True) + @default('lazy_evaluate_fields') + def _lazy_evaluate_fields_default(self): + return lazily_evaluate.copy() + justify = Bool(True, help=""" If True (default), each prompt will be right-aligned with the preceding one. @@ -297,6 +285,7 @@ def _lazy_evaluate_fields_default(self): return lazily_evaluate.copy() # The number of characters in each prompt which don't contribute to width invisible_chars = Dict() + @default('invisible_chars') def _invisible_chars_default(self): return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0} @@ -313,8 +302,8 @@ def __init__(self, shell, **kwargs): self.update_prompt('in2', self.in2_template) self.update_prompt('out', self.out_template) self.update_prompt('rewrite') - self.on_trait_change(self._update_prompt_trait, ['in_template', - 'in2_template', 'out_template']) + self.observe(self._update_prompt_trait, + names=['in_template', 'in2_template', 'out_template']) def update_prompt(self, name, new_template=None): """This is called when a prompt template is updated. It processes diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 2b6b29cf2c9..9bc99afd644 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -22,7 +22,7 @@ from IPython.utils.contexts import preserve_keys from IPython.utils.path import filefind from traitlets import ( - Unicode, Instance, List, Bool, CaselessStrEnum + Unicode, Instance, List, Bool, CaselessStrEnum, default, observe, ) from IPython.lib.inputhook import guis @@ -135,76 +135,73 @@ class InteractiveShellApp(Configurable): - :meth:`init_extensions` - :meth:`init_code` """ - extensions = List(Unicode(), config=True, + extensions = List(Unicode(), help="A list of dotted module names of IPython extensions to load." - ) - extra_extension = Unicode('', config=True, + ).tag(config=True) + extra_extension = Unicode('', help="dotted module name of an IPython extension to load." - ) + ).tag(config=True) - reraise_ipython_extension_failures = Bool( - False, - config=True, + reraise_ipython_extension_failures = Bool(False, help="Reraise exceptions encountered loading IPython extensions?", - ) + ).tag(config=True) # Extensions that are always loaded (not configurable) - default_extensions = List(Unicode(), [u'storemagic'], config=False) + default_extensions = List(Unicode(), [u'storemagic']).tag(config=False) - hide_initial_ns = Bool(True, config=True, + hide_initial_ns = Bool(True, help="""Should variables loaded at startup (by startup files, exec_lines, etc.) be hidden from tools like %who?""" - ) + ).tag(config=True) - exec_files = List(Unicode(), config=True, + exec_files = List(Unicode(), help="""List of files to run at IPython startup.""" - ) - exec_PYTHONSTARTUP = Bool(True, config=True, + ).tag(config=True) + exec_PYTHONSTARTUP = Bool(True, help="""Run the file referenced by the PYTHONSTARTUP environment variable at IPython startup.""" - ) - file_to_run = Unicode('', config=True, - help="""A file to be run""") + ).tag(config=True) + file_to_run = Unicode('', + help="""A file to be run""").tag(config=True) - exec_lines = List(Unicode(), config=True, + exec_lines = List(Unicode(), help="""lines of code to run at IPython startup.""" - ) - code_to_run = Unicode('', config=True, + ).tag(config=True) + code_to_run = Unicode('', help="Execute the given command string." - ) - module_to_run = Unicode('', config=True, + ).tag(config=True) + module_to_run = Unicode('', help="Run the module as a script." - ) - gui = CaselessStrEnum(gui_keys, config=True, allow_none=True, + ).tag(config=True) + gui = CaselessStrEnum(gui_keys, allow_none=True, help="Enable GUI event loop integration with any of {0}.".format(gui_keys) - ) + ).tag(config=True) matplotlib = CaselessStrEnum(backend_keys, allow_none=True, - config=True, help="""Configure matplotlib for interactive use with the default matplotlib backend.""" - ) + ).tag(config=True) pylab = CaselessStrEnum(backend_keys, allow_none=True, - config=True, help="""Pre-load matplotlib and numpy for interactive use, selecting a particular matplotlib backend and loop integration. """ - ) - pylab_import_all = Bool(True, config=True, + ).tag(config=True) + pylab_import_all = Bool(True, help="""If true, IPython will populate the user namespace with numpy, pylab, etc. and an ``import *`` is done from numpy and pylab, when using pylab mode. When False, pylab mode should not import any names into the user namespace. """ - ) + ).tag(config=True) shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) # whether interact-loop should start interact = Bool(True) user_ns = Instance(dict, args=None, allow_none=True) - def _user_ns_changed(self, name, old, new): + @observe('user_ns') + def _user_ns_changed(self, change): if self.shell is not None: - self.shell.user_ns = new + self.shell.user_ns = change['new'] self.shell.init_user_ns() def init_path(self): diff --git a/IPython/extensions/storemagic.py b/IPython/extensions/storemagic.py index f0ecbf3c10c..2fd1abf993b 100644 --- a/IPython/extensions/storemagic.py +++ b/IPython/extensions/storemagic.py @@ -10,30 +10,17 @@ c.StoreMagics.autorestore = True """ from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012, The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# Stdlib + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + import inspect, os, sys, textwrap -# Our own from IPython.core.error import UsageError from IPython.core.magic import Magics, magics_class, line_magic from traitlets import Bool from IPython.utils.py3compat import string_types -#----------------------------------------------------------------------------- -# Functions and classes -#----------------------------------------------------------------------------- def restore_aliases(ip): staliases = ip.db.get('stored_aliases', {}) @@ -74,11 +61,11 @@ class StoreMagics(Magics): Provides the %store magic.""" - autorestore = Bool(False, config=True, help= + autorestore = Bool(False, help= """If True, any %store-d variables will be automatically restored when IPython starts. """ - ) + ).tag(config=True) def __init__(self, shell): super(StoreMagics, self).__init__(shell=shell) diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index c1a3dad8e49..02edabe05be 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -14,6 +14,7 @@ import logging import os import sys +import warnings from traitlets.config.loader import Config from traitlets.config.application import boolean_flag, catch_config_error, Application @@ -33,10 +34,9 @@ ) from IPython.extensions.storemagic import StoreMagics from .ptshell import TerminalInteractiveShell -from IPython.utils import warn from IPython.paths import get_ipython_dir from traitlets import ( - Bool, List, Dict, + Bool, List, Dict, default, observe, ) #----------------------------------------------------------------------------- @@ -183,6 +183,7 @@ class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp): flags = Dict(flags) aliases = Dict(aliases) classes = List() + @default('classes') def _classes_default(self): """This has to be in a method, for TerminalIPythonApp to be available.""" return [ @@ -241,35 +242,37 @@ def _classes_default(self): # *do* autocreate requested profile, but don't create the config file. auto_create=Bool(True) # configurables - quick = Bool(False, config=True, + quick = Bool(False, help="""Start IPython quickly by skipping the loading of config files.""" - ) - def _quick_changed(self, name, old, new): - if new: + ).tag(config=True) + @observe('quick') + def _quick_changed(self, change): + if change['new']: self.load_config_file = lambda *a, **kw: None - display_banner = Bool(True, config=True, + display_banner = Bool(True, help="Whether to display a banner upon starting IPython." - ) + ).tag(config=True) # if there is code of files to run from the cmd line, don't interact # unless the --i flag (App.force_interact) is true. - force_interact = Bool(False, config=True, + force_interact = Bool(False, help="""If a command or file is given via the command-line, e.g. 'ipython foo.py', start an interactive shell after executing the file or command.""" - ) - def _force_interact_changed(self, name, old, new): - if new: + ).tag(config=True) + @observe('force_interact') + def _force_interact_changed(self, change): + if change['new']: self.interact = True - def _file_to_run_changed(self, name, old, new): + @observe('file_to_run', 'code_to_run', 'module_to_run') + def _file_to_run_changed(self, change): + new = change['new'] if new: self.something_to_run = True if new and not self.force_interact: self.interact = False - _code_to_run_changed = _file_to_run_changed - _module_to_run_changed = _file_to_run_changed # internal, not-configurable something_to_run=Bool(False) @@ -284,7 +287,7 @@ def parse_command_line(self, argv=None): # warn and transform into current syntax argv = argv[:] # copy, don't clobber idx = argv.index('-pylab') - warn.warn("`-pylab` flag has been deprecated.\n" + warnings.warn("`-pylab` flag has been deprecated.\n" " Use `--matplotlib ` and import pylab manually.") argv[idx] = '--pylab' @@ -331,7 +334,7 @@ def init_banner(self): def _pylab_changed(self, name, old, new): """Replace --pylab='inline' with --pylab='auto'""" if new == 'inline': - warn.warn("'inline' not available as pylab backend, " + warnings.warn("'inline' not available as pylab backend, " "using 'auto' instead.") self.pylab = 'auto' diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 85dbe22bfd8..fe84764ee3b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -13,7 +13,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input from IPython.utils.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd -from traitlets import Bool, CBool, Unicode, Dict, Integer, observe +from traitlets import Bool, Unicode, Dict, Integer, observe from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode @@ -100,15 +100,18 @@ def _space_for_menu_changed(self, old, new): pt_cli = None - autoedit_syntax = CBool(False).tag(config=True, - help="auto editing of files with syntax errors.") + autoedit_syntax = Bool(False, + help="auto editing of files with syntax errors.", + ).tag(config=True) + - confirm_exit = CBool(True).tag(config=True, + confirm_exit = Bool(True, help=""" Set to confirm when you try to exit IPython with an EOF (Control-D in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a direct exit without any confirmation.""", - ) + ).tag(config=True) + editing_mode = Unicode('emacs', help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", ).tag(config=True) @@ -121,7 +124,9 @@ def _space_for_menu_changed(self, old, new): help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) ).tag(config=True) - def _highlighting_style_changed(self, old, new): + + @observe('highlighting_style') + def _highlighting_style_changed(self, change): self._style = self._make_style_from_name(self.highlighting_style) highlighting_style_overrides = Dict( @@ -140,11 +145,9 @@ def _highlighting_style_changed(self, old, new): help="Display a multi column completion menu.", ).tag(config=True) - @observe('term_title') - def _term_title_changed(self, change): - self.init_term_title() - def init_term_title(self): + @observe('term_title') + def init_term_title(self, change=None): # Enable or disable the terminal title. if self.term_title: toggle_set_term_title(True) diff --git a/IPython/utils/colorable.py b/IPython/utils/colorable.py index a885eef092b..77e9dbf904f 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', config=True) + default_style=Unicode('lightbg').tag(config=True) From 12620da9920b4834e7ce09d3c54d35b97d1190d2 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 10:52:46 -0700 Subject: [PATCH 0311/4859] Update a few observer and .tag(config=True) to match new traitlets API. --- IPython/core/profileapp.py | 15 +++++++++------ IPython/core/prompts.py | 5 ++++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index fecdc0d5681..37f47eed74e 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -32,7 +32,7 @@ from IPython.utils.importstring import import_item from IPython.paths import get_ipython_dir, get_ipython_package_dir from IPython.utils import py3compat -from traitlets import Unicode, Bool, Dict +from traitlets import Unicode, Bool, Dict, observe #----------------------------------------------------------------------------- # Constants @@ -149,14 +149,14 @@ class ProfileList(Application): ) )) - ipython_dir = Unicode(get_ipython_dir(), config=True, + ipython_dir = Unicode(get_ipython_dir(), help=""" The name of the IPython directory. This directory is used for logging configuration (through profiles), history storage, etc. The default is usually $HOME/.ipython. This options can also be specified through the environment variable IPYTHONDIR. """ - ) + ).tag(config=True) def _print_profiles(self, profiles): @@ -211,15 +211,18 @@ class ProfileCreate(BaseIPythonApplication): name = u'ipython-profile' description = create_help examples = _create_examples - auto_create = Bool(True, config=False) + auto_create = Bool(True) def _log_format_default(self): return "[%(name)s] %(message)s" def _copy_config_files_default(self): return True - parallel = Bool(False, config=True, - help="whether to include parallel computing config files") + parallel = Bool(False, + help="whether to include parallel computing config files" + ).tag(config=True) + + @observe('parallel') def _parallel_changed(self, name, old, new): parallel_files = [ 'ipcontroller_config.py', 'ipengine_config.py', diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index 70f2e3036ca..0f425570032 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -285,6 +285,7 @@ def _lazy_evaluate_fields_default(self): # The number of characters in each prompt which don't contribute to width invisible_chars = Dict() + @default('invisible_chars') def _invisible_chars_default(self): return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0} @@ -321,7 +322,9 @@ def update_prompt(self, name, new_template=None): invis_chars = _invisible_characters(self._render(name, color=True)) self.invisible_chars[name] = invis_chars - def _update_prompt_trait(self, traitname, new_template): + def _update_prompt_trait(self, changes): + traitname = changes['name'] + new_template = changes['new'] name = traitname[:-9] # Cut off '_template' self.update_prompt(name, new_template) From d07581c7b23a85b9339690a8b82edebbe7311d61 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 11:00:50 -0700 Subject: [PATCH 0312/4859] Remove warning filtering in iptest. --- IPython/testing/iptest.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 35cab1a3cab..d100ec2fcfc 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -46,15 +46,6 @@ # Enable printing all warnings raise by IPython's modules warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') - -if version_info < (4,2): - # ignore some warnings from traitlets until 6.0 - warnings.filterwarnings('ignore', message='.*on_trait_change is deprecated: use observe instead.*') - warnings.filterwarnings('ignore', message='.*was set from the constructor.*', category=Warning, module='IPython.*') - warnings.filterwarnings('ignore', message='.*use the instance .help string directly, like x.help.*', category=DeprecationWarning, module='IPython.*') -else : - warnings.warn('iptest has been filtering out for Traitlets warnings messages, for 2 minor versions (since 4.x), please consider updating to use new API') - if version_info < (6,): # nose.tools renames all things from `camelCase` to `snake_case` which raise an # warning with the runner they also import from standard import library. (as of Dec 2015) From 74837a32d76b7eab5085c08d199a6ff013c79d65 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 11:05:28 -0700 Subject: [PATCH 0313/4859] Update /IPython/lib/latextool.py to use new traitlets API. --- IPython/lib/latextools.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index 88b0978b036..c0d646ba3aa 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -39,24 +39,24 @@ def _config_default(self): # for display style, the default ["matplotlib", "dvipng"] can # be used. To NOT use dvipng so that other repr such as # unicode pretty printing is used, you can use ["matplotlib"]. - config=True) + ).tag(config=True) use_breqn = Bool( True, help="Use breqn.sty to automatically break long equations. " "This configuration takes effect only for dvipng backend.", - config=True) + ).tag(config=True) packages = List( ['amsmath', 'amsthm', 'amssymb', 'bm'], help="A list of packages to use for dvipng backend. " "'breqn' will be automatically appended when use_breqn=True.", - config=True) + ).tag(config=True) preamble = Unicode( help="Additional preamble to use when generating LaTeX source " "for dvipng backend.", - config=True) + ).tag(config=True) def latex_to_png(s, encode=False, backend=None, wrap=False): From fd8a728e6adb819bb9aa2b163f055195e2922652 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 14:20:59 -0700 Subject: [PATCH 0314/4859] Eventloops are not created if IPY_TEST_SIMPLE_PROMPT set, or not a tty. --- IPython/terminal/ptshell.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 7751a055065..f0d4dcc5f54 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -382,8 +382,9 @@ def mainloop(self): break except KeyboardInterrupt: print("\nKeyboardInterrupt escaped interact()\n") - - self._eventloop.close() + + if hasattr(self, '_eventloop'): + self._eventloop.close() _inputhook = None def inputhook(self, context): From 35272e2d59366840f3f4480df1d2428d7bee062f Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 18 May 2016 10:57:25 +0200 Subject: [PATCH 0315/4859] get whatsnew changes from Z.X branches some minor backport releases got changelog updates without pushing those changelogs to master I grabbed the updates with `git checkout [branch] whatsnew/X` --- docs/source/whatsnew/github-stats-1.0.rst | 99 +++++++++++++++++++++++ docs/source/whatsnew/github-stats-2.0.rst | 9 ++- docs/source/whatsnew/github-stats-3.rst | 49 +++++++++++ docs/source/whatsnew/version2.0.rst | 9 ++- docs/source/whatsnew/version3.rst | 42 ++++++++++ 5 files changed, 204 insertions(+), 4 deletions(-) diff --git a/docs/source/whatsnew/github-stats-1.0.rst b/docs/source/whatsnew/github-stats-1.0.rst index d0b1ae18d6a..7f0da0bebdd 100644 --- a/docs/source/whatsnew/github-stats-1.0.rst +++ b/docs/source/whatsnew/github-stats-1.0.rst @@ -3,6 +3,105 @@ Issues closed in the 1.0 development cycle ========================================== + +Issues closed in 1.2 +-------------------- + +GitHub stats for 2013/09/09 - 2014/02/21 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +The following 13 authors contributed 84 commits. + +* Benjamin Ragan-Kelley +* Daryl Herzmann +* Doug Blank +* Fernando Perez +* James Porter +* Juergen Hasch +* Julian Taylor +* Kyle Kelley +* Lawrence Fu +* Matthias Bussonnier +* Paul Ivanov +* Pascal Schetelat +* Puneeth Chaganti +* Takeshi Kanmae +* Thomas Kluyver + +We closed a total of 55 issues, 38 pull requests and 17 regular issues; +this is the full list (generated with the script :file:`tools/github_stats.py`): + +Pull Requests (38): + +1.2.1: + +* :ghpull:`4372`: Don't assume that SyntaxTB is always called with a SyntaxError +* :ghpull:`5166`: remove mktemp usage +* :ghpull:`5163`: Simplify implementation of TemporaryWorkingDirectory. +* :ghpull:`5105`: add index to format to support py2.6 + +1.2.0: + +* :ghpull:`4972`: Work around problem in doctest discovery in Python 3.4 with PyQt +* :ghpull:`4934`: `ipython profile create` respects `--ipython-dir` +* :ghpull:`4845`: Add Origin Checking. +* :ghpull:`4928`: use importlib.machinery when available +* :ghpull:`4849`: Various unicode fixes (mostly on Windows) +* :ghpull:`4880`: set profile name from profile_dir +* :ghpull:`4908`: detect builtin docstrings in oinspect +* :ghpull:`4909`: sort dictionary keys before comparison, ordering is not guaranteed +* :ghpull:`4903`: use https for all embeds +* :ghpull:`4868`: Static path fixes +* :ghpull:`4820`: fix regex for cleaning old logs with ipcluster +* :ghpull:`4840`: Error in Session.send_raw() +* :ghpull:`4762`: whitelist alphanumeric characters for cookie_name +* :ghpull:`4748`: fix race condition in profiledir creation. +* :ghpull:`4720`: never use ssh multiplexer in tunnels +* :ghpull:`4738`: don't inject help into user_ns +* :ghpull:`4722`: allow purging local results as long as they are not outstanding +* :ghpull:`4668`: Make non-ASCII docstring unicode +* :ghpull:`4639`: Minor import fix to get qtconsole with --pylab=qt working +* :ghpull:`4453`: Play nice with App Nap +* :ghpull:`4609`: Fix bytes regex for Python 3. +* :ghpull:`4488`: fix typo in message spec doc +* :ghpull:`4346`: getpass() on Windows & Python 2 needs bytes prompt +* :ghpull:`4230`: Switch correctly to the user's default matplotlib backend after inline. +* :ghpull:`4214`: engine ID metadata should be unicode, not bytes +* :ghpull:`4232`: no highlight if no language specified +* :ghpull:`4218`: Fix display of SyntaxError when .py file is modified +* :ghpull:`4217`: avoid importing numpy at the module level +* :ghpull:`4213`: fixed dead link in examples/notebooks readme to Part 3 +* :ghpull:`4183`: ESC should be handled by CM if tooltip is not on +* :ghpull:`4193`: Update for #3549: Append Firefox overflow-x fix +* :ghpull:`4205`: use TextIOWrapper when communicating with pandoc subprocess +* :ghpull:`4204`: remove some extraneous print statements from IPython.parallel +* :ghpull:`4201`: HeadingCells cannot be split or merged + +1.2.1: + +* :ghissue:`5101`: IPython 1.2.0: notebook fail with "500 Internal Server Error" + +1.2.0: + +* :ghissue:`4892`: IPython.qt test failure with python3.4 +* :ghissue:`4810`: ipcluster bug in clean_logs flag +* :ghissue:`4765`: missing build script for highlight.js +* :ghissue:`4761`: ipv6 address triggers cookie exception +* :ghissue:`4721`: purge_results with jobid crashing - looking for insight +* :ghissue:`4602`: "ipcluster stop" fails after "ipcluster start --daemonize" using python3.3 +* :ghissue:`3386`: Magic %paste not working in Python 3.3.2. TypeError: Type str doesn't support the buffer API +* :ghissue:`4485`: Incorrect info in "Messaging in IPython" documentation. +* :ghissue:`4351`: /parallel/apps/launcher.py error +* :ghissue:`4334`: NotebookApp.webapp_settings static_url_prefix causes crash +* :ghissue:`4039`: Celltoolbar example issue +* :ghissue:`4256`: IPython no longer handles unicode file names +* :ghissue:`4122`: Nbconvert [windows]: Inconsistent line endings in markdown cells exported to latex +* :ghissue:`3819`: nbconvert add extra blank line to code block on Windows. +* :ghissue:`4203`: remove spurious print statement from parallel annoted functions +* :ghissue:`4200`: Notebook: merging a heading cell and markdown cell cannot be undone + + Issues closed in 1.1 -------------------- diff --git a/docs/source/whatsnew/github-stats-2.0.rst b/docs/source/whatsnew/github-stats-2.0.rst index 7fc99e67fb8..6eb0e0537a5 100644 --- a/docs/source/whatsnew/github-stats-2.0.rst +++ b/docs/source/whatsnew/github-stats-2.0.rst @@ -3,11 +3,16 @@ Issues closed in the 2.x development cycle ========================================== -Issues closed in 2.4.0 +Issues closed in 2.4.1 ---------------------- GitHub stats for 2014/11/01 - 2015/01/30 +.. note:: + + IPython 2.4.0 was released without a few of the backports listed below. + 2.4.1 has the correct patches intended for 2.4.0. + These lists are automatically generated, and may be incomplete or contain duplicates. The following 7 authors contributed 35 commits. @@ -31,7 +36,7 @@ Pull Requests (10): * :ghpull:`6778`: backport nbformat v4 to 2.x * :ghpull:`6761`: object_info_reply field is oname, not name * :ghpull:`6653`: Fix IPython.utils.ansispan() to ignore stray [0m -* :ghpull:`6706`: Correctly display prompt numbers that are 'None' +* :ghpull:`6706`: Correctly display prompt numbers that are ``None`` * :ghpull:`6634`: don't use contains in SelectWidget item_query * :ghpull:`6593`: note how to start the qtconsole * :ghpull:`6281`: more minor fixes to release scripts diff --git a/docs/source/whatsnew/github-stats-3.rst b/docs/source/whatsnew/github-stats-3.rst index 2abd3fa945b..2c91ef76b48 100644 --- a/docs/source/whatsnew/github-stats-3.rst +++ b/docs/source/whatsnew/github-stats-3.rst @@ -3,6 +3,55 @@ Issues closed in the 3.x development cycle ========================================== + +Issues closed in 3.2.1 +---------------------- + +GitHub stats for 2015/06/22 - 2015/07/12 (since 3.2) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 1 issue and merged 3 pull requests. +The full list can be seen `on GitHub `_ + +The following 5 authors contributed 9 commits. + +* Benjamin Ragan-Kelley +* Matthias Bussonnier +* Nitin Dahyabhai +* Sebastiaan Mathot +* Thomas Kluyver + + +Issues closed in 3.2 +-------------------- + +GitHub stats for 2015/04/03 - 2015/06/21 (since 3.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 7 issues and merged 30 pull requests. +The full list can be seen `on GitHub `_ + +The following 15 authors contributed 74 commits. + +* Benjamin Ragan-Kelley +* Brian Gough +* Damián Avila +* Ian Barfield +* Jason Grout +* Jeff Hussmann +* Jessica B. Hamrick +* Kyle Kelley +* Matthias Bussonnier +* Nicholas Bollweg +* Randy Lai +* Scott Sanderson +* Sylvain Corlay +* Thomas A Caswell +* Thomas Kluyver + + Issues closed in 3.1 -------------------- diff --git a/docs/source/whatsnew/version2.0.rst b/docs/source/whatsnew/version2.0.rst index 9606837a3f1..83f02871b2b 100644 --- a/docs/source/whatsnew/version2.0.rst +++ b/docs/source/whatsnew/version2.0.rst @@ -5,10 +5,15 @@ Release 2.4 =========== -January, 2015 +January, 2014 + +.. note:: + + Some of the patches marked for 2.4 were left out of 2.4.0. + Please use 2.4.1. - backport read support for nbformat v4 from IPython 3 -- support for PyQt5 +- support for PyQt5 in the kernel (not QtConsole) - support for Pygments 2.0 For more information on what fixes have been backported to 2.4, diff --git a/docs/source/whatsnew/version3.rst b/docs/source/whatsnew/version3.rst index 215f72b65c4..3372aaaa957 100644 --- a/docs/source/whatsnew/version3.rst +++ b/docs/source/whatsnew/version3.rst @@ -2,6 +2,48 @@ 3.x Series ============ +IPython 3.2.3 +============= + +Fixes compatibility with Python 3.4.4. + +IPython 3.2.2 +============= + +Address vulnerabilities when files have maliciously crafted filenames (CVE-2015-6938), +or vulnerability when opening text files with malicious binary content (CVE pending). + +Users are **strongly** encouraged to upgrade immediately. +There are also a few small unicode and nbconvert-related fixes. + + +IPython 3.2.1 +============= + +IPython 3.2.1 is a small bugfix release, primarily for cross-site security fixes in the notebook. +Users are **strongly** encouraged to upgrade immediately. +There are also a few small unicode and nbconvert-related fixes. + +See :ref:`issues_list_3` for details. + + +IPython 3.2 +=========== + +IPython 3.2 contains important security fixes. Users are **strongly** encouraged to upgrade immediately. + +Highlights: + +- Address cross-site scripting vulnerabilities CVE-2015-4706, CVE-2015-4707 +- A security improvement that set the secure attribute to login cookie to prevent them to be sent over http +- Revert the face color of matplotlib axes in the inline backend to not be transparent. +- Enable mathjax safe mode by default +- Fix XSS vulnerability in JSON error messages +- Various widget-related fixes + +See :ref:`issues_list_3` for details. + + IPython 3.1 =========== From 777642ebe5c7a94c440c0c9b61215246b467c19d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 17 May 2016 14:26:08 -0700 Subject: [PATCH 0316/4859] Remove unused import --- IPython/utils/terminal.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/utils/terminal.py b/IPython/utils/terminal.py index a1f0f73308e..3bdcee321c0 100644 --- a/IPython/utils/terminal.py +++ b/IPython/utils/terminal.py @@ -13,7 +13,6 @@ # Distributed under the terms of the Modified BSD License. import os -import struct import sys import warnings try: From f0e1cb1b7e072a342e5e4971716038007ffc8a53 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 18 May 2016 10:03:12 -0700 Subject: [PATCH 0317/4859] fix Traitlets 4.2 API usage. --- IPython/core/extensions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/IPython/core/extensions.py b/IPython/core/extensions.py index 5c05d46254d..87c671130b8 100644 --- a/IPython/core/extensions.py +++ b/IPython/core/extensions.py @@ -49,8 +49,7 @@ def load_ipython_extension(ipython): is added to ``sys.path`` automatically. """ - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC').tag( - allow_none=True) + shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) def __init__(self, shell=None, **kwargs): super(ExtensionManager, self).__init__(shell=shell, **kwargs) From c4587c2140e36d42124964c1d74941e19bd243d7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 18 May 2016 10:17:50 -0700 Subject: [PATCH 0318/4859] Remove Jedi integration before 5.0 There are a few bugs, and things to iron out that we will likely not have the chance to do before 5.0, do deactivating (removing) jedi integration for now, we can always resurrect the current code from git history. --- IPython/core/completer.py | 61 +--------------------------- IPython/core/tests/test_completer.py | 15 ++----- setup.py | 1 - 3 files changed, 4 insertions(+), 73 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 21c9110a942..cbff2aa0e7a 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -77,10 +77,6 @@ from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 from traitlets import Bool, Enum, observe -import jedi -import jedi.api.helpers -import jedi.parser.user_context - #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -649,6 +645,7 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, # All active matcher routines for completion self.matchers = [ + self.python_matches, self.file_matches, self.magic_matches, self.python_func_kw_matches, @@ -768,60 +765,6 @@ def magic_matches(self, text): comp += [ pre+m for m in line_magics if m.startswith(bare_text)] return [cast_unicode_py2(c) for c in comp] - def python_jedi_matches(self, text, line_buffer, cursor_pos): - """Match attributes or global Python names using Jedi.""" - if line_buffer.startswith('aimport ') or line_buffer.startswith('%aimport '): - return () - namespaces = [] - if self.namespace is None: - import __main__ - namespaces.append(__main__.__dict__) - else: - namespaces.append(self.namespace) - if self.global_namespace is not None: - namespaces.append(self.global_namespace) - - # cursor_pos is an it, jedi wants line and column - - interpreter = jedi.Interpreter(line_buffer, namespaces, column=cursor_pos) - path = jedi.parser.user_context.UserContext(line_buffer, \ - (1, len(line_buffer))).get_path_until_cursor() - path, dot, like = jedi.api.helpers.completion_parts(path) - if text.startswith('.'): - # text will be `.` on completions like `a[0].` - before = dot - else: - before = line_buffer[:len(line_buffer) - len(like)] - - - def trim_start(completion): - """completions need to start with `text`, trim the beginning until it does""" - ltext = text.lower() - lcomp = completion.lower() - if ltext in lcomp and not (lcomp.startswith(ltext)): - start_index = lcomp.index(ltext) - if cursor_pos: - if start_index >= cursor_pos: - start_index = min(start_index, cursor_pos) - return completion[start_index:] - return completion - - completions = interpreter.completions() - - completion_text = [c.name_with_symbols for c in completions] - - if self.omit__names: - if self.omit__names == 1: - # true if txt is _not_ a __ name, false otherwise: - no__name = lambda txt: not txt.startswith('__') - else: - # true if txt is _not_ a _ name, false otherwise: - no__name = lambda txt: not txt.startswith('_') - completion_text = filter(no__name, completion_text) - - - return [trim_start(before + c_text) for c_text in completion_text] - def python_matches(self, text): """Match attributes or global python names""" @@ -1255,8 +1198,6 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): # different types of objects. The rlcomplete() method could then # simply collapse the dict into a list for readline, but we'd have # richer completion semantics in other evironments. - self.matches.extend(self.python_jedi_matches(text, line_buffer, cursor_pos)) - self.matches = sorted(set(self.matches), key=completions_sorting_key) return text, self.matches diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 1ef7d3f4c9d..4f3ff800088 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -279,20 +279,11 @@ def _(line, cursor_pos, expect, message): _,c = ip.complete('.', line=line, cursor_pos=cursor_pos) nt.assert_in(expect, c, message%c) - yield _, 'a[0].', 5, '.real', "Should have completed on a[0].: %s" - yield _, 'a[0].r', 6, '.real', "Should have completed on a[0].r: %s" + yield _, 'a[0].', 5, 'a[0].real', "Should have completed on a[0].: %s" + yield _, 'a[0].r', 6, 'a[0].real', "Should have completed on a[0].r: %s" if sys.version_info > (3,4): - yield _, 'a[0].from_', 10, '.from_bytes', "Should have completed on a[0].from_: %s" - - - def _2(): - # jedi bug, this will be empty, makeitfail for now, - # once jedi is fixed, switch to assert_in - # https://github.com/davidhalter/jedi/issues/718 - _,c = ip.complete('.',line='a[0].from', cursor_pos=9) - nt.assert_not_in('.from_bytes', c, "Should not have completed on a[0].from (jedi bug), if fails, update test to assert_in: %s"%c) - yield _2 + yield _, 'a[0].from_', 10, 'a[0].from_bytes', "Should have completed on a[0].from_: %s" diff --git a/setup.py b/setup.py index b0c015184a8..ab74fb82158 100755 --- a/setup.py +++ b/setup.py @@ -191,7 +191,6 @@ def run(self): ) install_requires = [ 'setuptools>=18.5', - 'jedi', 'decorator', 'pickleshare', 'simplegeneric>0.8', From 5d76f1110a5d8d535bf0531210fdc305b1afbc97 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 19 May 2016 13:59:02 -0700 Subject: [PATCH 0319/4859] A few style fixes: Missing parameters in function call, use context manager correctly, For/else is also a rarely use construction that can be confusing. As we don't have break statement in the loop, there is no need for it. --- IPython/core/tests/test_oinspect.py | 2 +- IPython/external/decorators/_numpy_testing_utils.py | 10 +++------- IPython/lib/lexers.py | 10 ++++------ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index ebb18026d8c..ed6c08a2b21 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -398,7 +398,7 @@ def foo(self): def test_property_docstring_is_in_info_for_detail_level_0(): class A(object): @property - def foobar(): + def foobar(self): """This is `foobar` property.""" pass diff --git a/IPython/external/decorators/_numpy_testing_utils.py b/IPython/external/decorators/_numpy_testing_utils.py index a01e3468853..ad7bd0f9817 100644 --- a/IPython/external/decorators/_numpy_testing_utils.py +++ b/IPython/external/decorators/_numpy_testing_utils.py @@ -85,7 +85,7 @@ def showwarning(*args, **kwargs): else: return None - def __exit__(self): + def __exit__(self, type_, value, traceback): if not self._entered: raise RuntimeError("Cannot exit %r without entering first" % self) self._module.filters = self._filters @@ -101,10 +101,8 @@ def assert_warns(warning_class, func, *args, **kw): # XXX: once we may depend on python >= 2.6, this can be replaced by the # warnings module context manager. - ctx = WarningManager(record=True) - l = ctx.__enter__() - warnings.simplefilter('always') - try: + with WarningManager(record=True) as l: + warnings.simplefilter('always') func(*args, **kw) if not len(l) > 0: raise AssertionError("No warning raised when calling %s" @@ -112,5 +110,3 @@ def assert_warns(warning_class, func, *args, **kw): if not l[0].category is warning_class: raise AssertionError("First warning for %s is not a " \ "%s( is %s)" % (func.__name__, warning_class, l[0])) - finally: - ctx.__exit__() diff --git a/IPython/lib/lexers.py b/IPython/lib/lexers.py index 908188b0add..f983a3ddc80 100644 --- a/IPython/lib/lexers.py +++ b/IPython/lib/lexers.py @@ -39,7 +39,7 @@ Lexer, DelegatingLexer, RegexLexer, do_insertions, bygroups, using, ) from pygments.token import ( - Comment, Generic, Keyword, Literal, Name, Operator, Other, Text, Error, + Generic, Keyword, Literal, Name, Operator, Other, Text, Error, ) from pygments.util import get_bool_opt @@ -83,13 +83,11 @@ def build_ipy_lexer(python3): # we will also have two IPython lexer classes. if python3: PyLexer = Python3Lexer - clsname = 'IPython3Lexer' name = 'IPython3' aliases = ['ipython3'] doc = """IPython3 Lexer""" else: PyLexer = PythonLexer - clsname = 'IPythonLexer' name = 'IPython' aliases = ['ipython2', 'ipython'] doc = """IPython Lexer""" @@ -468,9 +466,9 @@ def get_tokens_unprocessed(self, text): if insertion: self.insertions.append((len(self.buffer), [insertion])) self.buffer += code - else: - for token in self.buffered_tokens(): - yield token + + for token in self.buffered_tokens(): + yield token class IPyLexer(Lexer): """ From fe2ef50e00d836e4596ed19ea9c4d5db1e3a521b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 20 May 2016 14:12:34 +0100 Subject: [PATCH 0320/4859] Catch failure to find source file for traceback Closes gh-9486 --- IPython/core/ultratb.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 4ba08ba502f..0d8bb98a753 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -925,7 +925,12 @@ def format_record(self, frame, file, lnum, func, lines, index): elif file.endswith(('.pyc', '.pyo')): # Look up the corresponding source file. - file = openpy.source_from_cache(file) + try: + file = openpy.source_from_cache(file) + except ValueError: + # Failed to get the source file for some reason + # E.g. https://github.com/ipython/ipython/issues/9486 + return '%s %s\n' % (link, call) def linereader(file=file, lnum=[lnum], getline=ulinecache.getline): line = getline(file, lnum[0]) From 55866283e89acbf2f9e1ea047e98e16fad5e732c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 19 May 2016 13:49:17 -0700 Subject: [PATCH 0321/4859] Remove Pydb integration as Pydb is unmaintained and not ion PyPI Closes # 9482 --- IPython/core/completer.py | 3 +- IPython/core/debugger.py | 52 ++----------------- IPython/core/interactiveshell.py | 12 ++--- IPython/core/shellapp.py | 12 +---- .../whatsnew/pr/incompat-remove-pydb.rst | 1 + 5 files changed, 10 insertions(+), 70 deletions(-) create mode 100644 docs/source/whatsnew/pr/incompat-remove-pydb.rst diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 21c9110a942..f0ed4b3b4b9 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -657,8 +657,7 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, def all_completions(self, text): """ - Wrapper around the complete method for the benefit of emacs - and pydb. + Wrapper around the complete method for the benefit of emacs. """ return self.complete(text)[1] diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 0f0c78a81fc..cf4fdcdabbe 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -37,25 +37,10 @@ from IPython.core.excolors import exception_colors from IPython.testing.skipdoctest import skip_doctest -# See if we can use pydb. -has_pydb = False prompt = 'ipdb> ' + #We have to check this directly from sys.argv, config struct not yet available -if '--pydb' in sys.argv: - try: - import pydb - if hasattr(pydb.pydb, "runl") and pydb.version>'1.17': - # Version 1.17 is broken, and that's what ships with Ubuntu Edgy, so we - # better protect against it. - has_pydb = True - except ImportError: - print("Pydb (http://bashdb.sourceforge.net/pydb/) does not seem to be available") - -if has_pydb: - from pydb import Pdb as OldPdb - prompt = 'ipydb> ' -else: - from pdb import Pdb as OldPdb +from pdb import Pdb as OldPdb # Allow the set_trace code to operate outside of an ipython instance, even if # it does so with some limitations. The rest of this support is implemented in @@ -220,14 +205,9 @@ def __init__(self,color_scheme='NoColor',completekey=None, except (TypeError, ValueError): raise ValueError("Context must be a positive integer") - if has_pydb and completekey is None: - OldPdb.__init__(self,stdin=stdin,stdout=sys.stdout) - else: - OldPdb.__init__(self,completekey,stdin,stdout) + OldPdb.__init__(self,completekey,stdin,stdout) # IPython changes... - self.is_pydb = has_pydb - self.shell = get_ipython() if self.shell is None: @@ -236,26 +216,6 @@ def __init__(self,color_scheme='NoColor',completekey=None, TerminalInteractiveShell self.shell = TerminalInteractiveShell.instance() - if self.is_pydb: - - # interactiveshell.py's ipalias seems to want pdb's checkline - # which located in pydb.fn - import pydb.fns - self.checkline = lambda filename, lineno: \ - pydb.fns.checkline(self, filename, lineno) - - self.curframe = None - self.do_restart = self.new_do_restart - - self.old_all_completions = self.shell.Completer.all_completions - self.shell.Completer.all_completions=self.all_completions - - self.do_list = decorate_fn_with_doc(self.list_command_pydb, - OldPdb.do_list) - self.do_l = self.do_list - self.do_frame = decorate_fn_with_doc(self.new_do_frame, - OldPdb.do_frame) - self.aliases = {} # Create color table: we copy the default one from the traceback @@ -482,12 +442,6 @@ def __format_line(self, tpl_line, filename, lineno, line, arrow = False): return tpl_line % (bp_mark_color + bp_mark, num, line) - def list_command_pydb(self, arg): - """List command to use if we have a newer pydb installed""" - filename, first, last = OldPdb.parse_list_cmd(self, arg) - if filename is not None: - self.print_list_lines(filename, first, last) - def print_list_lines(self, filename, first, last): """The printing (as opposed to the parsing part of a 'list' command.""" diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 6a18ecd48c0..c6e913ad433 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -31,7 +31,7 @@ from pickleshare import PickleShareDB from traitlets.config.configurable import SingletonConfigurable -from IPython.core import debugger, oinspect +from IPython.core import oinspect from IPython.core import magic from IPython.core import page from IPython.core import prefilter @@ -974,7 +974,7 @@ def _set_call_pdb(self,val): 'Control auto-activation of pdb at exceptions') def debugger(self,force=False): - """Call the pydb/pdb debugger. + """Call the pdb debugger. Keywords: @@ -991,15 +991,9 @@ def debugger(self,force=False): error('No traceback has been produced, nothing to debug.') return - # use pydb if available - if debugger.has_pydb: - from pydb import pm - else: - # fallback to our internal debugger - pm = lambda : self.InteractiveTB.debugger(force=True) with self.readline_no_record: - pm() + self.InteractiveTB.debugger(force=True) #------------------------------------------------------------------------- # Things related to IPython's various namespaces diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 9bc99afd644..a1d25546345 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -22,7 +22,7 @@ from IPython.utils.contexts import preserve_keys from IPython.utils.path import filefind from traitlets import ( - Unicode, Instance, List, Bool, CaselessStrEnum, default, observe, + Unicode, Instance, List, Bool, CaselessStrEnum, observe, ) from IPython.lib.inputhook import guis @@ -50,14 +50,6 @@ "Enable auto calling the pdb debugger after every exception.", "Disable auto calling the pdb debugger after every exception." ) -# pydb flag doesn't do any config, as core.debugger switches on import, -# which is before parsing. This just allows the flag to be passed. -shell_flags.update(dict( - pydb = ({}, - """Use the third party 'pydb' package as debugger, instead of pdb. - Requires that pydb is installed.""" - ) -)) addflag('pprint', 'PlainTextFormatter.pprint', "Enable auto pretty printing of results.", "Disable auto pretty printing of results." @@ -321,7 +313,7 @@ def _run_exec_lines(self): def _exec_file(self, fname, shell_futures=False): try: full_filename = filefind(fname, [u'.', self.ipython_dir]) - except IOError as e: + except IOError: self.log.warning("File not found: %r"%fname) return # Make sure that the running script gets a proper sys.argv as if it diff --git a/docs/source/whatsnew/pr/incompat-remove-pydb.rst b/docs/source/whatsnew/pr/incompat-remove-pydb.rst new file mode 100644 index 00000000000..4fe0fa5f5bf --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-remove-pydb.rst @@ -0,0 +1 @@ +Integration with pydb has been removed since pydb development has been stopped since 2012, and pydb is not installable from PyPI From f1b674736af0cad9b5445515bca3644f74bf6572 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 18 May 2016 12:13:21 -0700 Subject: [PATCH 0322/4859] Allow a raise on bad config using env variable. Closes https://github.com/ipython/ipython/issues/8927 --- IPython/core/application.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 0c9f0a63c3f..aed6184c2ec 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -43,6 +43,16 @@ "/etc/ipython", ] +_envvar = os.environ.get('IPYTHON_SUPPRESS_ERRORS') +if _envvar in {None, ''}: + IPYTHON_SUPPRESS_ERRORS = None +else: + if _envvar.lower() in {'1','true'}: + IPYTHON_SUPPRESS_ERRORS = True + elif _envvar.lower() in {'0','false'} : + IPYTHON_SUPPRESS_ERRORS = False + else: + sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar ) # aliases and flags @@ -272,18 +282,33 @@ def _ipython_dir_changed(self, change): self.log.error("couldn't create path %s: %s", path, e) self.log.debug("IPYTHONDIR set to: %s" % new) - def load_config_file(self, suppress_errors=True): + def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_ERRORS): """Load the config file. By default, errors in loading config are handled, and a warning printed on screen. For testing, the suppress_errors option is set to False, so errors will make tests fail. + + `supress_errors` default value is to be `None` in which case the + behavior default to the one of `traitlets.Application`. + + The default value can be changed : + - to `False` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '0', or 'false' (case insensitive). + - to `True` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '1' or 'true' (case insensitive). + - to `None` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '' (empty string) or leaving it unset. + + Any other value are invalid, and will make IPython exit with a non-zero return code. """ + + self.log.debug("Searching path %s for config files", self.config_file_paths) base_config = 'ipython_config.py' self.log.debug("Attempting to load config file: %s" % base_config) try: + if suppress_errors is not None: + old_value = Application.raise_config_file_errors + Application.raise_config_file_errors = not suppress_errors; Application.load_config_file( self, base_config, @@ -293,6 +318,8 @@ def load_config_file(self, suppress_errors=True): # ignore errors loading parent self.log.debug("Config file %s not found", base_config) pass + if suppress_errors is not None: + Application.raise_config_file_errors = old_value for config_file_name in self.config_files: if not config_file_name or config_file_name == base_config: From 208d0c1c0db2b1056678898dd300eb38c7625f9e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 20 May 2016 11:51:41 -0700 Subject: [PATCH 0323/4859] Correctly teardown test case, avoid filehandle leaking. --- IPython/testing/iptest.py | 2 ++ IPython/testing/tests/test_tools.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index d100ec2fcfc..9e1a883acd1 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -44,6 +44,8 @@ # Enable printing all warnings raise by IPython's modules +if sys.version_info > (3,0): + warnings.filterwarnings('error', message='.*', category=ResourceWarning, module='.*') warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') if version_info < (6,): diff --git a/IPython/testing/tests/test_tools.py b/IPython/testing/tests/test_tools.py index a4c2e775795..9c6db658c49 100644 --- a/IPython/testing/tests/test_tools.py +++ b/IPython/testing/tests/test_tools.py @@ -132,3 +132,9 @@ def test_exception_path2(self): ) out = "A\r\nB" tt.ipexec_validate(self.fname, expected_out=out, expected_err="C\r\nD") + + + def tearDown(self): + # tear down correctly the mixin, + # unittest.TestCase.tearDown does nothing + tt.TempFileMixin.tearDown(self) From 7c920975924cc5c8bec30c80996398df415e3f02 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 20 May 2016 14:14:13 -0700 Subject: [PATCH 0324/4859] /change/set/ --- IPython/core/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index aed6184c2ec..aa59e5f560b 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -292,7 +292,7 @@ def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_ERRORS): `supress_errors` default value is to be `None` in which case the behavior default to the one of `traitlets.Application`. - The default value can be changed : + The default value can be set : - to `False` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '0', or 'false' (case insensitive). - to `True` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '1' or 'true' (case insensitive). - to `None` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '' (empty string) or leaving it unset. From 80a92a58bd9e9980152924be7b4740e93d1e730d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 24 May 2016 11:07:48 -0700 Subject: [PATCH 0325/4859] Rename env variable. --- IPython/core/application.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index aa59e5f560b..038891e8423 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -43,16 +43,16 @@ "/etc/ipython", ] -_envvar = os.environ.get('IPYTHON_SUPPRESS_ERRORS') +_envvar = os.environ.get('IPYTHON_SUPPRESS_CONFIG_ERRORS') if _envvar in {None, ''}: - IPYTHON_SUPPRESS_ERRORS = None + IPYTHON_SUPPRESS_CONFIG_ERRORS = None else: if _envvar.lower() in {'1','true'}: - IPYTHON_SUPPRESS_ERRORS = True + IPYTHON_SUPPRESS_CONFIG_ERRORS = True elif _envvar.lower() in {'0','false'} : - IPYTHON_SUPPRESS_ERRORS = False + IPYTHON_SUPPRESS_CONFIG_ERRORS = False else: - sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar ) + sys.exit("Unsupported value for environment variable: 'IPYTHON_SUPPRESS_CONFIG_ERRORS' is set to '%s' which is none of {'0', '1', 'false', 'true', ''}."% _envvar ) # aliases and flags @@ -282,7 +282,7 @@ def _ipython_dir_changed(self, change): self.log.error("couldn't create path %s: %s", path, e) self.log.debug("IPYTHONDIR set to: %s" % new) - def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_ERRORS): + def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_CONFIG_ERRORS): """Load the config file. By default, errors in loading config are handled, and a warning @@ -293,9 +293,9 @@ def load_config_file(self, suppress_errors=IPYTHON_SUPPRESS_ERRORS): behavior default to the one of `traitlets.Application`. The default value can be set : - - to `False` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '0', or 'false' (case insensitive). - - to `True` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '1' or 'true' (case insensitive). - - to `None` by setting 'IPYTHON_SUPPRESS_ERRORS' environment variable to '' (empty string) or leaving it unset. + - to `False` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '0', or 'false' (case insensitive). + - to `True` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '1' or 'true' (case insensitive). + - to `None` by setting 'IPYTHON_SUPPRESS_CONFIG_ERRORS' environment variable to '' (empty string) or leaving it unset. Any other value are invalid, and will make IPython exit with a non-zero return code. """ From fff0bd6f8b0b5e2424734d4587c4d69c040417bb Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Wed, 25 May 2016 10:04:01 +0200 Subject: [PATCH 0326/4859] Added option to ptshell for highlighting matching brackets. --- IPython/terminal/ptshell.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c7d8486a14f..351e98bbb82 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -17,7 +17,7 @@ from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode +from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface @@ -25,6 +25,7 @@ from prompt_toolkit.keys import Keys from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer +from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor from prompt_toolkit.styles import PygmentsStyle, DynamicStyle from pygments.styles import get_style_by_name, get_all_styles @@ -145,7 +146,10 @@ def _highlighting_style_changed(self, change): help="Display a multi column completion menu.", ).tag(config=True) - + highlight_matching_brackets = Bool(False, + help="Highlight matching brackets .", + ).tag(config=True) + @observe('term_title') def init_term_title(self, change=None): # Enable or disable the terminal title. @@ -300,6 +304,13 @@ def _layout_options(self): 'get_continuation_tokens':self.get_continuation_tokens, 'multiline':True, 'display_completions_in_columns': self.display_completions_in_columns, + + # Highlight matching brackets, but only when this setting is + # enabled, and only when the DEFAULT_BUFFER has the focus. + 'extra_input_processors': [ConditionalProcessor( + processor=HighlightMatchingBracketProcessor(chars='[](){}'), + filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & + Condition(lambda cli: self.highlight_matching_brackets))], } def _update_layout(self): From 36fd81d61b41c93c32516afae37a25050af76b5d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 25 May 2016 12:30:22 -0700 Subject: [PATCH 0327/4859] Update docs on `.inputrc` and input mode. Bump #9388 to 6.0 --- docs/source/interactive/reference.rst | 67 +++++---------------------- 1 file changed, 12 insertions(+), 55 deletions(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 3ef89a7ee65..4d3b2345447 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -254,61 +254,18 @@ time you restart it. By default, the history file is named Autoindent ++++++++++ -IPython can recognize lines ending in ':' and indent the next line, -while also un-indenting automatically after 'raise' or 'return'. - -This feature uses the readline library, so it will honor your -:file:`~/.inputrc` configuration (or whatever file your :envvar:`INPUTRC` environment variable points -to). Adding the following lines to your :file:`.inputrc` file can make -indenting/unindenting more convenient (M-i indents, M-u unindents):: - - # if you don't already have a ~/.inputrc file, you need this include: - $include /etc/inputrc - - $if Python - "\M-i": " " - "\M-u": "\d\d\d\d" - $endif - -Note that there are 4 spaces between the quote marks after "M-i" above. - -.. warning:: - - Setting the above indents will cause problems with unicode text entry in - the terminal. - -.. warning:: - - Autoindent is ON by default, but it can cause problems with the pasting of - multi-line indented code (the pasted code gets re-indented on each line). A - magic function %autoindent allows you to toggle it on/off at runtime. You - can also disable it permanently on in your :file:`ipython_config.py` file - (set TerminalInteractiveShell.autoindent=False). - - If you want to paste multiple lines in the terminal, it is recommended that - you use ``%paste``. - - -Customizing readline behavior -+++++++++++++++++++++++++++++ - -All these features are based on the GNU readline library, which has an -extremely customizable interface. Normally, readline is configured via a -:file:`.inputrc` file. IPython respects this, and you can also customise readline -by setting the following :doc:`configuration ` options: - - * ``InteractiveShell.readline_parse_and_bind``: this holds a list of strings to be executed - via a readline.parse_and_bind() command. The syntax for valid commands - of this kind can be found by reading the documentation for the GNU - readline library, as these commands are of the kind which readline - accepts in its configuration file. - * ``InteractiveShell.readline_remove_delims``: a string of characters to be removed - from the default word-delimiters list used by readline, so that - completions may be performed on strings which contain them. Do not - change the default value unless you know what you're doing. - -You will find the default values in your configuration file. - +Starting with 5.0, IPython user `prompt_toolkit` in place of ``readline``, +it thus can recognize lines ending in ':' and indent the next line, +while also un-indenting automatically after 'raise' or 'return', +and support real multi-line editing as well as syntactic coloration +during edition. + +This feature does not use the ``readline`` library anymore – at least for now +– , so it will not honor your :file:`~/.inputrc` configuration (or whatever +file your :envvar:`INPUTRC` environment variable points to). + +In particular if you want to change the input mode to ``vi``, you will need to +set the ``TerminalInteractiveShell.vi_mode`` configuration option of IPython. Session logging and restoring ----------------------------- From 07a8e34740fb26f1b775ac886f59ca0ce4a4c5ef Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 25 May 2016 12:34:25 -0700 Subject: [PATCH 0328/4859] Add what's new incompat about readline. --- docs/source/whatsnew/pr/incompat-readline.rst | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 docs/source/whatsnew/pr/incompat-readline.rst diff --git a/docs/source/whatsnew/pr/incompat-readline.rst b/docs/source/whatsnew/pr/incompat-readline.rst new file mode 100644 index 00000000000..4fec45c15e2 --- /dev/null +++ b/docs/source/whatsnew/pr/incompat-readline.rst @@ -0,0 +1,4 @@ +IPython 5.0 now use prompt_toolkit, any setting that affect ``readline`` will +have no effect, and has (likely) be relplaced by a configuration option on +IPython itself. + From ce90d15939d94c41bff7fcc6843b1040830e6ec8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 25 May 2016 13:36:14 -0700 Subject: [PATCH 0329/4859] fix config name. --- docs/source/interactive/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 4d3b2345447..76586865768 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -265,7 +265,7 @@ This feature does not use the ``readline`` library anymore – at least for now file your :envvar:`INPUTRC` environment variable points to). In particular if you want to change the input mode to ``vi``, you will need to -set the ``TerminalInteractiveShell.vi_mode`` configuration option of IPython. +set the ``TerminalInteractiveShell.editing_mode`` configuration option of IPython. Session logging and restoring ----------------------------- From bcc45d55c5c2b790fc335da2922d8a7c61236e86 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 25 May 2016 14:01:57 -0700 Subject: [PATCH 0330/4859] Document IPYTHON_SUPPRESS_CONFIG_ERRORS. Closes #9493 --- docs/source/development/config.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/source/development/config.rst b/docs/source/development/config.rst index 39ec35c7d4a..08bdb41034e 100644 --- a/docs/source/development/config.rst +++ b/docs/source/development/config.rst @@ -55,6 +55,17 @@ under :file:`profile_default`. If you want the default config files for the :mod:`IPython.parallel` applications, add ``--parallel`` to the end of the command-line args. +.. note:: + + By default IPython will ignore any invalid configuration files, or any + unknown configuration option. + +.. versionadded:: 5.0 + + IPython can be configured to abort in case of invalid configuration file. + To do so set the environment variable ``IPYTHON_SUPPRESS_CONFIG_ERRORS`` to + `'1'` or `'true'` + Locating these files -------------------- From 0b9d90e683ab6a361e7e2f4fb6e3c89481c23368 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 26 May 2016 10:37:36 +0100 Subject: [PATCH 0331/4859] Enable bracket matching by default --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 351e98bbb82..b4f89d5718f 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -146,7 +146,7 @@ def _highlighting_style_changed(self, change): help="Display a multi column completion menu.", ).tag(config=True) - highlight_matching_brackets = Bool(False, + highlight_matching_brackets = Bool(True, help="Highlight matching brackets .", ).tag(config=True) From 3baa12db09cfe823da6db3297ccbfdd471ce9159 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 10:55:39 -0700 Subject: [PATCH 0332/4859] Fix english because english need to be fixed. --- docs/source/whatsnew/pr/incompat-readline.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/whatsnew/pr/incompat-readline.rst b/docs/source/whatsnew/pr/incompat-readline.rst index 4fec45c15e2..04272ce9db1 100644 --- a/docs/source/whatsnew/pr/incompat-readline.rst +++ b/docs/source/whatsnew/pr/incompat-readline.rst @@ -1,4 +1,3 @@ -IPython 5.0 now use prompt_toolkit, any setting that affect ``readline`` will -have no effect, and has (likely) be relplaced by a configuration option on +IPython 5.0 now uses prompt_toolkit, so any setting that affects ``readline`` will +have no effect, and has likely been replaced by a configuration option on IPython itself. - From 27e605f66fe4b7cbfd1aa3c5bd5e67ce90cf304a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:17:17 -0700 Subject: [PATCH 0333/4859] Update config.rst --- docs/source/development/config.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/development/config.rst b/docs/source/development/config.rst index 08bdb41034e..c460e8d9b1d 100644 --- a/docs/source/development/config.rst +++ b/docs/source/development/config.rst @@ -57,8 +57,10 @@ command-line args. .. note:: - By default IPython will ignore any invalid configuration files, or any - unknown configuration option. + IPython configuration options are case sensitive, and IPython cannot + catch misnamed keys or invalid values. + + By default IPython will also ignore any invalid configuration files. .. versionadded:: 5.0 From a82df1cfc7bf248ce69454d3bb2deefa65084ad0 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:18:39 -0700 Subject: [PATCH 0334/4859] Update reference.rst --- docs/source/interactive/reference.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 76586865768..73426fd19ba 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -260,8 +260,8 @@ while also un-indenting automatically after 'raise' or 'return', and support real multi-line editing as well as syntactic coloration during edition. -This feature does not use the ``readline`` library anymore – at least for now -– , so it will not honor your :file:`~/.inputrc` configuration (or whatever +This feature does not use the ``readline`` library anymore, so it will +not honor your :file:`~/.inputrc` configuration (or whatever file your :envvar:`INPUTRC` environment variable points to). In particular if you want to change the input mode to ``vi``, you will need to From 6aabd66239f40f9916761704f6716ffe0a0d2958 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:23:16 -0700 Subject: [PATCH 0335/4859] Make a few test non-optional. And add a few testing dependencies. --- IPython/core/tests/test_display.py | 1 - IPython/core/tests/test_magic.py | 4 +-- IPython/core/tests/test_run.py | 44 ++++++++++++++--------------- IPython/terminal/tests/test_help.py | 1 - IPython/testing/iptest.py | 1 + IPython/testing/tools.py | 7 +++++ setup.py | 3 +- 7 files changed, 34 insertions(+), 27 deletions(-) diff --git a/IPython/core/tests/test_display.py b/IPython/core/tests/test_display.py index 9f10df491aa..58e2e914dcb 100644 --- a/IPython/core/tests/test_display.py +++ b/IPython/core/tests/test_display.py @@ -2,7 +2,6 @@ # Distributed under the terms of the Modified BSD License. import json -import tempfile import os import warnings diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index a507ab9861d..17af507e9d1 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -39,6 +39,8 @@ def invalidate_caches(): from StringIO import StringIO +_ip = get_ipython() + @magic.magics_class class DummyMagics(magic.Magics): pass @@ -89,7 +91,6 @@ def test_config(): def test_rehashx(): # clear up everything - _ip = get_ipython() _ip.alias_manager.clear_aliases() del _ip.db['syscmdlist'] @@ -625,7 +626,6 @@ def test_extension(): sys.path.remove(daft_path) -@dec.skip_without('nbformat') def test_notebook_export_json(): _ip = get_ipython() _ip.history_manager.reset() # Clear any existing history. diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index 6f73f732463..5e64fb2a67e 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -254,22 +254,22 @@ def test_aggressive_namespace_cleanup(self): Returning from another run magic deletes the namespace""" # see ticket https://github.com/ipython/ipython/issues/238 - class secondtmp(tt.TempFileMixin): pass - empty = secondtmp() - empty.mktmp('') - # On Windows, the filename will have \users in it, so we need to use the - # repr so that the \u becomes \\u. - src = ("ip = get_ipython()\n" - "for i in range(5):\n" - " try:\n" - " ip.magic(%r)\n" - " except NameError as e:\n" - " print(i)\n" - " break\n" % ('run ' + empty.fname)) - self.mktmp(src) - _ip.magic('run %s' % self.fname) - _ip.run_cell('ip == get_ipython()') - nt.assert_equal(_ip.user_ns['i'], 4) + + with tt.TempFileMixin() as empty: + empty.mktmp('') + # On Windows, the filename will have \users in it, so we need to use the + # repr so that the \u becomes \\u. + src = ("ip = get_ipython()\n" + "for i in range(5):\n" + " try:\n" + " ip.magic(%r)\n" + " except NameError as e:\n" + " print(i)\n" + " break\n" % ('run ' + empty.fname)) + self.mktmp(src) + _ip.magic('run %s' % self.fname) + _ip.run_cell('ip == get_ipython()') + nt.assert_equal(_ip.user_ns['i'], 4) def test_run_second(self): """Test that running a second file doesn't clobber the first, gh-3547 @@ -278,12 +278,12 @@ def test_run_second(self): "def afunc():\n" " return avar\n") - empty = tt.TempFileMixin() - empty.mktmp("") - - _ip.magic('run %s' % self.fname) - _ip.magic('run %s' % empty.fname) - nt.assert_equal(_ip.user_ns['afunc'](), 1) + with tt.TempFileMixin() as empty: + empty.mktmp("") + + _ip.magic('run %s' % self.fname) + _ip.magic('run %s' % empty.fname) + nt.assert_equal(_ip.user_ns['afunc'](), 1) @dec.skip_win32 def test_tclass(self): diff --git a/IPython/terminal/tests/test_help.py b/IPython/terminal/tests/test_help.py index 9f92942b2d5..16a6f57eb8b 100644 --- a/IPython/terminal/tests/test_help.py +++ b/IPython/terminal/tests/test_help.py @@ -25,6 +25,5 @@ def test_locate_help(): def test_locate_profile_help(): tt.help_all_output_test("locate profile") -@skip_without('nbformat') # Requires jsonschema to be installed def test_trust_help(): tt.help_all_output_test("trust") diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 9e1a883acd1..1a9dd72d6e0 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -44,6 +44,7 @@ # Enable printing all warnings raise by IPython's modules +warnings.filterwarnings('ignore', message='.*Matplotlib is building the font cache.*', category=UserWarning, module='.*') if sys.version_info > (3,0): warnings.filterwarnings('error', message='.*', category=ResourceWarning, module='.*') warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index 69e56339fee..73f4ee7201f 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -303,6 +303,13 @@ def tearDown(self): # delete it. I have no clue why pass + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.tearDown() + + pair_fail_msg = ("Testing {0}\n\n" "In:\n" " {1!r}\n" diff --git a/setup.py b/setup.py index ab74fb82158..b4f98268995 100755 --- a/setup.py +++ b/setup.py @@ -182,13 +182,14 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], notebook = ['notebook', 'ipywidgets'], nbconvert = ['nbconvert'], ) + install_requires = [ 'setuptools>=18.5', 'decorator', From 2191a0a27e9f7e5c6d001b237e476bc7bcb85d55 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:15:13 -0700 Subject: [PATCH 0336/4859] /user/uses/ --- docs/source/interactive/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 73426fd19ba..492c8830eda 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -254,7 +254,7 @@ time you restart it. By default, the history file is named Autoindent ++++++++++ -Starting with 5.0, IPython user `prompt_toolkit` in place of ``readline``, +Starting with 5.0, IPython uses `prompt_toolkit` in place of ``readline``, it thus can recognize lines ending in ':' and indent the next line, while also un-indenting automatically after 'raise' or 'return', and support real multi-line editing as well as syntactic coloration From 3c803f0e177cabd033274de57f0c4ef57427e0bc Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 19 May 2016 13:09:20 -0700 Subject: [PATCH 0337/4859] Use python-prompt-toolkit for ipdb. Still need to hookup history and completion. --- IPython/core/debugger.py | 49 ++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index dcbd65dda46..3c7b9444c39 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -37,6 +37,8 @@ from IPython.core.excolors import exception_colors from IPython.testing.skipdoctest import skip_doctest +from prompt_toolkit import prompt as ptk_prompt + prompt = 'ipdb> ' #We have to check this directly from sys.argv, config struct not yet available @@ -245,13 +247,46 @@ def __init__(self,color_scheme='NoColor',completekey=None, self.parser = PyColorize.Parser() # Set the prompt - the default prompt is '(Pdb)' - Colors = cst.active_colors - if color_scheme == 'NoColor': - self.prompt = prompt - else: - # The colour markers are wrapped by bytes 01 and 02 so that readline - # can calculate the width. - self.prompt = u'\x01%s\x02%s\x01%s\x02' % (Colors.prompt, prompt, Colors.Normal) + self.prompt = prompt + + + def cmdloop(self, intro=None): + """Repeatedly issue a prompt, accept input, parse an initial prefix + off the received input, and dispatch to action methods, passing them + the remainder of the line as argument. + + override the same methods from cmd.Cmd to provide prompt toolkit replacement. + """ + if not self.use_rawinput: + raise ValueError('Sorry ipdb does not support raw_input=False') + + def get_prompt_tokens(cli): + from pygments.token import Token + return [(Token.Prompt, self.prompt)] + + self.preloop() + try: + if intro is not None: + self.intro = intro + if self.intro: + self.stdout.write(str(self.intro)+"\n") + stop = None + while not stop: + if self.cmdqueue: + line = self.cmdqueue.pop(0) + else: + try: + line = ptk_prompt(get_prompt_tokens=get_prompt_tokens) + except EOFError: + line = 'EOF' + line = self.precmd(line) + stop = self.onecmd(line) + stop = self.postcmd(stop, line) + self.postloop() + except Exception: + pass + + def set_colors(self, scheme): """Shorthand access to the color table scheme selector method.""" From 5fe78218ecaf78ca376504d778223f919382cb6c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 20 May 2016 13:49:16 +0100 Subject: [PATCH 0338/4859] Check for a prompt_toolkit shell and fall back to regular input --- IPython/core/debugger.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 3c7b9444c39..90ef58a08cd 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -218,6 +218,10 @@ def __init__(self,color_scheme='NoColor',completekey=None, TerminalInteractiveShell self.shell = TerminalInteractiveShell.instance() + # This is icky, but I'm not currently sure how best to test if we're + # in a terminal shell using prompt_toolkit + self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli') + self.aliases = {} # Create color table: we copy the default one from the traceback @@ -257,6 +261,9 @@ def cmdloop(self, intro=None): override the same methods from cmd.Cmd to provide prompt toolkit replacement. """ + if not self.use_prompt_toolkit: + super(Pdb, self).cmdloop(intro) + if not self.use_rawinput: raise ValueError('Sorry ipdb does not support raw_input=False') From f3051aeb1cce2ad60cbef73ad994fd5bfaa88562 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 20 May 2016 13:53:43 +0100 Subject: [PATCH 0339/4859] Remove readline code from debugger machinery --- IPython/core/debugger.py | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 90ef58a08cd..96a99199e8d 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -122,12 +122,6 @@ def __init__(self, colors=None): sys.excepthook = functools.partial(BdbQuit_excepthook, excepthook=sys.excepthook) def_colors = 'NoColor' - try: - # Limited tab completion support - import readline - readline.parse_and_bind('tab: complete') - except ImportError: - pass else: # In ipython, we use its custom exception handler mechanism def_colors = ip.colors @@ -300,18 +294,10 @@ def set_colors(self, scheme): self.color_scheme_table.set_active_scheme(scheme) def interaction(self, frame, traceback): - self.shell.set_completer_frame(frame) - while True: - try: - OldPdb.interaction(self, frame, traceback) - break - except KeyboardInterrupt: - self.shell.write('\n' + self.shell.get_exception_only()) - break - finally: - # Pdb sets readline delimiters, so set them back to our own - if self.shell.readline is not None: - self.shell.readline.set_completer_delims(self.shell.readline_delims) + try: + OldPdb.interaction(self, frame, traceback) + except KeyboardInterrupt: + sys.stdout.write('\n' + self.shell.get_exception_only()) def parseline(self, line): if line.startswith("!!"): From 2359cacf45936b74fc2f8932ff29403f30b3511a Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 20 May 2016 14:01:01 +0100 Subject: [PATCH 0340/4859] These classes are Old School Or Old Style. Roll on, end of Python 2 support. --- IPython/core/debugger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 96a99199e8d..3bd640197ae 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -256,7 +256,7 @@ def cmdloop(self, intro=None): override the same methods from cmd.Cmd to provide prompt toolkit replacement. """ if not self.use_prompt_toolkit: - super(Pdb, self).cmdloop(intro) + return OldPdb.cmdloop(self, intro) if not self.use_rawinput: raise ValueError('Sorry ipdb does not support raw_input=False') From 448fa1fa93afc0c05a9d23d6a6060fc369c43252 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 22 May 2016 12:09:35 +0100 Subject: [PATCH 0341/4859] Store command history for the debugger --- IPython/core/debugger.py | 4 +++- IPython/terminal/ptshell.py | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 3bd640197ae..3b5997e433e 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -277,7 +277,9 @@ def get_prompt_tokens(cli): line = self.cmdqueue.pop(0) else: try: - line = ptk_prompt(get_prompt_tokens=get_prompt_tokens) + line = ptk_prompt(get_prompt_tokens=get_prompt_tokens, + history=self.shell.debugger_history, + ) except EOFError: line = 'EOF' line = self.precmd(line) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index b4f89d5718f..2829f06048c 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -100,6 +100,7 @@ def _space_for_menu_changed(self, old, new): self._update_layout() pt_cli = None + debugger_history = None autoedit_syntax = Bool(False, help="auto editing of files with syntax errors.", @@ -362,6 +363,8 @@ def __init__(self, *args, **kwargs): self.init_term_title() self.keep_running = True + self.debugger_history = InMemoryHistory() + def ask_exit(self): self.keep_running = False From b4462efe5e04a983cf48e30535ae79e42c3670df Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sun, 22 May 2016 12:26:52 +0100 Subject: [PATCH 0342/4859] Integrate completion into debugger --- IPython/core/completer.py | 6 ++++ IPython/core/debugger.py | 9 ++++++ IPython/terminal/ptshell.py | 62 ++----------------------------------- IPython/terminal/ptutils.py | 62 +++++++++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 60 deletions(-) create mode 100644 IPython/terminal/ptutils.py diff --git a/IPython/core/completer.py b/IPython/core/completer.py index d023e82d533..f11d60f1bbd 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -652,6 +652,9 @@ def __init__(self, shell=None, namespace=None, global_namespace=None, self.dict_key_matches, ] + # This is set externally by InteractiveShell + self.custom_completers = None + def all_completions(self, text): """ Wrapper around the complete method for the benefit of emacs. @@ -1072,6 +1075,9 @@ def latex_matches(self, text): return u'', [] def dispatch_custom_completer(self, text): + if not self.custom_completers: + return + line = self.line_buffer if not line.strip(): return None diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 3b5997e433e..59a99eec7d4 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -34,8 +34,10 @@ from IPython import get_ipython from IPython.utils import PyColorize, ulinecache from IPython.utils import coloransi, py3compat +from IPython.core.completer import IPCompleter from IPython.core.excolors import exception_colors from IPython.testing.skipdoctest import skip_doctest +from IPython.terminal.ptutils import IPythonPTCompleter from prompt_toolkit import prompt as ptk_prompt @@ -276,9 +278,16 @@ def get_prompt_tokens(cli): if self.cmdqueue: line = self.cmdqueue.pop(0) else: + compl = IPCompleter(shell=self.shell, + namespace=self.curframe_locals, + global_namespace=self.curframe.f_globals, + use_readline=False, + parent=self.shell, + ) try: line = ptk_prompt(get_prompt_tokens=get_prompt_tokens, history=self.shell.debugger_history, + completer=IPythonPTCompleter(compl), ) except EOFError: line = 'EOF' diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 2829f06048c..a3865df4bbc 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -4,18 +4,15 @@ import os import sys import signal -import unicodedata from warnings import warn -from wcwidth import wcwidth from IPython.core.error import TryNext from IPython.core.interactiveshell import InteractiveShell -from IPython.utils.py3compat import PY3, cast_unicode_py2, input +from IPython.utils.py3compat import cast_unicode_py2, input 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 -from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone from prompt_toolkit.history import InMemoryHistory @@ -23,70 +20,15 @@ from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.lexers import Lexer -from prompt_toolkit.layout.lexers import PygmentsLexer from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor from prompt_toolkit.styles import PygmentsStyle, DynamicStyle from pygments.styles import get_style_by_name, get_all_styles -from pygments.lexers import Python3Lexer, BashLexer, PythonLexer from pygments.token import Token from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics - - -class IPythonPTCompleter(Completer): - """Adaptor to provide IPython completions to prompt_toolkit""" - def __init__(self, ipy_completer): - self.ipy_completer = ipy_completer - - def get_completions(self, document, complete_event): - if not document.current_line.strip(): - return - - used, matches = self.ipy_completer.complete( - line_buffer=document.current_line, - cursor_pos=document.cursor_position_col - ) - start_pos = -len(used) - for m in matches: - m = unicodedata.normalize('NFC', m) - - # When the first character of the completion has a zero length, - # then it's probably a decomposed unicode character. E.g. caused by - # the "\dot" completion. Try to compose again with the previous - # character. - if wcwidth(m[0]) == 0: - if document.cursor_position + start_pos > 0: - char_before = document.text[document.cursor_position + start_pos - 1] - m = unicodedata.normalize('NFC', char_before + m) - - # Yield the modified completion instead, if this worked. - if wcwidth(m[0:1]) == 1: - yield Completion(m, start_position=start_pos - 1) - continue - - # TODO: Use Jedi to determine meta_text - # (Jedi currently has a bug that results in incorrect information.) - # meta_text = '' - # yield Completion(m, start_position=start_pos, - # display_meta=meta_text) - yield Completion(m, start_position=start_pos) - -class IPythonPTLexer(Lexer): - """ - Wrapper around PythonLexer and BashLexer. - """ - def __init__(self): - self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer) - self.shell_lexer = PygmentsLexer(BashLexer) - - def lex_document(self, cli, document): - if document.text.startswith('!'): - return self.shell_lexer.lex_document(cli, document) - else: - return self.python_lexer.lex_document(cli, document) +from .ptutils import IPythonPTCompleter, IPythonPTLexer class TerminalInteractiveShell(InteractiveShell): diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py new file mode 100644 index 00000000000..4dafab19800 --- /dev/null +++ b/IPython/terminal/ptutils.py @@ -0,0 +1,62 @@ +import unicodedata +from wcwidth import wcwidth + +from IPython.utils.py3compat import PY3 + +from prompt_toolkit.completion import Completer, Completion +from prompt_toolkit.layout.lexers import Lexer +from prompt_toolkit.layout.lexers import PygmentsLexer + +from pygments.lexers import Python3Lexer, BashLexer, PythonLexer + +class IPythonPTCompleter(Completer): + """Adaptor to provide IPython completions to prompt_toolkit""" + def __init__(self, ipy_completer): + self.ipy_completer = ipy_completer + + def get_completions(self, document, complete_event): + if not document.current_line.strip(): + return + + used, matches = self.ipy_completer.complete( + line_buffer=document.current_line, + cursor_pos=document.cursor_position_col + ) + start_pos = -len(used) + for m in matches: + m = unicodedata.normalize('NFC', m) + + # When the first character of the completion has a zero length, + # then it's probably a decomposed unicode character. E.g. caused by + # the "\dot" completion. Try to compose again with the previous + # character. + if wcwidth(m[0]) == 0: + if document.cursor_position + start_pos > 0: + char_before = document.text[document.cursor_position + start_pos - 1] + m = unicodedata.normalize('NFC', char_before + m) + + # Yield the modified completion instead, if this worked. + if wcwidth(m[0:1]) == 1: + yield Completion(m, start_position=start_pos - 1) + continue + + # TODO: Use Jedi to determine meta_text + # (Jedi currently has a bug that results in incorrect information.) + # meta_text = '' + # yield Completion(m, start_position=start_pos, + # display_meta=meta_text) + yield Completion(m, start_position=start_pos) + +class IPythonPTLexer(Lexer): + """ + Wrapper around PythonLexer and BashLexer. + """ + def __init__(self): + self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer) + self.shell_lexer = PygmentsLexer(BashLexer) + + def lex_document(self, cli, document): + if document.text.startswith('!'): + return self.shell_lexer.lex_document(cli, document) + else: + return self.python_lexer.lex_document(cli, document) From f09ebf2e5eeb1bcaf3adccfd4938a60738b7ef6d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 22 May 2016 11:08:55 -0700 Subject: [PATCH 0343/4859] Speedup debugger CLI a bit. Also fix lookup of current namespace. --- IPython/core/debugger.py | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 59a99eec7d4..a6f77bbb91b 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -40,6 +40,7 @@ from IPython.terminal.ptutils import IPythonPTCompleter from prompt_toolkit import prompt as ptk_prompt +from prompt_toolkit.token import Token prompt = 'ipdb> ' @@ -248,6 +249,7 @@ def __init__(self,color_scheme='NoColor',completekey=None, # Set the prompt - the default prompt is '(Pdb)' self.prompt = prompt + self._ptcomp = None def cmdloop(self, intro=None): @@ -264,10 +266,19 @@ def cmdloop(self, intro=None): raise ValueError('Sorry ipdb does not support raw_input=False') def get_prompt_tokens(cli): - from pygments.token import Token return [(Token.Prompt, self.prompt)] self.preloop() + + if self._ptcomp is None: + compl = IPCompleter(shell=self.shell, + namespace=self.curframe_locals, + global_namespace=self.curframe.f_globals, + use_readline=False, + parent=self.shell, + ) + self._ptcomp = IPythonPTCompleter(compl) + try: if intro is not None: self.intro = intro @@ -278,16 +289,12 @@ def get_prompt_tokens(cli): if self.cmdqueue: line = self.cmdqueue.pop(0) else: - compl = IPCompleter(shell=self.shell, - namespace=self.curframe_locals, - global_namespace=self.curframe.f_globals, - use_readline=False, - parent=self.shell, - ) + self._ptcomp.ipy_completer.namespace = self.curframe_locals + self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals try: line = ptk_prompt(get_prompt_tokens=get_prompt_tokens, history=self.shell.debugger_history, - completer=IPythonPTCompleter(compl), + completer=self._ptcomp ) except EOFError: line = 'EOF' @@ -323,18 +330,15 @@ def parseline(self, line): def new_do_up(self, arg): OldPdb.do_up(self, arg) - self.shell.set_completer_frame(self.curframe) do_u = do_up = decorate_fn_with_doc(new_do_up, OldPdb.do_up) def new_do_down(self, arg): OldPdb.do_down(self, arg) - self.shell.set_completer_frame(self.curframe) do_d = do_down = decorate_fn_with_doc(new_do_down, OldPdb.do_down) def new_do_frame(self, arg): OldPdb.do_frame(self, arg) - self.shell.set_completer_frame(self.curframe) def new_do_quit(self, arg): @@ -351,9 +355,6 @@ def new_do_restart(self, arg): self.msg("Restart doesn't make sense here. Using 'quit' instead.") return self.do_quit(arg) - def postloop(self): - self.shell.set_completer_frame(None) - def print_stack_trace(self, context=None): if context is None: context = self.context From 9c62a249daf861203169e7e0d8534e5a27d26e75 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 22 May 2016 15:17:42 -0700 Subject: [PATCH 0344/4859] Reuse CLI in between pdb prompts The prompt drawing delay is now invisible to human eye. --- IPython/core/debugger.py | 55 +++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index a6f77bbb91b..a056ddafe81 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -39,8 +39,11 @@ from IPython.testing.skipdoctest import skip_doctest from IPython.terminal.ptutils import IPythonPTCompleter -from prompt_toolkit import prompt as ptk_prompt from prompt_toolkit.token import Token +from prompt_toolkit.shortcuts import create_prompt_application +from prompt_toolkit.interface import CommandLineInterface +from prompt_toolkit.enums import EditingMode + prompt = 'ipdb> ' @@ -204,7 +207,7 @@ def __init__(self,color_scheme='NoColor',completekey=None, except (TypeError, ValueError): raise ValueError("Context must be a positive integer") - OldPdb.__init__(self,completekey,stdin,stdout) + OldPdb.__init__(self, completekey, stdin, stdout) # IPython changes... self.shell = get_ipython() @@ -217,7 +220,6 @@ def __init__(self,color_scheme='NoColor',completekey=None, # This is icky, but I'm not currently sure how best to test if we're # in a terminal shell using prompt_toolkit - self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli') self.aliases = {} @@ -250,6 +252,36 @@ def __init__(self,color_scheme='NoColor',completekey=None, # Set the prompt - the default prompt is '(Pdb)' self.prompt = prompt self._ptcomp = None + self.pt_init() + + def pt_init(self): + self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli') + + if not self.use_prompt_toolkit: + return + + def get_prompt_tokens(cli): + return [(Token.Prompt, self.prompt)] + + if self._ptcomp is None: + compl = IPCompleter(shell=self.shell, + namespace={}, + global_namespace={}, + use_readline=False, + parent=self.shell, + ) + self._ptcomp = IPythonPTCompleter(compl) + + self._pt_app = create_prompt_application( + editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()), + history=self.shell.debugger_history, + completer= self._ptcomp, + enable_history_search=True, + mouse_support=self.shell.mouse_support, + get_prompt_tokens=get_prompt_tokens + ) + self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop) + def cmdloop(self, intro=None): @@ -265,19 +297,9 @@ def cmdloop(self, intro=None): if not self.use_rawinput: raise ValueError('Sorry ipdb does not support raw_input=False') - def get_prompt_tokens(cli): - return [(Token.Prompt, self.prompt)] self.preloop() - if self._ptcomp is None: - compl = IPCompleter(shell=self.shell, - namespace=self.curframe_locals, - global_namespace=self.curframe.f_globals, - use_readline=False, - parent=self.shell, - ) - self._ptcomp = IPythonPTCompleter(compl) try: if intro is not None: @@ -292,10 +314,7 @@ def get_prompt_tokens(cli): self._ptcomp.ipy_completer.namespace = self.curframe_locals self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals try: - line = ptk_prompt(get_prompt_tokens=get_prompt_tokens, - history=self.shell.debugger_history, - completer=self._ptcomp - ) + line = self.pt_cli.run(reset_current_buffer=True).text except EOFError: line = 'EOF' line = self.precmd(line) @@ -303,7 +322,7 @@ def get_prompt_tokens(cli): stop = self.postcmd(stop, line) self.postloop() except Exception: - pass + raise From 2c8483069f9b07e76c65706e992d68dd91ba3eb2 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 23 May 2016 15:21:33 +0100 Subject: [PATCH 0345/4859] Create separate class for debugger using prompt_toolkit --- IPython/core/debugger.py | 81 -------------------------------- IPython/core/interactiveshell.py | 6 ++- IPython/core/ultratb.py | 10 ++-- IPython/terminal/debugger.py | 73 ++++++++++++++++++++++++++++ IPython/terminal/ptshell.py | 2 + 5 files changed, 86 insertions(+), 86 deletions(-) create mode 100644 IPython/terminal/debugger.py diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index a056ddafe81..e25faca9067 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -34,15 +34,8 @@ from IPython import get_ipython from IPython.utils import PyColorize, ulinecache from IPython.utils import coloransi, py3compat -from IPython.core.completer import IPCompleter from IPython.core.excolors import exception_colors from IPython.testing.skipdoctest import skip_doctest -from IPython.terminal.ptutils import IPythonPTCompleter - -from prompt_toolkit.token import Token -from prompt_toolkit.shortcuts import create_prompt_application -from prompt_toolkit.interface import CommandLineInterface -from prompt_toolkit.enums import EditingMode prompt = 'ipdb> ' @@ -251,80 +244,6 @@ def __init__(self,color_scheme='NoColor',completekey=None, # Set the prompt - the default prompt is '(Pdb)' self.prompt = prompt - self._ptcomp = None - self.pt_init() - - def pt_init(self): - self.use_prompt_toolkit = hasattr(self.shell, 'pt_cli') - - if not self.use_prompt_toolkit: - return - - def get_prompt_tokens(cli): - return [(Token.Prompt, self.prompt)] - - if self._ptcomp is None: - compl = IPCompleter(shell=self.shell, - namespace={}, - global_namespace={}, - use_readline=False, - parent=self.shell, - ) - self._ptcomp = IPythonPTCompleter(compl) - - self._pt_app = create_prompt_application( - editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()), - history=self.shell.debugger_history, - completer= self._ptcomp, - enable_history_search=True, - mouse_support=self.shell.mouse_support, - get_prompt_tokens=get_prompt_tokens - ) - self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop) - - - - def cmdloop(self, intro=None): - """Repeatedly issue a prompt, accept input, parse an initial prefix - off the received input, and dispatch to action methods, passing them - the remainder of the line as argument. - - override the same methods from cmd.Cmd to provide prompt toolkit replacement. - """ - if not self.use_prompt_toolkit: - return OldPdb.cmdloop(self, intro) - - if not self.use_rawinput: - raise ValueError('Sorry ipdb does not support raw_input=False') - - - self.preloop() - - - try: - if intro is not None: - self.intro = intro - if self.intro: - self.stdout.write(str(self.intro)+"\n") - stop = None - while not stop: - if self.cmdqueue: - line = self.cmdqueue.pop(0) - else: - self._ptcomp.ipy_completer.namespace = self.curframe_locals - self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals - try: - line = self.pt_cli.run(reset_current_buffer=True).text - except EOFError: - line = 'EOF' - line = self.precmd(line) - stop = self.onecmd(line) - stop = self.postcmd(stop, line) - self.postloop() - except Exception: - raise - - def set_colors(self, scheme): """Shorthand access to the color table scheme selector method.""" diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c6e913ad433..3bcc3e09eb5 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -42,6 +42,7 @@ from IPython.core.builtin_trap import BuiltinTrap from IPython.core.events import EventManager, available_events from IPython.core.compilerop import CachingCompiler, check_linecache_ipython +from IPython.core.debugger import Pdb from IPython.core.display_trap import DisplayTrap from IPython.core.displayhook import DisplayHook from IPython.core.displaypub import DisplayPublisher @@ -1584,6 +1585,8 @@ def init_history(self): # Things related to exception handling and tracebacks (not debugging) #------------------------------------------------------------------------- + debugger_cls = Pdb + def init_traceback_handlers(self, custom_exceptions): # Syntax error handler. self.SyntaxTB = ultratb.SyntaxTB(color_scheme='NoColor') @@ -1594,7 +1597,8 @@ def init_traceback_handlers(self, custom_exceptions): self.InteractiveTB = ultratb.AutoFormattedTB(mode = 'Plain', color_scheme='NoColor', tb_offset = 1, - check_cache=check_linecache_ipython) + check_cache=check_linecache_ipython, + debugger_cls=self.debugger_cls) # 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 0d8bb98a753..38ba74eac0b 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -809,7 +809,7 @@ 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): + check_cache=None, debugger_cls = None): """Specify traceback offset, headers and color scheme. Define how many frames to drop from the tracebacks. Calling it with @@ -830,6 +830,8 @@ def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None, check_cache = linecache.checkcache self.check_cache = check_cache + self.debugger_cls = debugger_cls or debugger.Pdb + def format_records(self, records, last_unique, recursion_repeat): """Format the stack frames of the traceback""" frames = [] @@ -1217,7 +1219,7 @@ def debugger(self, force=False): if force or self.call_pdb: if self.pdb is None: - self.pdb = debugger.Pdb( + self.pdb = self.debugger_cls( self.color_scheme_table.active_scheme_name) # the system displayhook may have changed, restore the original # for pdb @@ -1278,7 +1280,7 @@ 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): + check_cache=None, debugger_cls=None): # NEVER change the order of this list. Put new modes at the end: self.valid_modes = ['Plain', 'Context', 'Verbose'] @@ -1287,7 +1289,7 @@ 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) + check_cache=check_cache, debugger_cls=debugger_cls) # Different types of tracebacks are joined with different separators to # form a single string. They are taken from this dict diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py new file mode 100644 index 00000000000..315c956cb6e --- /dev/null +++ b/IPython/terminal/debugger.py @@ -0,0 +1,73 @@ +from IPython.core.debugger import Pdb + +from IPython.core.completer import IPCompleter +from .ptutils import IPythonPTCompleter + +from prompt_toolkit.token import Token +from prompt_toolkit.shortcuts import create_prompt_application +from prompt_toolkit.interface import CommandLineInterface +from prompt_toolkit.enums import EditingMode + +class TerminalPdb(Pdb): + def __init__(self, *args, **kwargs): + Pdb.__init__(self, *args, **kwargs) + self._ptcomp = None + self.pt_init() + + def pt_init(self): + def get_prompt_tokens(cli): + return [(Token.Prompt, self.prompt)] + + if self._ptcomp is None: + compl = IPCompleter(shell=self.shell, + namespace={}, + global_namespace={}, + use_readline=False, + parent=self.shell, + ) + self._ptcomp = IPythonPTCompleter(compl) + + self._pt_app = create_prompt_application( + editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()), + history=self.shell.debugger_history, + completer= self._ptcomp, + enable_history_search=True, + mouse_support=self.shell.mouse_support, + get_prompt_tokens=get_prompt_tokens + ) + self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self.shell._eventloop) + + def cmdloop(self, intro=None): + """Repeatedly issue a prompt, accept input, parse an initial prefix + off the received input, and dispatch to action methods, passing them + the remainder of the line as argument. + + override the same methods from cmd.Cmd to provide prompt toolkit replacement. + """ + if not self.use_rawinput: + raise ValueError('Sorry ipdb does not support use_rawinput=False') + + self.preloop() + + try: + if intro is not None: + self.intro = intro + if self.intro: + self.stdout.write(str(self.intro)+"\n") + stop = None + while not stop: + if self.cmdqueue: + line = self.cmdqueue.pop(0) + else: + self._ptcomp.ipy_completer.namespace = self.curframe_locals + self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals + try: + line = self.pt_cli.run(reset_current_buffer=True).text + except EOFError: + line = 'EOF' + line = self.precmd(line) + stop = self.onecmd(line) + stop = self.postcmd(stop, line) + self.postloop() + except Exception: + raise diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index a3865df4bbc..b229284f6b0 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -26,6 +26,7 @@ from pygments.styles import get_style_by_name, get_all_styles from pygments.token import Token +from .debugger import TerminalPdb from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics from .ptutils import IPythonPTCompleter, IPythonPTLexer @@ -43,6 +44,7 @@ def _space_for_menu_changed(self, old, new): pt_cli = None debugger_history = None + debugger_cls = TerminalPdb autoedit_syntax = Bool(False, help="auto editing of files with syntax errors.", From 94631e5d2302862af5002cba6f3c968e41527f85 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 23 May 2016 15:23:00 +0100 Subject: [PATCH 0346/4859] Remove leftover comment --- IPython/core/debugger.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index e25faca9067..115e0aacdcf 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -211,9 +211,6 @@ def __init__(self,color_scheme='NoColor',completekey=None, TerminalInteractiveShell self.shell = TerminalInteractiveShell.instance() - # This is icky, but I'm not currently sure how best to test if we're - # in a terminal shell using prompt_toolkit - self.aliases = {} # Create color table: we copy the default one from the traceback From 7b89b5af27a291d7c91c21b0f58ebf4bdfd06543 Mon Sep 17 00:00:00 2001 From: nvdv Date: Fri, 27 May 2016 16:13:52 +0300 Subject: [PATCH 0347/4859] Add units to height and width in Image docstring. --- IPython/core/display.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/display.py b/IPython/core/display.py index 1db5d8ae73d..4a943e4dbb4 100644 --- a/IPython/core/display.py +++ b/IPython/core/display.py @@ -678,9 +678,9 @@ def __init__(self, data=None, url=None, filename=None, format=None, Note that QtConsole is not able to display images if `embed` is set to `False` width : int - Width to which to constrain the image in html + Width in pixels to which to constrain the image in html height : int - Height to which to constrain the image in html + Height in pixels to which to constrain the image in html retina : bool Automatically set the width and height to half of the measured width and height. From d0455b3b688e40ba320ecadcac382a2ad2a81a58 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sat, 28 May 2016 22:27:16 -0700 Subject: [PATCH 0348/4859] 'enable python 3.6 nightly' --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 291473c99ff..12aedd744f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ # http://travis-ci.org/#!/ipython/ipython language: python python: + - "nightly" - 3.5 - 3.4 - 3.3 From 65bad830fd5b4cf710dcca696a163760a2541c5e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:30:13 -0700 Subject: [PATCH 0349/4859] Remove deprecated observer for 5.0 as warning says. --- IPython/core/formatters.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 72659893348..998512e9e5b 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -35,21 +35,6 @@ class DisplayFormatter(Configurable): - # When set to true only the default plain text formatter will be used. - plain_text_only = Bool(False).tag(config=True) - def _plain_text_only_changed(self, name, old, new): - warnings.warn("""DisplayFormatter.plain_text_only is deprecated. - - It will be removed in IPython 5.0 - - Use DisplayFormatter.active_types = ['text/plain'] - for the same effect. - """, DeprecationWarning) - if new: - self.active_types = ['text/plain'] - else: - self.active_types = self.format_types - active_types = List(Unicode(), help="""List of currently active mime-types to display. You can use this to set a white-list for formats to display. From 30b75a2b0ecff6ef550de27bd2abcd203577cb27 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:36:28 -0700 Subject: [PATCH 0350/4859] Remove deprecated "define_magic", that marked to be removed for 5.0 --- IPython/core/magic.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/IPython/core/magic.py b/IPython/core/magic.py index c68160634da..61a929fd231 100644 --- a/IPython/core/magic.py +++ b/IPython/core/magic.py @@ -426,25 +426,6 @@ def register_function(self, func, magic_kind='line', magic_name=None): setattr(self.user_magics, magic_name, func) record_magic(self.magics, magic_kind, magic_name, func) - def define_magic(self, name, func): - """[Deprecated] Expose own function as magic function for IPython. - - Will be removed in IPython 5.0 - - Example:: - - def foo_impl(self, parameter_s=''): - 'My very own magic!. (Use docstrings, IPython reads them).' - print 'Magic function. Passed parameter is between < >:' - print '<%s>' % parameter_s - print 'The self object is:', self - - ip.define_magic('foo',foo_impl) - """ - meth = types.MethodType(func, self.user_magics) - setattr(self.user_magics, name, meth) - record_magic(self.magics, 'line', name, meth) - def register_alias(self, alias_name, magic_name, magic_kind='line'): """Register an alias to a magic function. From 3a5e9b7b7d091a5accb6a488dba53f671b1b4df4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:38:43 -0700 Subject: [PATCH 0351/4859] Removed deprecated flag marked for removal in 5.0 --- IPython/core/shellapp.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index a1d25546345..821e593139d 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -62,20 +62,6 @@ colours.""", "Disable using colors for info related things." ) -addflag('deep-reload', 'InteractiveShell.deep_reload', - """ **Deprecated** and will be removed in IPython 5.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(). This feature is off - by default [which means that you have both normal reload() and - dreload()].""", - "Disable deep (recursive) reloading by default." -) nosep_config = Config() nosep_config.InteractiveShell.separate_in = '' nosep_config.InteractiveShell.separate_out = '' From 6f69404fdffe83ed9f0c19f37b7309cef3d37323 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:46:26 -0700 Subject: [PATCH 0352/4859] Remove deprecated magics marked for removal in 5.0 --- IPython/core/magics/__init__.py | 1 - IPython/core/magics/deprecated.py | 47 ------------------------------- 2 files changed, 48 deletions(-) delete mode 100644 IPython/core/magics/deprecated.py diff --git a/IPython/core/magics/__init__.py b/IPython/core/magics/__init__.py index 29085bdf433..d2fd5a6cfb6 100644 --- a/IPython/core/magics/__init__.py +++ b/IPython/core/magics/__init__.py @@ -17,7 +17,6 @@ from .basic import BasicMagics from .code import CodeMagics, MacroToEdit from .config import ConfigMagics -from .deprecated import DeprecatedMagics from .display import DisplayMagics from .execution import ExecutionMagics from .extension import ExtensionMagics diff --git a/IPython/core/magics/deprecated.py b/IPython/core/magics/deprecated.py deleted file mode 100644 index df5b74ac5fd..00000000000 --- a/IPython/core/magics/deprecated.py +++ /dev/null @@ -1,47 +0,0 @@ -"""Deprecated Magic functions. -""" -from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012 The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# Our own packages -from IPython.core.magic import Magics, magics_class, line_magic -import warnings - -#----------------------------------------------------------------------------- -# Magic implementation classes -#----------------------------------------------------------------------------- - -@magics_class -class DeprecatedMagics(Magics): - """Magics slated for later removal.""" - - @line_magic - def install_profiles(self, parameter_s=''): - """%install_profiles has been deprecated.""" - print('\n'.join([ - "%install_profiles has been deprecated and will be removed in IPython 5.0.", - "Use `ipython profile list` to view available profiles.", - "Requesting a profile with `ipython profile create `", - "or `ipython --profile=` will start with the bundled", - "profile of that name if it exists." - ])) - - @line_magic - def install_default_config(self, parameter_s=''): - """%install_default_config has been deprecate and will be removed in IPython 5.0.""" - print('\n'.join([ - "%install_default_config has been deprecated.", - "Use `ipython profile create ` to initialize a profile", - "with the default config files.", - "Add `--reset` to overwrite already existing config files with defaults." - ])) From ef5c26c448eb0600a9879b940de9b8d08315a178 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:46:53 -0700 Subject: [PATCH 0353/4859] Turn warning into error as marked in the warning message. --- IPython/terminal/embed.py | 3 +-- IPython/utils/warn.py | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index d893c48be15..e69c86cbfce 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -89,8 +89,7 @@ def __init__(self, **kw): if kw.get('user_global_ns', None) is not None: - warnings.warn("user_global_ns has been replaced by user_module. The\ - parameter will be ignored, and removed in IPython 5.0", DeprecationWarning) + raise DeprecationWarning("Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") self._call_location_id = kw.pop('_call_location_id', None) diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index eee175bf41e..1b67423de45 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -11,7 +11,7 @@ import sys import warnings -warnings.warn("The module IPython.utils.warn is deprecated, use the standard warnings module instead", DeprecationWarning) +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): """Standard warning printer. Gives formatting consistency. @@ -30,7 +30,7 @@ def warn(msg,level=2,exit_val=1): -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, use the standard warnings module instead", DeprecationWarning) + 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) From cf807220b3514121263038a09002d512140d72e5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 14:51:41 -0700 Subject: [PATCH 0354/4859] Turn marked deprecation warnings into errors for 5.0 --- IPython/terminal/embed.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index e69c86cbfce..9ada31cf18b 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -196,12 +196,10 @@ def mainloop(self, local_ns=None, module=None, stack_depth=0, """ if (global_ns is not None) and (module is None): - warnings.warn("global_ns is deprecated, and will be removed in IPython 5.0 use module instead.", DeprecationWarning) - module = DummyMod() - module.__dict__ = global_ns + raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") if (display_banner is not None): - warnings.warn("The display_banner parameter is deprecated.", DeprecationWarning) + warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) # Get locals and globals from caller if ((local_ns is None or module is None or compile_flags is None) From bfccb45ebba52ea291bf1382b29ee783218db5c6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:00:42 -0700 Subject: [PATCH 0355/4859] Fix deprecation warning removal notice to 6.0. The 2 notice say contradicting things, fallback to the later. --- IPython/core/builtin_trap.py | 2 +- IPython/lib/deepreload.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/IPython/core/builtin_trap.py b/IPython/core/builtin_trap.py index 95c9ca4bf18..909a555c733 100644 --- a/IPython/core/builtin_trap.py +++ b/IPython/core/builtin_trap.py @@ -57,7 +57,7 @@ def __init__(self, shell=None): from IPython.lib import deepreload if self.shell.deep_reload: from warnings import warn - warn("Automatically replacing builtin `reload` by `deepreload.reload` is deprecated and will be removed in IPython 6.0, please import `reload` explicitly from `IPython.lib.deeprelaod", DeprecationWarning) + 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 diff --git a/IPython/lib/deepreload.py b/IPython/lib/deepreload.py index af226d9c94e..521acf352b0 100644 --- a/IPython/lib/deepreload.py +++ b/IPython/lib/deepreload.py @@ -350,12 +350,12 @@ def _dreload(module, **kwargs): 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, and will be removed in IPython 5.0. +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) -# Uncomment the following to automatically activate deep reloading whenever -# this module is imported -#builtin_mod.reload = reload From 412b95c5a3ab449947ef9bb6f458630e7e211bff Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:06:12 -0700 Subject: [PATCH 0356/4859] Remove shim marked for removal. --- IPython/__init__.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/IPython/__init__.py b/IPython/__init__.py index cd7d1e9b672..9b450da6a0c 100644 --- a/IPython/__init__.py +++ b/IPython/__init__.py @@ -144,14 +144,3 @@ def start_kernel(argv=None, **kwargs): from IPython.kernel.zmq.kernelapp import launch_new_instance return launch_new_instance(argv=argv, **kwargs) -# deprecated shim for IPython.Config -import traitlets.config -class Config(traitlets.config.Config): - def __init__(self, *args, **kwargs): - warnings.warn( - "IPython.Config is deprecated and will be removed in IPython 5." - " Use traitlets.config.Config.", - DeprecationWarning, stacklevel=2, - ) - super(Config, self).__init__(*args, **kwargs) - From f5309065f011eda3b43499c04862ed55885f13d9 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:06:47 -0700 Subject: [PATCH 0357/4859] Be more explicit in some deprecation warnings --- IPython/utils/io.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/IPython/utils/io.py b/IPython/utils/io.py index 826e3b2f237..bab42265b7d 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -23,7 +23,9 @@ @undoc class IOStream: - def __init__(self,stream, fallback=None): + def __init__(self, stream, fallback=None): + warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead', + DeprecationWarning, stacklevel=2) if not hasattr(stream,'write') or not hasattr(stream,'flush'): if fallback is not None: stream = fallback @@ -44,7 +46,7 @@ def __repr__(self): return tpl.format(mod=cls.__module__, cls=cls.__name__, args=self.stream) def write(self,data): - warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead', + warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead', DeprecationWarning, stacklevel=2) try: self._swrite(data) @@ -60,7 +62,7 @@ def write(self,data): file=sys.stderr) def writelines(self, lines): - warn('IOStream is deprecated, use sys.{stdin,stdout,stderr} instead', + warn('IOStream is deprecated since IPython 5.0, use sys.{stdin,stdout,stderr} instead', DeprecationWarning, stacklevel=2) if isinstance(lines, string_types): lines = [lines] From c7755fb9b53e2f6928c1532a04ae1f4bc9ced4ff Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:12:04 -0700 Subject: [PATCH 0358/4859] Remove 'define_magic' alias. --- IPython/core/interactiveshell.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3bcc3e09eb5..a98041c08e4 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2019,7 +2019,6 @@ def init_magics(self): # Expose as public API from the magics manager self.register_magics = self.magics_manager.register - self.define_magic = self.magics_manager.define_magic self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics, m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics, From 919ab3ed90cd174c53136d1dc340c819f43c508f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:23:34 -0700 Subject: [PATCH 0359/4859] Don't register deprecated magics that have been removed. --- IPython/core/interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index a98041c08e4..2de9cb0c379 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2021,7 +2021,7 @@ def init_magics(self): self.register_magics = self.magics_manager.register self.register_magics(m.AutoMagics, m.BasicMagics, m.CodeMagics, - m.ConfigMagics, m.DeprecatedMagics, m.DisplayMagics, m.ExecutionMagics, + m.ConfigMagics, m.DisplayMagics, m.ExecutionMagics, m.ExtensionMagics, m.HistoryMagics, m.LoggingMagics, m.NamespaceMagics, m.OSMagics, m.PylabMagics, m.ScriptMagics, ) From 94e7434af7670eeadeaeeb0db78d31282fb88b60 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 26 May 2016 15:24:00 -0700 Subject: [PATCH 0360/4859] 5.0 is "a few releases" from 0.11, we can probably remove __IPYHTON__active --- IPython/core/interactiveshell.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 2de9cb0c379..c4462811d56 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -643,14 +643,6 @@ def init_builtins(self): # IPython at a time. builtin_mod.__dict__['__IPYTHON__'] = True - # In 0.11 we introduced '__IPYTHON__active' as an integer we'd try to - # manage on enter/exit, but with all our shells it's virtually - # impossible to get all the cases right. We're leaving the name in for - # those who adapted their codes to check for this flag, but will - # eventually remove it after a few more releases. - builtin_mod.__dict__['__IPYTHON__active'] = \ - 'Deprecated, check for __IPYTHON__' - self.builtin_trap = BuiltinTrap(shell=self) def init_inspector(self): From 03f53a74ac2d3f69c468c9d460bd7fc37a7e41d5 Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Mon, 30 May 2016 17:13:02 -0400 Subject: [PATCH 0361/4859] Use the default shell to capture shell output. Adhere to the user $SHELL choice when capturing output from system commands. This makes the getoutput() behavior consistent with that of the system() interactive function. --- IPython/utils/_process_common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/utils/_process_common.py b/IPython/utils/_process_common.py index ce2c19e3f75..3062975c248 100644 --- a/IPython/utils/_process_common.py +++ b/IPython/utils/_process_common.py @@ -17,6 +17,7 @@ import subprocess import shlex import sys +import os from IPython.utils import py3compat @@ -70,6 +71,7 @@ def process_handler(cmd, callback, stderr=subprocess.PIPE): # On win32, close_fds can't be true when using pipes for stdin/out/err close_fds = sys.platform != 'win32' p = subprocess.Popen(cmd, shell=isinstance(cmd, py3compat.string_types), + executable=os.environ.get('SHELL'), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, From ab23885fd4eb61acab89dfea0c3700950d1df452 Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Tue, 31 May 2016 11:01:14 -0400 Subject: [PATCH 0362/4859] Run user $SHELL only for shell commands. Do this only for POSIX systems. Use default shell execution on Windows even if SHELL is set in the environment. --- IPython/utils/_process_common.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/IPython/utils/_process_common.py b/IPython/utils/_process_common.py index 3062975c248..9ede30d3f8a 100644 --- a/IPython/utils/_process_common.py +++ b/IPython/utils/_process_common.py @@ -70,8 +70,14 @@ def process_handler(cmd, callback, stderr=subprocess.PIPE): sys.stderr.flush() # On win32, close_fds can't be true when using pipes for stdin/out/err close_fds = sys.platform != 'win32' - p = subprocess.Popen(cmd, shell=isinstance(cmd, py3compat.string_types), - executable=os.environ.get('SHELL'), + # Determine if cmd should be run with system shell. + shell = isinstance(cmd, py3compat.string_types) + # On POSIX systems run shell commands with user-preferred shell. + executable = None + if shell and os.name == 'posix' and 'SHELL' in os.environ: + executable = os.environ['SHELL'] + p = subprocess.Popen(cmd, shell=shell, + executable=executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, From 49c798c18d45baf197a3db36f85528448d2148f8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 27 May 2016 10:37:51 -0700 Subject: [PATCH 0363/4859] Add flag for simple_prompt. As this mode seem to be useful beyond testing, expose it via a flag and make it official. --- IPython/terminal/ipapp.py | 5 +++++ IPython/terminal/ptshell.py | 15 ++++++++++++++- docs/source/whatsnew/pr/simple_prompt.rst | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 docs/source/whatsnew/pr/simple_prompt.rst diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index 02edabe05be..b39eb52058b 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -102,6 +102,11 @@ def make_report(self,traceback): 'Turn on auto editing of files with syntax errors.', 'Turn off auto editing of files with syntax errors.' ) +addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt', + "Force simple minimal prompt using `raw_input`", + "Use a rich interactive prompt with prompt_toolkit", +) + addflag('banner', 'TerminalIPythonApp.display_banner', "Display a banner upon starting IPython.", "Don't display a banner upon starting IPython." diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index b229284f6b0..d7597c84406 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -31,6 +31,7 @@ from .interactiveshell import get_default_editor, TerminalMagics from .ptutils import IPythonPTCompleter, IPythonPTLexer +_use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() class TerminalInteractiveShell(InteractiveShell): colors_force = True @@ -46,6 +47,18 @@ def _space_for_menu_changed(self, old, new): debugger_history = None debugger_cls = TerminalPdb + simple_prompt = Bool(_use_simple_prompt, + help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. + + Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: + IPython own testing machinery, and emacs inferior-shell integration through elpy. + + This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` + environment variable is set, or the current terminal is not a tty. + + """ + ).tag(config=True) + autoedit_syntax = Bool(False, help="auto editing of files with syntax errors.", ).tag(config=True) @@ -117,7 +130,7 @@ def get_continuation_tokens(self, cli, width): ] def init_prompt_toolkit_cli(self): - if ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or not sys.stdin.isatty(): + if self.simple_prompt: # Fall back to plain non-interactive output for tests. # This is very limited, and only accepts a single line. def prompt(): diff --git a/docs/source/whatsnew/pr/simple_prompt.rst b/docs/source/whatsnew/pr/simple_prompt.rst new file mode 100644 index 00000000000..c9d3ec5e35e --- /dev/null +++ b/docs/source/whatsnew/pr/simple_prompt.rst @@ -0,0 +1,4 @@ +when using IPython as a subprocess, like for emacs inferior-shell, IPython can +be started with --simple-prompt flag, which will bypass the prompt_toolkit +input layer. In this mode completion, prompt color and many other features are +disabled. From b9ee4853d38f873709fd0d246eebed31d27393e5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 31 May 2016 13:42:09 -0700 Subject: [PATCH 0364/4859] Also fall-back on simple debugger if `--simple-prompt` --- IPython/terminal/ptshell.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index d7597c84406..3ac5a2fd744 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -26,7 +26,7 @@ from pygments.styles import get_style_by_name, get_all_styles from pygments.token import Token -from .debugger import TerminalPdb +from .debugger import TerminalPdb, Pdb from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics from .ptutils import IPythonPTCompleter, IPythonPTLexer @@ -59,6 +59,14 @@ def _space_for_menu_changed(self, old, new): """ ).tag(config=True) + @observe('simple_prompt') + def _simple_prompt_changed(self, changes): + if changes['new'] == True: + self.debugger_cls = Pdb + else: + self.debugger_cls = TerminalPdb + + autoedit_syntax = Bool(False, help="auto editing of files with syntax errors.", ).tag(config=True) From e19fec2d40a263b9d4cbf084aa733e2f76420659 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 12 May 2016 19:11:55 -0700 Subject: [PATCH 0365/4859] On Windows, quote paths instead of escaping them. --- IPython/core/completer.py | 9 ++++- IPython/core/interactiveshell.py | 9 ++--- IPython/core/magics/basic.py | 2 - IPython/core/magics/code.py | 5 +-- IPython/core/magics/execution.py | 4 +- IPython/core/magics/osm.py | 14 ++----- IPython/core/tests/test_completer.py | 58 +++++++++++++++------------- IPython/utils/path.py | 2 + IPython/utils/tests/test_path.py | 13 ------- 9 files changed, 52 insertions(+), 64 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index d023e82d533..a969045f9fc 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -117,9 +117,14 @@ def has_open_quotes(s): def protect_filename(s): """Escape a string to protect certain characters.""" + if set(s) & set(PROTECTABLES): + if sys.platform == "win32": + return '"' + s + '"' + else: + return "".join("\\" + c if c in PROTECTABLES else c for c in s) + else: + return s - return "".join([(ch in PROTECTABLES and '\\' + ch or ch) - for ch in s]) def expand_user(path): """Expand '~'-style usernames in strings. diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c6e913ad433..e7093dee252 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -67,7 +67,7 @@ from IPython.utils.io import ask_yes_no from IPython.utils.ipstruct import Struct from IPython.paths import get_ipython_dir -from IPython.utils.path import get_home_dir, get_py_filename, unquote_filename, ensure_dir_exists +from IPython.utils.path import get_home_dir, get_py_filename, ensure_dir_exists from IPython.utils.process import system, getoutput from IPython.utils.py3compat import (builtin_mod, unicode_type, string_types, with_metaclass, iteritems) @@ -3139,10 +3139,9 @@ def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=T code = self.extract_input_lines(target, raw=raw) # Grab history if code: return code - utarget = unquote_filename(target) try: - if utarget.startswith(('http://', 'https://')): - return openpy.read_py_url(utarget, skip_encoding_cookie=skip_encoding_cookie) + if target.startswith(('http://', 'https://')): + return openpy.read_py_url(target, skip_encoding_cookie=skip_encoding_cookie) except UnicodeDecodeError: if not py_only : # Deferred import @@ -3152,7 +3151,7 @@ def find_user_code(self, target, raw=True, py_only=False, skip_encoding_cookie=T from urllib import urlopen response = urlopen(target) return response.read().decode('latin1') - raise ValueError(("'%s' seem to be unreadable.") % utarget) + raise ValueError(("'%s' seem to be unreadable.") % target) potential_target = [target] try : diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index b42aab9e9d1..a71615d33f7 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -13,7 +13,6 @@ from IPython.utils.text import format_screen, dedent, indent from IPython.testing.skipdoctest import skip_doctest from IPython.utils.ipstruct import Struct -from IPython.utils.path import unquote_filename from IPython.utils.py3compat import unicode_type from warnings import warn from logging import error @@ -598,7 +597,6 @@ def notebook(self, s): args = magic_arguments.parse_argstring(self.notebook, s) from nbformat import write, v4 - args.filename = unquote_filename(args.filename) if args.export: cells = [] hist = list(self.shell.history_manager.get_range()) diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index 4581fff6f96..a865d68db2e 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -32,7 +32,7 @@ from IPython.utils import py3compat from IPython.utils.py3compat import string_types from IPython.utils.contexts import preserve_keys -from IPython.utils.path import get_py_filename, unquote_filename +from IPython.utils.path import get_py_filename from warnings import warn from logging import error from IPython.utils.text import get_text_list @@ -189,7 +189,7 @@ def save(self, parameter_s=''): append = 'a' in opts mode = 'a' if append else 'w' ext = u'.ipy' if raw else u'.py' - fname, codefrom = unquote_filename(args[0]), " ".join(args[1:]) + fname, codefrom = args[0], " ".join(args[1:]) if not fname.endswith((u'.py',u'.ipy')): fname += ext file_exists = os.path.isfile(fname) @@ -369,7 +369,6 @@ def _find_edit_target(shell, args, opts, last_call): def make_filename(arg): "Make a filename from the given args" - arg = unquote_filename(arg) try: filename = get_py_filename(arg) except IOError: diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 4edadc9ce70..6ab3d24e720 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -42,7 +42,7 @@ from IPython.utils.capture import capture_output from IPython.utils.ipstruct import Struct from IPython.utils.module_paths import find_mod -from IPython.utils.path import get_py_filename, unquote_filename, shellglob +from IPython.utils.path import get_py_filename, shellglob from IPython.utils.timing import clock, clock2 from warnings import warn from logging import error @@ -338,12 +338,10 @@ def _run_with_profiler(self, code, opts, namespace): dump_file = opts.D[0] text_file = opts.T[0] if dump_file: - dump_file = unquote_filename(dump_file) prof.dump_stats(dump_file) print('\n*** Profile stats marshalled to file',\ repr(dump_file)+'.',sys_exit) if text_file: - text_file = unquote_filename(text_file) pfile = open(text_file,'w') pfile.write(output) pfile.close() diff --git a/IPython/core/magics/osm.py b/IPython/core/magics/osm.py index 5c3db3eb567..352cf2d4513 100644 --- a/IPython/core/magics/osm.py +++ b/IPython/core/magics/osm.py @@ -34,7 +34,6 @@ ) from IPython.testing.skipdoctest import skip_doctest from IPython.utils.openpy import source_to_unicode -from IPython.utils.path import unquote_filename from IPython.utils.process import abbrev_cwd from IPython.utils import py3compat from IPython.utils.py3compat import unicode_type @@ -324,10 +323,7 @@ def cd(self, parameter_s=''): else: - #turn all non-space-escaping backslashes to slashes, - # for c:\windows\directory\names\ - parameter_s = re.sub(r'\\(?! )','/', parameter_s) - opts,ps = self.parse_options(parameter_s,'qb',mode='string') + opts, ps = self.parse_options(parameter_s, 'qb', mode='string') # jump to previous if ps == '-': try: @@ -348,8 +344,6 @@ def cd(self, parameter_s=''): raise UsageError("Bookmark '%s' not found. " "Use '%%bookmark -l' to see your bookmarks." % ps) - # strip extra quotes on Windows, because os.chdir doesn't like them - ps = unquote_filename(ps) # at this point ps should point to the target dir if ps: try: @@ -443,7 +437,7 @@ def pushd(self, parameter_s=''): """ dir_s = self.shell.dir_stack - tgt = os.path.expanduser(unquote_filename(parameter_s)) + tgt = os.path.expanduser(parameter_s) cwd = py3compat.getcwd().replace(self.shell.home_dir,'~') if tgt: self.cd(parameter_s) @@ -781,8 +775,8 @@ def writefile(self, line, cell): The file will be overwritten unless the -a (--append) flag is specified. """ args = magic_arguments.parse_argstring(self.writefile, line) - filename = os.path.expanduser(unquote_filename(args.filename)) - + filename = os.path.expanduser(args.filename) + if os.path.exists(filename): if args.append: print("Appending to %s" % filename) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 4f3ff800088..da7b538b00c 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -36,32 +36,38 @@ def greedy_completion(): ip.Completer.greedy = greedy_original def test_protect_filename(): - pairs = [ ('abc','abc'), - (' abc',r'\ abc'), - ('a bc',r'a\ bc'), - ('a bc',r'a\ \ bc'), - (' bc',r'\ \ bc'), - ] - # On posix, we also protect parens and other special characters - if sys.platform != 'win32': - pairs.extend( [('a(bc',r'a\(bc'), - ('a)bc',r'a\)bc'), - ('a( )bc',r'a\(\ \)bc'), - ('a[1]bc', r'a\[1\]bc'), - ('a{1}bc', r'a\{1\}bc'), - ('a#bc', r'a\#bc'), - ('a?bc', r'a\?bc'), - ('a=bc', r'a\=bc'), - ('a\\bc', r'a\\bc'), - ('a|bc', r'a\|bc'), - ('a;bc', r'a\;bc'), - ('a:bc', r'a\:bc'), - ("a'bc", r"a\'bc"), - ('a*bc', r'a\*bc'), - ('a"bc', r'a\"bc'), - ('a^bc', r'a\^bc'), - ('a&bc', r'a\&bc'), - ] ) + if sys.platform == 'win32': + pairs = [ ('abc','abc'), + (' abc',"' abc'"), + ('a bc',"'a bc'"), + ('a bc',"'a bc'"), + (' bc',"' bc'"), + ] + else: + pairs = [ ('abc','abc'), + (' abc',r'\ abc'), + ('a bc',r'a\ bc'), + ('a bc',r'a\ \ bc'), + (' bc',r'\ \ bc'), + # On posix, we also protect parens and other special characters + ('a(bc',r'a\(bc'), + ('a)bc',r'a\)bc'), + ('a( )bc',r'a\(\ \)bc'), + ('a[1]bc', r'a\[1\]bc'), + ('a{1}bc', r'a\{1\}bc'), + ('a#bc', r'a\#bc'), + ('a?bc', r'a\?bc'), + ('a=bc', r'a\=bc'), + ('a\\bc', r'a\\bc'), + ('a|bc', r'a\|bc'), + ('a;bc', r'a\;bc'), + ('a:bc', r'a\:bc'), + ("a'bc", r"a\'bc"), + ('a*bc', r'a\*bc'), + ('a"bc', r'a\"bc'), + ('a^bc', r'a\^bc'), + ('a&bc', r'a\&bc'), + ] # run the actual tests for s1, s2 in pairs: s1p = completer.protect_filename(s1) diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 94b3d95a69a..1a6cd8e673a 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -74,11 +74,13 @@ def get_long_path_name(path): def unquote_filename(name, win32=(sys.platform=='win32')): """ On Windows, remove leading and trailing quotes from filenames. """ + warn("'unquote_filename' is deprecated", DeprecationWarning) if win32: if name.startswith(("'", '"')) and name.endswith(("'", '"')): name = name[1:-1] return name + def compress_user(path): """Reverse of :func:`os.path.expanduser` """ diff --git a/IPython/utils/tests/test_path.py b/IPython/utils/tests/test_path.py index 1775d72d02b..2378e5134f9 100644 --- a/IPython/utils/tests/test_path.py +++ b/IPython/utils/tests/test_path.py @@ -302,19 +302,6 @@ def test_not_writable_ipdir(): ipdir = paths.get_ipython_dir() env.pop('IPYTHON_DIR', None) -def test_unquote_filename(): - for win32 in (True, False): - nt.assert_equal(path.unquote_filename('foo.py', win32=win32), 'foo.py') - nt.assert_equal(path.unquote_filename('foo bar.py', win32=win32), 'foo bar.py') - nt.assert_equal(path.unquote_filename('"foo.py"', win32=True), 'foo.py') - nt.assert_equal(path.unquote_filename('"foo bar.py"', win32=True), 'foo bar.py') - nt.assert_equal(path.unquote_filename("'foo.py'", win32=True), 'foo.py') - nt.assert_equal(path.unquote_filename("'foo bar.py'", win32=True), 'foo bar.py') - nt.assert_equal(path.unquote_filename('"foo.py"', win32=False), '"foo.py"') - nt.assert_equal(path.unquote_filename('"foo bar.py"', win32=False), '"foo bar.py"') - nt.assert_equal(path.unquote_filename("'foo.py'", win32=False), "'foo.py'") - nt.assert_equal(path.unquote_filename("'foo bar.py'", win32=False), "'foo bar.py'") - @with_environment def test_get_py_filename(): os.chdir(TMP_TEST_DIR) From 4d2184138e4ad630f2149b16e53f903185aa2d8f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 1 Jun 2016 10:31:05 +0100 Subject: [PATCH 0366/4859] Simplify picking debugger class --- IPython/terminal/ptshell.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3ac5a2fd744..cb63634c4b2 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -45,7 +45,6 @@ def _space_for_menu_changed(self, old, new): pt_cli = None debugger_history = None - debugger_cls = TerminalPdb simple_prompt = Bool(_use_simple_prompt, help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. @@ -59,13 +58,9 @@ def _space_for_menu_changed(self, old, new): """ ).tag(config=True) - @observe('simple_prompt') - def _simple_prompt_changed(self, changes): - if changes['new'] == True: - self.debugger_cls = Pdb - else: - self.debugger_cls = TerminalPdb - + @property + def debugger_cls(self): + return Pdb if self.simple_prompt else TerminalPdb autoedit_syntax = Bool(False, help="auto editing of files with syntax errors.", From 06ee4de05f4bfd56fc3eb31bad67520cc91c58b9 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 17 May 2016 14:36:20 +0100 Subject: [PATCH 0367/4859] Don't update width of prompt area Fixes gh-9331 (roughly) The input prompts are now displayed through prompt_toolkit, so this code doesn't know the width it's trying to match. --- IPython/core/prompts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index 0f425570032..bd1dd88e4b5 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -403,10 +403,10 @@ def render(self, name, color=True, just=None, **kwargs): # Handle justification of prompt invis_chars = self.invisible_chars[name] if color else 0 - self.txtwidth = _lenlastline(res) - invis_chars + # self.txtwidth = _lenlastline(res) - invis_chars just = self.justify if (just is None) else just # If the prompt spans more than one line, don't try to justify it: if just and name != 'in' and ('\n' not in res) and ('\r' not in res): res = res.rjust(self.width + invis_chars) - self.width = _lenlastline(res) - invis_chars + # self.width = _lenlastline(res) - invis_chars return res From ecdc51a4be9100f63dee156a0fac273c6c7f647c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 14:41:07 +0100 Subject: [PATCH 0368/4859] New prompts class for terminal interface --- IPython/core/interactiveshell.py | 11 ++-------- IPython/terminal/prompts.py | 36 +++++++++++++++++++++++++++++++ IPython/terminal/ptshell.py | 37 +++++++++++++++++++------------- 3 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 IPython/terminal/prompts.py diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c4462811d56..908f81c6f26 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2339,16 +2339,9 @@ def auto_rewrite_input(self, cmd): """ if not self.show_rewritten_input: return - - rw = self.prompt_manager.render('rewrite') + cmd - try: - # plain ascii works better w/ pyreadline, on some machines, so - # we use it and only print uncolored rewrite if we have unicode - rw = str(rw) - print(rw) - except UnicodeEncodeError: - print("------> " + cmd) + # This is overridden in TerminalInteractiveShell to use fancy prompts + print("------> " + cmd) #------------------------------------------------------------------------- # Things related to extracting values/expressions from kernel and user_ns diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py new file mode 100644 index 00000000000..f39707ba5b9 --- /dev/null +++ b/IPython/terminal/prompts.py @@ -0,0 +1,36 @@ +from pygments.token import Token + +class Prompts(object): + def __init__(self, shell): + self.shell = shell + + def in_prompt_tokens(self, cli=None): + return [ + (Token.Prompt, 'In ['), + (Token.PromptNum, str(self.shell.execution_count)), + (Token.Prompt, ']: '), + ] + + def _width(self): + in_tokens = self.in_prompt_tokens() + return sum(len(s) for (t, s) in in_tokens) + + def continuation_prompt_tokens(self, cli=None, width=None): + if width is None: + width = self._width() + return [ + (Token.Prompt, (' ' * (width - 5)) + '...: '), + ] + + def rewrite_prompt_tokens(self): + width = self._width() + return [ + (Token.Prompt, ('-' * (width - 2)) + '> '), + ] + + def out_prompt_tokens(self): + return [ + (Token.OutPrompt, 'Out['), + (Token.OutPromptNum, str(self.shell.execution_count)), + (Token.OutPrompt, ']: '), + ] diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index cb63634c4b2..fcc64e8d5fe 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -11,7 +11,7 @@ from IPython.utils.py3compat import cast_unicode_py2, input 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 +from traitlets import Bool, Unicode, Dict, Integer, observe, Instance from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone @@ -29,6 +29,7 @@ from .debugger import TerminalPdb, Pdb from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics +from .prompts import Prompts from .ptutils import IPythonPTCompleter, IPythonPTLexer _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() @@ -98,6 +99,11 @@ def _highlighting_style_changed(self, change): editor = Unicode(get_default_editor(), help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ).tag(config=True) + + prompts = Instance(Prompts) + + def _prompts_default(self): + return Prompts(self) term_title = Bool(True, help="Automatically set the terminal title" @@ -120,18 +126,6 @@ def init_term_title(self, change=None): else: toggle_set_term_title(False) - def get_prompt_tokens(self, cli): - return [ - (Token.Prompt, 'In ['), - (Token.PromptNum, str(self.execution_count)), - (Token.Prompt, ']: '), - ] - - def get_continuation_tokens(self, cli, width): - return [ - (Token.Prompt, (' ' * (width - 5)) + '...: '), - ] - def init_prompt_toolkit_cli(self): if self.simple_prompt: # Fall back to plain non-interactive output for tests. @@ -261,8 +255,8 @@ def _layout_options(self): return { 'lexer':IPythonPTLexer(), 'reserve_space_for_menu':self.space_for_menu, - 'get_prompt_tokens':self.get_prompt_tokens, - 'get_continuation_tokens':self.get_continuation_tokens, + 'get_prompt_tokens':self.prompts.in_prompt_tokens, + 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, 'multiline':True, 'display_completions_in_columns': self.display_completions_in_columns, @@ -439,6 +433,19 @@ def int0(x): # work correctly. system = InteractiveShell.system_raw + def auto_rewrite_input(self, cmd): + """Overridden from the parent class to use fancy rewriting prompt""" + if not self.show_rewritten_input: + return + + tokens = self.prompts.rewrite_prompt_tokens() + if self.pt_cli: + self.pt_cli.print_tokens(tokens) + print(cmd) + else: + prompt = ''.join(s for t, s in tokens) + print(prompt, cmd, sep='') + if __name__ == '__main__': TerminalInteractiveShell.instance().interact() From 36dbc76a97d1a1cc2f75e0abedc17187e2951e6c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 14:53:08 +0100 Subject: [PATCH 0369/4859] Use new prompt machinery to generate Out prompts --- IPython/core/displayhook.py | 2 +- IPython/terminal/prompts.py | 14 ++++++++++++++ IPython/terminal/ptshell.py | 9 +++++++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 269ae1820b6..41d03d2c8d5 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -113,7 +113,7 @@ def write_output_prompt(self): """ # Use write, not print which adds an extra space. sys.stdout.write(self.shell.separate_out) - outprompt = self.shell.prompt_manager.render('out') + outprompt = 'Out[{}]: '.format(self.shell.execution_count) if self.do_full_cache: sys.stdout.write(outprompt) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index f39707ba5b9..fdfc9f96ed4 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -1,4 +1,7 @@ from pygments.token import Token +import sys + +from IPython.core.displayhook import DisplayHook class Prompts(object): def __init__(self, shell): @@ -34,3 +37,14 @@ def out_prompt_tokens(self): (Token.OutPromptNum, str(self.shell.execution_count)), (Token.OutPrompt, ']: '), ] + +class RichPromptDisplayHook(DisplayHook): + """Subclass of base display hook using coloured prompt""" + def write_output_prompt(self): + sys.stdout.write(self.shell.separate_out) + if self.do_full_cache: + tokens = self.shell.prompts.out_prompt_tokens() + if self.shell.pt_cli: + self.shell.pt_cli.print_tokens(tokens) + else: + print(*(s for t, s in tokens), sep='') diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index fcc64e8d5fe..40d802bd343 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -29,7 +29,7 @@ from .debugger import TerminalPdb, Pdb from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics -from .prompts import Prompts +from .prompts import Prompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() @@ -104,7 +104,10 @@ def _highlighting_style_changed(self, change): def _prompts_default(self): return Prompts(self) - + + def _displayhook_class_default(self): + return RichPromptDisplayHook + term_title = Bool(True, help="Automatically set the terminal title" ).tag(config=True) @@ -228,6 +231,8 @@ def _make_style_from_name(self, name): style_overrides = { Token.Prompt: '#009900', Token.PromptNum: '#00ff00 bold', + Token.OutPrompt: '#990000', + Token.OutPromptNum: '#ff0000 bold', } if name == 'default': style_cls = get_style_by_name('default') From 366c5a40575d5271b42435d6d30b98e3f9f9394f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:00:42 +0100 Subject: [PATCH 0370/4859] Integrate new prompt machinery with intelli-newlining --- IPython/core/displayhook.py | 6 ++++-- IPython/terminal/prompts.py | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index 41d03d2c8d5..ad3cc27ba65 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -149,6 +149,9 @@ def compute_format_data(self, result): """ return self.shell.display_formatter.format(result) + # This can be set to True by the write_output_prompt method in a subclass + prompt_end_newline = False + def write_format_data(self, format_dict, md_dict=None): """Write the format data dict to the frontend. @@ -179,8 +182,7 @@ def write_format_data(self, format_dict, md_dict=None): # because the expansion may add ANSI escapes that will interfere # with our ability to determine whether or not we should add # a newline. - prompt_template = self.shell.prompt_manager.out_template - if prompt_template and not prompt_template.endswith('\n'): + if not self.prompt_end_newline: # But avoid extraneous empty lines. result_repr = '\n' + result_repr diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index fdfc9f96ed4..8e429672a85 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -42,8 +42,11 @@ class RichPromptDisplayHook(DisplayHook): """Subclass of base display hook using coloured prompt""" def write_output_prompt(self): sys.stdout.write(self.shell.separate_out) + self.prompt_end_newline = False if self.do_full_cache: tokens = self.shell.prompts.out_prompt_tokens() + if tokens and tokens[-1][1].endswith('\n'): + self.prompt_end_newline = True if self.shell.pt_cli: self.shell.pt_cli.print_tokens(tokens) else: From b9c504fb7c49e9aa26c319d2868c40dfa1d9b741 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:09:38 +0100 Subject: [PATCH 0371/4859] Remove usage of prompt_manager --- IPython/core/interactiveshell.py | 3 --- IPython/core/magics/basic.py | 17 ----------------- IPython/core/tests/test_run.py | 7 ------- IPython/sphinxext/ipython_directive.py | 1 - IPython/terminal/interactiveshell.py | 4 ++-- IPython/terminal/ipapp.py | 2 -- 6 files changed, 2 insertions(+), 32 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 908f81c6f26..d7aa60b5467 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -56,7 +56,6 @@ from IPython.core.payload import PayloadManager from IPython.core.prefilter import PrefilterManager from IPython.core.profiledir import ProfileDir -from IPython.core.prompts import PromptManager from IPython.core.usage import default_banner from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest from IPython.utils import PyColorize @@ -664,8 +663,6 @@ def init_io(self): io.stderr = io.IOStream(sys.stderr) def init_prompts(self): - self.prompt_manager = PromptManager(shell=self, parent=self) - self.configurables.append(self.prompt_manager) # Set system prompts, so that scripts can decide if they are running # interactively. sys.ps1 = 'In : ' diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index b42aab9e9d1..a896d1fb326 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -356,14 +356,6 @@ def color_switch_err(name): # Will remove this check after switching to prompt_toolkit new_scheme = 'NoColor' - # Set prompt colors - try: - shell.prompt_manager.color_scheme = new_scheme - except: - color_switch_err('prompt') - else: - shell.colors = \ - shell.prompt_manager.color_scheme_table.active_scheme_name # Set exception colors try: shell.InteractiveTB.set_colors(scheme = new_scheme) @@ -435,7 +427,6 @@ def doctest_mode(self, parameter_s=''): # Shorthands shell = self.shell - pm = shell.prompt_manager meta = shell.meta disp_formatter = self.shell.display_formatter ptformatter = disp_formatter.formatters['text/plain'] @@ -457,16 +448,12 @@ def doctest_mode(self, parameter_s=''): if not mode: # turn on - pm.in_template = '>>> ' - pm.in2_template = '... ' - pm.out_template = '' # Prompt separators like plain python shell.separate_in = '' shell.separate_out = '' shell.separate_out2 = '' - pm.justify = False ptformatter.pprint = False disp_formatter.active_types = ['text/plain'] @@ -474,15 +461,11 @@ def doctest_mode(self, parameter_s=''): shell.magic('xmode Plain') else: # turn off - pm.in_template, pm.in2_template, pm.out_template = dstore.prompt_templates - shell.separate_in = dstore.rc_separate_in shell.separate_out = dstore.rc_separate_out shell.separate_out2 = dstore.rc_separate_out2 - pm.justify = dstore.rc_prompts_pad_left - ptformatter.pprint = dstore.rc_pprint disp_formatter.active_types = dstore.rc_active_types diff --git a/IPython/core/tests/test_run.py b/IPython/core/tests/test_run.py index 5e64fb2a67e..e3ade579548 100644 --- a/IPython/core/tests/test_run.py +++ b/IPython/core/tests/test_run.py @@ -205,13 +205,6 @@ def test_builtins_type(self): _ip = get_ipython() self.run_tmpfile() nt.assert_equal(type(_ip.user_ns['__builtins__']),type(sys)) - - def test_prompts(self): - """Test that prompts correctly generate after %run""" - self.run_tmpfile() - _ip = get_ipython() - p2 = _ip.prompt_manager.render('in2').strip() - nt.assert_equal(p2[:3], '...') def test_run_profile( self ): """Test that the option -p, which invokes the profiler, do not diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index eb1219fe01d..7c13cd47f17 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -898,7 +898,6 @@ def setup(self): if not self.state.document.current_source in self.seen_docs: self.shell.IP.history_manager.reset() self.shell.IP.execution_count = 1 - self.shell.IP.prompt_manager.width = 0 self.seen_docs.add(self.state.document.current_source) # and attach to shell so we don't have to pass them around diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 85f17af14b1..1c1eaef2593 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -614,7 +614,7 @@ def interact(self, display_banner=None): self.hooks.pre_prompt_hook() if more: try: - prompt = self.prompt_manager.render('in2') + prompt = ' ...: ' except: self.showtraceback() if self.autoindent: @@ -622,7 +622,7 @@ def interact(self, display_banner=None): else: try: - prompt = self.separate_in + self.prompt_manager.render('in') + prompt = self.separate_in + 'In [{}]: '.format(self.execution_count) except: self.showtraceback() try: diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index b39eb52058b..d0470a1026b 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -24,7 +24,6 @@ from IPython.core.crashhandler import CrashHandler from IPython.core.formatters import PlainTextFormatter from IPython.core.history import HistoryManager -from IPython.core.prompts import PromptManager from IPython.core.application import ( ProfileDir, BaseIPythonApplication, base_flags, base_aliases ) @@ -195,7 +194,6 @@ def _classes_default(self): InteractiveShellApp, # ShellApp comes before TerminalApp, because self.__class__, # it will also affect subclasses (e.g. QtConsole) TerminalInteractiveShell, - PromptManager, HistoryManager, ProfileDir, PlainTextFormatter, From 566cfa8349748a97e8dfa590fe7a7c6d981b5b2b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:14:20 +0100 Subject: [PATCH 0372/4859] Remove PromptManager class LazyEvaluate is still used in ipykernel --- IPython/core/prompts.py | 392 +---------------------------- IPython/core/tests/test_prompts.py | 94 +------ 2 files changed, 4 insertions(+), 482 deletions(-) diff --git a/IPython/core/prompts.py b/IPython/core/prompts.py index bd1dd88e4b5..7802bc5363c 100644 --- a/IPython/core/prompts.py +++ b/IPython/core/prompts.py @@ -1,37 +1,8 @@ # -*- coding: utf-8 -*- -"""Classes for handling input/output prompts.""" +"""Being removed +""" -# Copyright (c) 2001-2007 Fernando Perez -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. - -import os -import re -import socket -import sys -import time - -from string import Formatter - -from traitlets.config.configurable import Configurable -from IPython.core import release -from IPython.utils import coloransi, py3compat -from traitlets import Unicode, Instance, Dict, Bool, Int, observe, default - -from IPython.utils.PyColorize import LightBGColors, LinuxColors, NoColor - -#----------------------------------------------------------------------------- -# Color schemes for prompts -#----------------------------------------------------------------------------- - -InputColors = coloransi.InputTermColors # just a shorthand -Colors = coloransi.TermColors # just a shorthand - -color_lists = dict(normal=Colors(), inp=InputColors(), nocolor=coloransi.NoColors()) - -#----------------------------------------------------------------------------- -# Utilities -#----------------------------------------------------------------------------- +from IPython.utils import py3compat class LazyEvaluate(object): """This is used for formatting strings with values that need to be updated @@ -53,360 +24,3 @@ def __unicode__(self): def __format__(self, format_spec): return format(self(), format_spec) - -def multiple_replace(dict, text): - """ Replace in 'text' all occurrences of any key in the given - dictionary by its corresponding value. Returns the new string.""" - - # Function by Xavier Defrang, originally found at: - # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/81330 - - # Create a regular expression from the dictionary keys - regex = re.compile("(%s)" % "|".join(map(re.escape, dict.keys()))) - # For each match, look-up corresponding value in dictionary - return regex.sub(lambda mo: dict[mo.string[mo.start():mo.end()]], text) - -#----------------------------------------------------------------------------- -# Special characters that can be used in prompt templates, mainly bash-like -#----------------------------------------------------------------------------- - -# If $HOME isn't defined (Windows), make it an absurd string so that it can -# never be expanded out into '~'. Basically anything which can never be a -# reasonable directory name will do, we just want the $HOME -> '~' operation -# to become a no-op. We pre-compute $HOME here so it's not done on every -# prompt call. - -# FIXME: - -# - This should be turned into a class which does proper namespace management, -# since the prompt specials need to be evaluated in a certain namespace. -# Currently it's just globals, which need to be managed manually by code -# below. - -# - I also need to split up the color schemes from the prompt specials -# somehow. I don't have a clean design for that quite yet. - -HOME = py3compat.str_to_unicode(os.environ.get("HOME","//////:::::ZZZZZ,,,~~~")) - -# This is needed on FreeBSD, and maybe other systems which symlink /home to -# /usr/home, but retain the $HOME variable as pointing to /home -HOME = os.path.realpath(HOME) - -# We precompute a few more strings here for the prompt_specials, which are -# fixed once ipython starts. This reduces the runtime overhead of computing -# prompt strings. -USER = py3compat.str_to_unicode(os.environ.get("USER",'')) -HOSTNAME = py3compat.str_to_unicode(socket.gethostname()) -HOSTNAME_SHORT = HOSTNAME.split(".")[0] - -# IronPython doesn't currently have os.getuid() even if -# os.name == 'posix'; 2/8/2014 -ROOT_SYMBOL = "#" if (os.name=='nt' or sys.platform=='cli' or os.getuid()==0) else "$" - -prompt_abbreviations = { - # Prompt/history count - '%n' : '{color.number}' '{count}' '{color.prompt}', - r'\#': '{color.number}' '{count}' '{color.prompt}', - # Just the prompt counter number, WITHOUT any coloring wrappers, so users - # can get numbers displayed in whatever color they want. - r'\N': '{count}', - - # Prompt/history count, with the actual digits replaced by dots or - # spaces. Used mainly in continuation prompts (prompt_in2). - r'\D': '{dots}', - r'\S': '{spaces}', - - # Current time - r'\T' : '{time}', - # Current working directory - r'\w': '{cwd}', - # Basename of current working directory. - # (use os.sep to make this portable across OSes) - r'\W' : '{cwd_last}', - # These X are an extension to the normal bash prompts. They return - # N terms of the path, after replacing $HOME with '~' - r'\X0': '{cwd_x[0]}', - r'\X1': '{cwd_x[1]}', - r'\X2': '{cwd_x[2]}', - r'\X3': '{cwd_x[3]}', - r'\X4': '{cwd_x[4]}', - r'\X5': '{cwd_x[5]}', - # Y are similar to X, but they show '~' if it's the directory - # N+1 in the list. Somewhat like %cN in tcsh. - r'\Y0': '{cwd_y[0]}', - r'\Y1': '{cwd_y[1]}', - r'\Y2': '{cwd_y[2]}', - r'\Y3': '{cwd_y[3]}', - r'\Y4': '{cwd_y[4]}', - r'\Y5': '{cwd_y[5]}', - # Hostname up to first . - r'\h': HOSTNAME_SHORT, - # Full hostname - r'\H': HOSTNAME, - # Username of current user - r'\u': USER, - # Escaped '\' - '\\\\': '\\', - # Newline - r'\n': '\n', - # Carriage return - r'\r': '\r', - # Release version - r'\v': release.version, - # Root symbol ($ or #) - r'\$': ROOT_SYMBOL, - } - -#----------------------------------------------------------------------------- -# More utilities -#----------------------------------------------------------------------------- - -def cwd_filt(depth): - """Return the last depth elements of the current working directory. - - $HOME is always replaced with '~'. - If depth==0, the full path is returned.""" - - cwd = py3compat.getcwd().replace(HOME,"~") - out = os.sep.join(cwd.split(os.sep)[-depth:]) - return out or os.sep - -def cwd_filt2(depth): - """Return the last depth elements of the current working directory. - - $HOME is always replaced with '~'. - If depth==0, the full path is returned.""" - - full_cwd = py3compat.getcwd() - cwd = full_cwd.replace(HOME,"~").split(os.sep) - if '~' in cwd and len(cwd) == depth+1: - depth += 1 - drivepart = '' - if sys.platform == 'win32' and len(cwd) > depth: - drivepart = os.path.splitdrive(full_cwd)[0] - out = drivepart + '/'.join(cwd[-depth:]) - - return out or os.sep - -#----------------------------------------------------------------------------- -# Prompt classes -#----------------------------------------------------------------------------- - -lazily_evaluate = {'time': LazyEvaluate(time.strftime, "%H:%M:%S"), - 'cwd': LazyEvaluate(py3compat.getcwd), - 'cwd_last': LazyEvaluate(lambda: py3compat.getcwd().split(os.sep)[-1]), - 'cwd_x': [LazyEvaluate(lambda: py3compat.getcwd().replace(HOME,"~"))] +\ - [LazyEvaluate(cwd_filt, x) for x in range(1,6)], - 'cwd_y': [LazyEvaluate(cwd_filt2, x) for x in range(6)] - } - -def _lenlastline(s): - """Get the length of the last line. More intelligent than - len(s.splitlines()[-1]). - """ - if not s or s.endswith(('\n', '\r')): - return 0 - return len(s.splitlines()[-1]) - - -invisible_chars_re = re.compile('\001[^\001\002]*\002') -def _invisible_characters(s): - """ - Get the number of invisible ANSI characters in s. Invisible characters - must be delimited by \001 and \002. - """ - return _lenlastline(s) - _lenlastline(invisible_chars_re.sub('', s)) - -class UserNSFormatter(Formatter): - """A Formatter that falls back on a shell's user_ns and __builtins__ for name resolution""" - def __init__(self, shell): - self.shell = shell - - def get_value(self, key, args, kwargs): - # try regular formatting first: - try: - return Formatter.get_value(self, key, args, kwargs) - except Exception: - pass - # next, look in user_ns and builtins: - for container in (self.shell.user_ns, __builtins__): - if key in container: - return container[key] - # nothing found, put error message in its place - return "" % key - - -class PromptManager(Configurable): - """This is the primary interface for producing IPython's prompts.""" - shell = Instance('IPython.core.interactiveshell.InteractiveShellABC', allow_none=True) - - color_scheme_table = Instance(coloransi.ColorSchemeTable, allow_none=True) - color_scheme = Unicode('Linux').tag(config=True) - - @observe('color_scheme') - def _color_scheme_changed(self, change): - self.color_scheme_table.set_active_scheme(change['new']) - for pname in ['in', 'in2', 'out', 'rewrite']: - # We need to recalculate the number of invisible characters - self.update_prompt(pname) - - lazy_evaluate_fields = Dict(help=""" - This maps field names used in the prompt templates to functions which - will be called when the prompt is rendered. This allows us to include - things like the current time in the prompts. Functions are only called - if they are used in the prompt. - """) - - in_template = Unicode('In [\\#]: ', - help="Input prompt. '\\#' will be transformed to the prompt number" - ).tag(config=True) - in2_template = Unicode(' .\\D.: ', - help="Continuation prompt.").tag(config=True) - out_template = Unicode('Out[\\#]: ', - help="Output prompt. '\\#' will be transformed to the prompt number" - ).tag(config=True) - - @default('lazy_evaluate_fields') - def _lazy_evaluate_fields_default(self): - return lazily_evaluate.copy() - - justify = Bool(True, help=""" - If True (default), each prompt will be right-aligned with the - preceding one. - """).tag(config=True) - - # We actually store the expanded templates here: - templates = Dict() - - # The number of characters in the last prompt rendered, not including - # colour characters. - width = Int() - txtwidth = Int() # Not including right-justification - - # The number of characters in each prompt which don't contribute to width - invisible_chars = Dict() - - @default('invisible_chars') - def _invisible_chars_default(self): - return {'in': 0, 'in2': 0, 'out': 0, 'rewrite':0} - - def __init__(self, shell, **kwargs): - super(PromptManager, self).__init__(shell=shell, **kwargs) - - # Prepare colour scheme table - self.color_scheme_table = coloransi.ColorSchemeTable([NoColor, - LinuxColors, LightBGColors], self.color_scheme) - - self._formatter = UserNSFormatter(shell) - # Prepare templates & numbers of invisible characters - self.update_prompt('in', self.in_template) - self.update_prompt('in2', self.in2_template) - self.update_prompt('out', self.out_template) - self.update_prompt('rewrite') - self.observe(self._update_prompt_trait, - names=['in_template', 'in2_template', 'out_template']) - - def update_prompt(self, name, new_template=None): - """This is called when a prompt template is updated. It processes - abbreviations used in the prompt template (like \#) and calculates how - many invisible characters (ANSI colour escapes) the resulting prompt - contains. - - It is also called for each prompt on changing the colour scheme. In both - cases, traitlets should take care of calling this automatically. - """ - if new_template is not None: - self.templates[name] = multiple_replace(prompt_abbreviations, new_template) - # We count invisible characters (colour escapes) on the last line of the - # prompt, to calculate the width for lining up subsequent prompts. - invis_chars = _invisible_characters(self._render(name, color=True)) - self.invisible_chars[name] = invis_chars - - def _update_prompt_trait(self, changes): - traitname = changes['name'] - new_template = changes['new'] - name = traitname[:-9] # Cut off '_template' - self.update_prompt(name, new_template) - - def _render(self, name, color=True, **kwargs): - """Render but don't justify, or update the width or txtwidth attributes. - """ - if name == 'rewrite': - return self._render_rewrite(color=color) - - if color: - scheme = self.color_scheme_table.active_colors - if name=='out': - colors = color_lists['normal'] - colors.number, colors.prompt, colors.normal = \ - scheme.out_number, scheme.out_prompt, scheme.normal - else: - colors = color_lists['inp'] - colors.number, colors.prompt, colors.normal = \ - scheme.in_number, scheme.in_prompt, scheme.in_normal - if name=='in2': - colors.prompt = scheme.in_prompt2 - else: - # No color - colors = color_lists['nocolor'] - colors.number, colors.prompt, colors.normal = '', '', '' - - count = self.shell.execution_count # Shorthand - # Build the dictionary to be passed to string formatting - fmtargs = dict(color=colors, count=count, - dots="."*len(str(count)), spaces=" "*len(str(count)), - width=self.width, txtwidth=self.txtwidth) - fmtargs.update(self.lazy_evaluate_fields) - fmtargs.update(kwargs) - - # Prepare the prompt - prompt = colors.prompt + self.templates[name] + colors.normal - - # Fill in required fields - return self._formatter.format(prompt, **fmtargs) - - def _render_rewrite(self, color=True): - """Render the ---> rewrite prompt.""" - if color: - scheme = self.color_scheme_table.active_colors - # We need a non-input version of these escapes - color_prompt = scheme.in_prompt.replace("\001","").replace("\002","") - color_normal = scheme.normal - else: - color_prompt, color_normal = '', '' - - return color_prompt + "-> ".rjust(self.txtwidth, "-") + color_normal - - def render(self, name, color=True, just=None, **kwargs): - """ - Render the selected prompt. - - Parameters - ---------- - name : str - Which prompt to render. One of 'in', 'in2', 'out', 'rewrite' - color : bool - If True (default), include ANSI escape sequences for a coloured prompt. - just : bool - If True, justify the prompt to the width of the last prompt. The - default is stored in self.justify. - **kwargs : - Additional arguments will be passed to the string formatting operation, - so they can override the values that would otherwise fill in the - template. - - Returns - ------- - A string containing the rendered prompt. - """ - res = self._render(name, color=color, **kwargs) - - # Handle justification of prompt - invis_chars = self.invisible_chars[name] if color else 0 - # self.txtwidth = _lenlastline(res) - invis_chars - just = self.justify if (just is None) else just - # If the prompt spans more than one line, don't try to justify it: - if just and name != 'in' and ('\n' not in res) and ('\r' not in res): - res = res.rjust(self.width + invis_chars) - # self.width = _lenlastline(res) - invis_chars - return res diff --git a/IPython/core/tests/test_prompts.py b/IPython/core/tests/test_prompts.py index 024ebaa104b..6595daba6c3 100644 --- a/IPython/core/tests/test_prompts.py +++ b/IPython/core/tests/test_prompts.py @@ -3,75 +3,14 @@ import unittest -import os - -from IPython.testing import tools as tt, decorators as dec -from IPython.core.prompts import PromptManager, LazyEvaluate, _invisible_characters +from IPython.core.prompts import LazyEvaluate from IPython.testing.globalipapp import get_ipython -from IPython.utils.tempdir import TemporaryWorkingDirectory -from IPython.utils import py3compat from IPython.utils.py3compat import unicode_type ip = get_ipython() class PromptTests(unittest.TestCase): - def setUp(self): - self.pm = PromptManager(shell=ip, config=ip.config) - - def test_multiline_prompt(self): - self.pm.in_template = "[In]\n>>>" - self.pm.render('in') - self.assertEqual(self.pm.width, 3) - self.assertEqual(self.pm.txtwidth, 3) - - self.pm.in_template = '[In]\n' - self.pm.render('in') - self.assertEqual(self.pm.width, 0) - self.assertEqual(self.pm.txtwidth, 0) - - def test_translate_abbreviations(self): - def do_translate(template): - self.pm.in_template = template - return self.pm.templates['in'] - - pairs = [(r'%n>', '{color.number}{count}{color.prompt}>'), - (r'\T', '{time}'), - (r'\n', '\n') - ] - - tt.check_pairs(do_translate, pairs) - - def test_user_ns(self): - self.pm.color_scheme = 'NoColor' - ip.ex("foo='bar'") - self.pm.in_template = "In [{foo}]" - prompt = self.pm.render('in') - self.assertEqual(prompt, u'In [bar]') - - def test_builtins(self): - self.pm.color_scheme = 'NoColor' - self.pm.in_template = "In [{int}]" - prompt = self.pm.render('in') - self.assertEqual(prompt, u"In [%r]" % int) - - def test_undefined(self): - self.pm.color_scheme = 'NoColor' - self.pm.in_template = "In [{foo_dne}]" - prompt = self.pm.render('in') - self.assertEqual(prompt, u"In []") - - def test_render(self): - self.pm.in_template = r'\#>' - self.assertEqual(self.pm.render('in',color=False), '%d>' % ip.execution_count) - - @dec.onlyif_unicode_paths - def test_render_unicode_cwd(self): - with TemporaryWorkingDirectory(u'ünicødé'): - self.pm.in_template = r'\w [\#]' - p = self.pm.render('in', color=False) - self.assertEqual(p, u"%s [%i]" % (py3compat.getcwd(), ip.execution_count)) - def test_lazy_eval_unicode(self): u = u'ünicødé' lz = LazyEvaluate(lambda : u) @@ -95,35 +34,4 @@ def test_lazy_eval_float(self): self.assertEqual(unicode_type(lz), unicode_type(f)) self.assertEqual(format(lz), str(f)) self.assertEqual(format(lz, '.1'), '0.5') - - @dec.skip_win32 - def test_cwd_x(self): - self.pm.in_template = r"\X0" - save = py3compat.getcwd() - os.chdir(os.path.expanduser('~')) - p = self.pm.render('in', color=False) - try: - self.assertEqual(p, '~') - finally: - os.chdir(save) - - def test_invisible_chars(self): - self.assertEqual(_invisible_characters('abc'), 0) - self.assertEqual(_invisible_characters('\001\033[1;37m\002'), 9) - # Sequences must be between \001 and \002 to be counted - self.assertEqual(_invisible_characters('\033[1;37m'), 0) - # Test custom escape sequences - self.assertEqual(_invisible_characters('\001\033]133;A\a\002'), 10) - - def test_width(self): - default_in = '\x01\x1b]133;A\x07\x02In [1]: \x01\x1b]133;B\x07\x02' - self.pm.in_template = default_in - self.pm.render('in') - self.assertEqual(self.pm.width, 8) - self.assertEqual(self.pm.txtwidth, 8) - # Test custom escape sequences - self.pm.in_template = '\001\033]133;A\a\002' + default_in + '\001\033]133;B\a\002' - self.pm.render('in') - self.assertEqual(self.pm.width, 8) - self.assertEqual(self.pm.txtwidth, 8) From 94cfb0eb919e49916ce81ece3dc6979bf4aa73ee Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:27:32 +0100 Subject: [PATCH 0373/4859] Missed a few uses of prompt manager in doctest code --- IPython/core/magics/basic.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index a896d1fb326..37d3f8ccb2b 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -441,10 +441,8 @@ def doctest_mode(self, parameter_s=''): save_dstore('xmode',shell.InteractiveTB.mode) save_dstore('rc_separate_out',shell.separate_out) save_dstore('rc_separate_out2',shell.separate_out2) - save_dstore('rc_prompts_pad_left',pm.justify) save_dstore('rc_separate_in',shell.separate_in) save_dstore('rc_active_types',disp_formatter.active_types) - save_dstore('prompt_templates',(pm.in_template, pm.in2_template, pm.out_template)) if not mode: # turn on From 6a2667e1b4c5a6b565a703f68400e8f4eaf1bcad Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:39:14 +0100 Subject: [PATCH 0374/4859] Fix shellapp tests --- IPython/core/tests/test_shellapp.py | 10 ++++------ IPython/testing/tools.py | 8 +------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/IPython/core/tests/test_shellapp.py b/IPython/core/tests/test_shellapp.py index 6e2e31b0fa6..8e15743a1c4 100644 --- a/IPython/core/tests/test_shellapp.py +++ b/IPython/core/tests/test_shellapp.py @@ -52,10 +52,9 @@ def test_py_script_file_attribute_interactively(self): src = "True\n" self.mktmp(src) - out = 'In [1]: False\n\nIn [2]:' - err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None - tt.ipexec_validate(self.fname, out, err, options=['-i'], + out, err = tt.ipexec(self.fname, options=['-i'], commands=['"__file__" in globals()', 'exit()']) + self.assertIn("False", out) @dec.skip_win32 @dec.skipif(PY3) @@ -64,7 +63,6 @@ def test_py_script_file_compiler_directive(self): src = "from __future__ import division\n" self.mktmp(src) - out = 'In [1]: float\n\nIn [2]:' - err = SQLITE_NOT_AVAILABLE_ERROR if sqlite_err_maybe else None - tt.ipexec_validate(self.fname, out, err, options=['-i'], + out, err = tt.ipexec(self.fname, options=['-i'], commands=['type(1/2)', 'exit()']) + self.assertIn('float', out) diff --git a/IPython/testing/tools.py b/IPython/testing/tools.py index 73f4ee7201f..bf62f302154 100644 --- a/IPython/testing/tools.py +++ b/IPython/testing/tools.py @@ -202,13 +202,7 @@ def ipexec(fname, options=None, commands=()): """ if options is None: options = [] - # For these subprocess calls, eliminate all prompt printing so we only see - # output from script execution - prompt_opts = [ '--PromptManager.in_template=""', - '--PromptManager.in2_template=""', - '--PromptManager.out_template=""' - ] - cmdargs = default_argv() + prompt_opts + options + cmdargs = default_argv() + options test_dir = os.path.dirname(__file__) From e01d4ada54f2068ad360190aa12b055642b0f92e Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 15:49:36 +0100 Subject: [PATCH 0375/4859] Add __future__ import for prompts module --- IPython/terminal/prompts.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index 8e429672a85..919c72af125 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -1,3 +1,6 @@ +"""Terminal input and output prompts.""" +from __future__ import print_function + from pygments.token import Token import sys From 99b9f151d4940c6873216e099362bd20475c61a7 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 18 May 2016 16:25:27 +0100 Subject: [PATCH 0376/4859] Switch prompts for doctest_mode --- IPython/core/interactiveshell.py | 5 +++++ IPython/core/magics/basic.py | 6 +++++- IPython/terminal/prompts.py | 17 +++++++++++++++++ IPython/terminal/ptshell.py | 16 +++++++++++++++- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index d7aa60b5467..067476a6917 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -3219,6 +3219,11 @@ def cleanup(self): self.restore_sys_module_state() + # Overridden in terminal subclass to change prompts + def switch_doctest_mode(self, mode): + pass + + class InteractiveShellABC(with_metaclass(abc.ABCMeta, object)): """An abstract base class for InteractiveShell.""" diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 37d3f8ccb2b..818a90ccb95 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -469,8 +469,12 @@ def doctest_mode(self, parameter_s=''): shell.magic('xmode ' + dstore.xmode) + # mode here is the state before we switch; switch_doctest_mode takes + # the mode we're switching to. + shell.switch_doctest_mode(not mode) + # Store new mode and inform - dstore.mode = bool(1-int(mode)) + dstore.mode = bool(not mode) mode_label = ['OFF','ON'][dstore.mode] print('Doctest mode is:', mode_label) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index 919c72af125..95471286846 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -41,6 +41,23 @@ def out_prompt_tokens(self): (Token.OutPrompt, ']: '), ] +class ClassicPrompts(Prompts): + def in_prompt_tokens(self, cli=None): + return [ + (Token.Prompt, '>>> '), + ] + + def continuation_prompt_tokens(self, cli=None, width=None): + return [ + (Token.Prompt, '... ') + ] + + def rewrite_prompt_tokens(self): + return [] + + def out_prompt_tokens(self): + return [] + class RichPromptDisplayHook(DisplayHook): """Subclass of base display hook using coloured prompt""" def write_output_prompt(self): diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 40d802bd343..3c34d7c2fb8 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -29,7 +29,7 @@ from .debugger import TerminalPdb, Pdb from .pt_inputhooks import get_inputhook_func from .interactiveshell import get_default_editor, TerminalMagics -from .prompts import Prompts, RichPromptDisplayHook +from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() @@ -105,6 +105,10 @@ def _highlighting_style_changed(self, change): def _prompts_default(self): return Prompts(self) + @observe('prompts') + def _(self, change): + self._update_layout() + def _displayhook_class_default(self): return RichPromptDisplayHook @@ -451,6 +455,16 @@ def auto_rewrite_input(self, cmd): prompt = ''.join(s for t, s in tokens) print(prompt, cmd, sep='') + _prompts_before = None + def switch_doctest_mode(self, mode): + """Switch prompts to classic for %doctest_mode""" + if mode: + self._prompts_before = self.prompts + self.prompts = ClassicPrompts(self) + elif self._prompts_before: + self.prompts = self._prompts_before + self._prompts_before = None + if __name__ == '__main__': TerminalInteractiveShell.instance().interact() From 95ed0855ae23e55c10b46903db911265aa1cdd58 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 31 May 2016 12:24:20 -0700 Subject: [PATCH 0377/4859] Add some documentation on how to configure prompts. --- docs/source/config/details.rst | 63 ------------------------------- docs/source/config/intro.rst | 5 --- docs/source/interactive/shell.rst | 54 +++++++++++++++++++------- examples/utils/cwd_prompt.py | 26 +++++++++++++ 4 files changed, 66 insertions(+), 82 deletions(-) create mode 100644 examples/utils/cwd_prompt.py diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index c8b01c7fdeb..3f7414b65fa 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -2,52 +2,6 @@ Specific config details ======================= -Prompts -======= - -In the terminal, the format of the input and output prompts can be -customised. This does not currently affect other frontends. - -The following codes in the prompt string will be substituted into the -prompt string: - -====== =================================== ===================================================== -Short Long Notes -====== =================================== ===================================================== -%n,\\# {color.number}{count}{color.prompt} history counter with bolding -\\N {count} history counter without bolding -\\D {dots} series of dots the same width as the history counter -\\T {time} current time -\\w {cwd} current working directory -\\W {cwd_last} basename of CWD -\\Xn {cwd_x[n]} Show the last n terms of the CWD. n=0 means show all. -\\Yn {cwd_y[n]} Like \Xn, but show '~' for $HOME -\\h hostname, up to the first '.' -\\H full hostname -\\u username (from the $USER environment variable) -\\v IPython version -\\$ root symbol ("$" for normal user or "#" for root) -``\\`` escaped '\\' -\\n newline -\\r carriage return -n/a {color.} set terminal colour - see below for list of names -====== =================================== ===================================================== - -Available colour names are: Black, BlinkBlack, BlinkBlue, BlinkCyan, -BlinkGreen, BlinkLightGray, BlinkPurple, BlinkRed, BlinkYellow, Blue, -Brown, Cyan, DarkGray, Green, LightBlue, LightCyan, LightGray, LightGreen, -LightPurple, LightRed, Purple, Red, White, Yellow. The selected colour -scheme also defines the names *prompt* and *number*. Finally, the name -*normal* resets the terminal to its default colour. - -So, this config:: - - c.PromptManager.in_template = "{color.LightGreen}{time}{color.Yellow} \u{color.normal}>>>" - -will produce input prompts with the time in light green, your username -in yellow, and a ``>>>`` prompt in the default terminal colour. - - .. _termcolour: Terminal Colors @@ -84,27 +38,10 @@ These have shown problems: extensions. Once Gary's readline library is installed, the normal WinXP/2k command prompt works perfectly. -Currently the following color schemes are available: - - * NoColor: uses no color escapes at all (all escapes are empty '' '' - strings). This 'scheme' is thus fully safe to use in any terminal. - * Linux: works well in Linux console type environments: dark - background with light fonts. It uses bright colors for - information, so it is difficult to read if you have a light - colored background. - * LightBG: the basic colors are similar to those in the Linux scheme - but darker. It is easy to read in terminals with light backgrounds. - IPython uses colors for two main groups of things: prompts and tracebacks which are directly printed to the terminal, and the object introspection system which passes large sets of data through a pager. -If you are seeing garbage sequences in your terminal and no colour, you -may need to disable colours: run ``%colors NoColor`` inside IPython, or -add this to a config file:: - - c.InteractiveShell.colors = 'NoColor' - Colors in the pager ------------------- diff --git a/docs/source/config/intro.rst b/docs/source/config/intro.rst index f91e70127b7..d3ab800a615 100644 --- a/docs/source/config/intro.rst +++ b/docs/source/config/intro.rst @@ -73,11 +73,6 @@ Example config file c.InteractiveShell.editor = 'nano' c.InteractiveShell.xmode = 'Context' - c.PromptManager.in_template = 'In [\#]: ' - c.PromptManager.in2_template = ' .\D.: ' - c.PromptManager.out_template = 'Out[\#]: ' - c.PromptManager.justify = True - c.PrefilterManager.multi_line_specials = True c.AliasManager.user_aliases = [ diff --git a/docs/source/interactive/shell.rst b/docs/source/interactive/shell.rst index 4ba0f54ef32..5724efbf252 100644 --- a/docs/source/interactive/shell.rst +++ b/docs/source/interactive/shell.rst @@ -63,20 +63,46 @@ switching to any of them. Type ``cd?`` for more details. Prompt customization ==================== -Here are some prompt configurations you can try out interactively by using the -``%config`` magic:: - - %config PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> ' - %config PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> ' - %config PromptManager.out_template = r'<\#> ' - - -You can change the prompt configuration to your liking permanently by editing -``ipython_config.py``:: - - c.PromptManager.in_template = r'{color.LightGreen}\u@\h{color.LightBlue}[{color.LightCyan}\Y1{color.LightBlue}]{color.Green}|\#> ' - c.PromptManager.in2_template = r'{color.Green}|{color.LightGreen}\D{color.Green}> ' - c.PromptManager.out_template = r'<\#> ' +Starting at IPython 5.0 the prompt customisation is done by subclassing :class:`IPython.terminal.prompts.Prompt`. + +The custom ``Prompt`` receive the current IPython shell instance as first +argument, which by default is stored as the ``shell`` attribute of the object. +The class can implement optional methods for each of the available prompt types: + + - ``in_prompt_tokens(self, cli=None)``, input prompt , default to ``In [1]`` + - ``continuation_prompt_tokens(self, cli=None, width=None)``, continuation prompt for multi lines (default `...:`) + - ``rewrite_prompt_tokens(self)`` + - ``out_prompt_tokens(self)`` + +Each of these methods should return a list of `(TokenType, Token)` pairs. See documentation of `prompt_toolkit` and/or `Pygments`. + +Here is an example of Prompt class that will insert the current working directory in front of a prompt: + + +.. codeblock:: python + + from IPython.terminal.prompts import Prompts, Token + import os + + class MyPrompt(Prompts): + + def in_prompt_tokens(self, cli=None): + return [(Token, os.getcwd()), + (Token.Prompt, ' >>>')] + +To set the new prompt, assign it to the `prompts` attribute of the IPython shell: + +.. codeblock:: python + + In[2]: ip = get_ipython() + ...: ip.prompts = MyPrompt(ip) + + ~/ >>> # it works + + +See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an +extensions that customise prompts. + Read more about the :ref:`configuration system ` for details on how to find ``ipython_config.py``. diff --git a/examples/utils/cwd_prompt.py b/examples/utils/cwd_prompt.py new file mode 100644 index 00000000000..1d1b03ac66b --- /dev/null +++ b/examples/utils/cwd_prompt.py @@ -0,0 +1,26 @@ +"""This is an example that shows how to create new prompts for IPython +""" + +from IPython.terminal.prompts import Prompts, Token +import os + +class MyPrompt(Prompts): + + def in_prompt_tokens(self, cli=None): + return [(Token, os.getcwd()), + (Token.Prompt, '>>>')] + +def load_ipython_extension(shell): + new_prompts = MyPrompt(shell) + new_prompts.old_prompts = shell.prompts + shell.prompts = new_prompts + +def unload_ipython_extension(shell): + if not hasattr(shell.prompts, 'old_prompts'): + print("cannot unload") + else: + shell.prompts = shell.prompts.old_prompts + + + + From 0021167631bbadb1b4e82deb4420e99c3cbb6cb8 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 31 May 2016 15:28:34 -0700 Subject: [PATCH 0378/4859] Use generic showtraceback() instead of showsyntaxerror() Should close #9199 --- IPython/core/interactiveshell.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c4462811d56..d081dfd859a 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1604,7 +1604,7 @@ def init_traceback_handlers(self, custom_exceptions): self.InteractiveTB.set_mode(mode=self.xmode) def set_custom_exc(self, exc_tuple, handler): - """set_custom_exc(exc_tuple,handler) + """set_custom_exc(exc_tuple, handler) Set a custom exception handler, which will be called if any of the exceptions in exc_tuple occur in the mainloop (specifically, in the @@ -1647,7 +1647,7 @@ def my_handler(self, etype, value, tb, tb_offset=None): assert type(exc_tuple)==type(()) , \ "The custom exceptions must be given AS A TUPLE." - def dummy_handler(self,etype,value,tb,tb_offset=None): + def dummy_handler(self, etype, value, tb, tb_offset=None): print('*** Simple custom exception handler ***') print('Exception type :',etype) print('Exception value:',value) @@ -2682,6 +2682,10 @@ def error_before_exec(value): # Compile to bytecode try: code_ast = compiler.ast_parse(cell, filename=cell_name) + except self.custom_exceptions as e: + etype, value, tb = sys.exc_info() + self.CustomTB(etype, value, tb) + return error_before_exec(e) except IndentationError as e: self.showindentationerror() if store_history: From bfe8da61676f6293bcee49c1be286e4452b9ba1b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 31 May 2016 15:35:43 -0700 Subject: [PATCH 0379/4859] Test that custom exceptions handlers can handle `SyntaxError`s --- IPython/core/tests/test_interactiveshell.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 11164d47a5b..3a38c84f2b5 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -434,6 +434,21 @@ def foo(self): found = ip._ofind('a.foo', [('locals', locals())]) nt.assert_is(found['obj'], A.foo) + def test_custom_syntaxerror_exception(self): + called = [] + 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((SyntaxError,), my_handler) + try: + ip.run_cell("1f") + # Check that this was called, and only once. + self.assertEqual(called, [SyntaxError]) + finally: + # Reset the custom exception hook + ip.set_custom_exc((), None) + def test_custom_exception(self): called = [] def my_handler(shell, etype, value, tb, tb_offset=None): From 780fdb8820fe743c4ea53f2a054b6efbd1bb1833 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 1 Jun 2016 11:33:30 -0700 Subject: [PATCH 0380/4859] Make numpy a test dependency. Since April 2016, numpy (1.11.0) have manylinux1 uploaded on PyPI. There is thus no reasons not to require numpy for testing. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b4f98268995..c80bfa92390 100755 --- a/setup.py +++ b/setup.py @@ -182,7 +182,7 @@ def run(self): parallel = ['ipyparallel'], qtconsole = ['qtconsole'], doc = ['Sphinx>=1.3'], - test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel'], + test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel', 'numpy'], terminal = [], kernel = ['ipykernel'], nbformat = ['nbformat'], From e14fb804dd2bee43505580450c0b28f786a218fb Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 14 Apr 2016 16:55:30 +0100 Subject: [PATCH 0381/4859] Remove the readline shell machinery IPython now uses the prompt_toolkit based TerminalInteractiveShell instead, so this removes the readline code we're no longer using. --- IPython/terminal/interactiveshell.py | 810 +----------------- IPython/terminal/magics.py | 207 +++++ IPython/terminal/ptshell.py | 26 +- .../terminal/tests/test_interactivshell.py | 187 +--- 4 files changed, 247 insertions(+), 983 deletions(-) create mode 100644 IPython/terminal/magics.py diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 1c1eaef2593..a294a9d99ab 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -1,810 +1,18 @@ # -*- coding: utf-8 -*- -"""Subclass of InteractiveShell for terminal based frontends.""" +"""DEPRECATED: old import location of TerminalInteractiveShell""" # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. -from __future__ import print_function - -import bdb -import os -import sys - -from IPython.core.error import TryNext, UsageError -from IPython.core.usage import interactive_usage -from IPython.core.inputsplitter import IPythonInputSplitter, ESC_MAGIC -from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC -from IPython.core.magic import Magics, magics_class, line_magic -from IPython.lib.clipboard import ClipboardEmpty -from IPython.utils.contexts import NoOpContext -from IPython.utils.decorators import undoc -from IPython.utils.encoding import get_stream_enc -from IPython.utils import py3compat -from IPython.utils.terminal import toggle_set_term_title, set_term_title -from IPython.utils.process import abbrev_cwd from warnings import warn -from logging import error -from IPython.utils.text import num_ini_spaces, SList, strip_email_quotes -from traitlets import Integer, CBool, Unicode - -def get_default_editor(): - try: - ed = os.environ['EDITOR'] - if not py3compat.PY3: - ed = ed.decode() - return ed - except KeyError: - pass - except UnicodeError: - warn("$EDITOR environment variable is not pure ASCII. Using platform " - "default editor.") - - if os.name == 'posix': - return 'vi' # the only one guaranteed to be there! - else: - return 'notepad' # same in Windows! - -def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False): - """ Yield pasted lines until the user enters the given sentinel value. - """ - if not quiet: - print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \ - % sentinel) - prompt = ":" - else: - prompt = "" - while True: - try: - l = py3compat.str_to_unicode(l_input(prompt)) - if l == sentinel: - return - else: - yield l - except EOFError: - print('') - return +from IPython.utils.decorators import undoc +from .ptshell import TerminalInteractiveShell as PromptToolkitShell @undoc -def no_op(*a, **kw): pass - - -class ReadlineNoRecord(object): - """Context manager to execute some code, then reload readline history - so that interactive input to the code doesn't appear when pressing up.""" - def __init__(self, shell): - self.shell = shell - self._nested_level = 0 - - def __enter__(self): - if self._nested_level == 0: - try: - self.orig_length = self.current_length() - self.readline_tail = self.get_readline_tail() - except (AttributeError, IndexError): # Can fail with pyreadline - self.orig_length, self.readline_tail = 999999, [] - self._nested_level += 1 - - def __exit__(self, type, value, traceback): - self._nested_level -= 1 - if self._nested_level == 0: - # Try clipping the end if it's got longer - try: - e = self.current_length() - self.orig_length - if e > 0: - for _ in range(e): - self.shell.readline.remove_history_item(self.orig_length) - - # If it still doesn't match, just reload readline history. - if self.current_length() != self.orig_length \ - or self.get_readline_tail() != self.readline_tail: - self.shell.refill_readline_hist() - except (AttributeError, IndexError): - pass - # Returning False will cause exceptions to propagate - return False - - def current_length(self): - return self.shell.readline.get_current_history_length() - - def get_readline_tail(self, n=10): - """Get the last n items in readline history.""" - end = self.shell.readline.get_current_history_length() + 1 - start = max(end-n, 1) - ghi = self.shell.readline.get_history_item - return [ghi(x) for x in range(start, end)] - - -@magics_class -class TerminalMagics(Magics): - def __init__(self, shell): - super(TerminalMagics, self).__init__(shell) - self.input_splitter = IPythonInputSplitter() - - def store_or_execute(self, block, name): - """ Execute a block, or store it in a variable, per the user's request. - """ - if name: - # If storing it for further editing - self.shell.user_ns[name] = SList(block.splitlines()) - print("Block assigned to '%s'" % name) - else: - b = self.preclean_input(block) - self.shell.user_ns['pasted_block'] = b - self.shell.using_paste_magics = True - try: - self.shell.run_cell(b) - finally: - self.shell.using_paste_magics = False - - def preclean_input(self, block): - lines = block.splitlines() - while lines and not lines[0].strip(): - lines = lines[1:] - return strip_email_quotes('\n'.join(lines)) - - def rerun_pasted(self, name='pasted_block'): - """ Rerun a previously pasted command. - """ - b = self.shell.user_ns.get(name) - - # Sanity checks - if b is None: - raise UsageError('No previous pasted block available') - if not isinstance(b, py3compat.string_types): - raise UsageError( - "Variable 'pasted_block' is not a string, can't execute") - - print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))) - self.shell.run_cell(b) - - @line_magic - def autoindent(self, parameter_s = ''): - """Toggle autoindent on/off (if available).""" - - self.shell.set_autoindent() - print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent]) - - @line_magic - def cpaste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - You must terminate the block with '--' (two minus-signs) or Ctrl-D - alone on the line. You can also provide your own sentinel with '%paste - -s %%' ('%%' is the new sentinel for this operation). - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%cpaste foo'. - This assigns the pasted block to variable 'foo' as string, without - dedenting or executing it (preceding >>> and + is still stripped) - - '%cpaste -r' re-executes the block previously entered by cpaste. - '%cpaste -q' suppresses any additional output messages. - - Do not be alarmed by garbled output on Windows (it's a readline bug). - Just press enter and type -- (and press enter again) and the block - will be what was just pasted. - - IPython statements (magics, shell escapes) are not supported (yet). - - See also - -------- - paste: automatically pull code from clipboard. - - Examples - -------- - :: - - In [8]: %cpaste - Pasting code; enter '--' alone on the line to stop. - :>>> a = ["world!", "Hello"] - :>>> print " ".join(sorted(a)) - :-- - Hello world! - """ - opts, name = self.parse_options(parameter_s, 'rqs:', mode='string') - if 'r' in opts: - self.rerun_pasted() - return - - quiet = ('q' in opts) - - sentinel = opts.get('s', u'--') - block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet)) - self.store_or_execute(block, name) - - @line_magic - def paste(self, parameter_s=''): - """Paste & execute a pre-formatted code block from clipboard. - - The text is pulled directly from the clipboard without user - intervention and printed back on the screen before execution (unless - the -q flag is given to force quiet mode). - - The block is dedented prior to execution to enable execution of method - definitions. '>' and '+' characters at the beginning of a line are - ignored, to allow pasting directly from e-mails, diff files and - doctests (the '...' continuation prompt is also stripped). The - executed block is also assigned to variable named 'pasted_block' for - later editing with '%edit pasted_block'. - - You can also pass a variable name as an argument, e.g. '%paste foo'. - This assigns the pasted block to variable 'foo' as string, without - executing it (preceding >>> and + is still stripped). - - Options: - - -r: re-executes the block previously entered by cpaste. - - -q: quiet mode: do not echo the pasted text back to the terminal. - - IPython statements (magics, shell escapes) are not supported (yet). - - See also - -------- - cpaste: manually paste code into terminal until you mark its end. - """ - opts, name = self.parse_options(parameter_s, 'rq', mode='string') - if 'r' in opts: - self.rerun_pasted() - return - try: - block = self.shell.hooks.clipboard_get() - except TryNext as clipboard_exc: - message = getattr(clipboard_exc, 'args') - if message: - error(message[0]) - else: - error('Could not get text from the clipboard.') - return - except ClipboardEmpty: - raise UsageError("The clipboard appears to be empty") - - # By default, echo back to terminal unless quiet mode is requested - if 'q' not in opts: - write = self.shell.write - write(self.shell.pycolorize(block)) - if not block.endswith('\n'): - write('\n') - write("## -- End pasted text --\n") - - self.store_or_execute(block, name) - - # Class-level: add a '%cls' magic only on Windows - if sys.platform == 'win32': - @line_magic - def cls(self, s): - """Clear screen. - """ - os.system("cls") - - -class TerminalInteractiveShell(InteractiveShell): - - autoedit_syntax = CBool(False, config=True, - help="auto editing of files with syntax errors.") - confirm_exit = CBool(True, config=True, - help=""" - Set to confirm when you try to exit IPython with an EOF (Control-D - in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', - you can force a direct exit without any confirmation.""", - ) - # This display_banner only controls whether or not self.show_banner() - # is called when mainloop/interact are called. The default is False - # because for the terminal based application, the banner behavior - # is controlled by the application. - display_banner = CBool(False) # This isn't configurable! - embedded = CBool(False) - embedded_active = CBool(False) - editor = Unicode(get_default_editor(), config=True, - help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." - ) - pager = Unicode('less', config=True, - help="The shell program to be used for paging.") - - screen_length = Integer(0, config=True, - help= - """Number of lines of your screen, used to control printing of very - long strings. Strings longer than this number of lines will be sent - through a pager instead of directly printed. The default value for - this is 0, which means IPython will auto-detect your screen size every - time it needs to print certain potentially long strings (this doesn't - change the behavior of the 'print' keyword, it's only triggered - internally). If for some reason this isn't working well (it needs - curses support), specify it yourself. Otherwise don't change the - default.""", - ) - term_title = CBool(False, config=True, - help="Enable auto setting the terminal title." - ) - usage = Unicode(interactive_usage) - - # This `using_paste_magics` is used to detect whether the code is being - # executed via paste magics functions - using_paste_magics = CBool(False) - - # In the terminal, GUI control is done via PyOS_InputHook - @staticmethod - def enable_gui(gui=None, app=None): - """Switch amongst GUI input hooks by name. - """ - # Deferred import - from IPython.lib.inputhook import enable_gui as real_enable_gui - try: - return real_enable_gui(gui, app) - except ValueError as e: - raise UsageError("%s" % e) - - system = InteractiveShell.system_raw - - #------------------------------------------------------------------------- - # Overrides of init stages - #------------------------------------------------------------------------- - - def init_display_formatter(self): - super(TerminalInteractiveShell, self).init_display_formatter() - # terminal only supports plaintext - self.display_formatter.active_types = ['text/plain'] - - #------------------------------------------------------------------------- - # Things related to readline - #------------------------------------------------------------------------- - - def init_readline(self): - """Command history completion/saving/reloading.""" - - if self.readline_use: - import IPython.utils.rlineimpl as readline - - self.rl_next_input = None - self.rl_do_indent = False - - if not self.readline_use or not readline.have_readline: - self.readline = None - # Set a number of methods that depend on readline to be no-op - self.readline_no_record = NoOpContext() - self.set_readline_completer = no_op - self.set_custom_completer = no_op - if self.readline_use: - warn('Readline services not available or not loaded.') - else: - self.has_readline = True - self.readline = readline - sys.modules['readline'] = readline - - # Platform-specific configuration - if os.name == 'nt': - # FIXME - check with Frederick to see if we can harmonize - # naming conventions with pyreadline to avoid this - # platform-dependent check - self.readline_startup_hook = readline.set_pre_input_hook - else: - self.readline_startup_hook = readline.set_startup_hook - - # Readline config order: - # - IPython config (default value) - # - custom inputrc - # - IPython config (user customized) - - # load IPython config before inputrc if default - # skip if libedit because parse_and_bind syntax is different - if not self._custom_readline_config and not readline.uses_libedit: - for rlcommand in self.readline_parse_and_bind: - readline.parse_and_bind(rlcommand) - - # Load user's initrc file (readline config) - # Or if libedit is used, load editrc. - inputrc_name = os.environ.get('INPUTRC') - if inputrc_name is None: - inputrc_name = '.inputrc' - if readline.uses_libedit: - inputrc_name = '.editrc' - inputrc_name = os.path.join(self.home_dir, inputrc_name) - if os.path.isfile(inputrc_name): - try: - readline.read_init_file(inputrc_name) - except: - warn('Problems reading readline initialization file <%s>' - % inputrc_name) - - # load IPython config after inputrc if user has customized - if self._custom_readline_config: - for rlcommand in self.readline_parse_and_bind: - readline.parse_and_bind(rlcommand) - - # Remove some chars from the delimiters list. If we encounter - # unicode chars, discard them. - delims = readline.get_completer_delims() - if not py3compat.PY3: - delims = delims.encode("ascii", "ignore") - for d in self.readline_remove_delims: - delims = delims.replace(d, "") - delims = delims.replace(ESC_MAGIC, '') - readline.set_completer_delims(delims) - # Store these so we can restore them if something like rpy2 modifies - # them. - self.readline_delims = delims - # otherwise we end up with a monster history after a while: - readline.set_history_length(self.history_length) - - self.refill_readline_hist() - self.readline_no_record = ReadlineNoRecord(self) - - # Configure auto-indent for all platforms - self.set_autoindent(self.autoindent) - - def init_completer(self): - super(TerminalInteractiveShell, self).init_completer() - - # Only configure readline if we truly are using readline. - if self.has_readline: - self.set_readline_completer() - - def set_readline_completer(self): - """Reset readline's completer to be our own.""" - self.readline.set_completer(self.Completer.rlcomplete) - - - def pre_readline(self): - """readline hook to be used at the start of each line. - - It handles auto-indent and text from set_next_input.""" - - if self.rl_do_indent: - self.readline.insert_text(self._indent_current_str()) - if self.rl_next_input is not None: - self.readline.insert_text(self.rl_next_input) - self.rl_next_input = None - - def refill_readline_hist(self): - # Load the last 1000 lines from history - self.readline.clear_history() - stdin_encoding = sys.stdin.encoding or "utf-8" - last_cell = u"" - for _, _, cell in self.history_manager.get_tail(self.history_load_length, - include_latest=True): - # Ignore blank lines and consecutive duplicates - cell = cell.rstrip() - if cell and (cell != last_cell): - try: - if self.multiline_history: - self.readline.add_history(py3compat.unicode_to_str(cell, - stdin_encoding)) - else: - for line in cell.splitlines(): - self.readline.add_history(py3compat.unicode_to_str(line, - stdin_encoding)) - last_cell = cell - - except (TypeError, ValueError) as e: - # The history DB can get corrupted so it returns strings - # containing null bytes, which readline objects to. - warn(("Failed to add string to readline history.\n" - "Error: {}\n" - "Cell: {!r}").format(e, cell)) - - #------------------------------------------------------------------------- - # Things related to the terminal - #------------------------------------------------------------------------- - - @property - def usable_screen_length(self): - if self.screen_length == 0: - return 0 - else: - num_lines_bot = self.separate_in.count('\n')+1 - return self.screen_length - num_lines_bot - - def _term_title_changed(self, name, new_value): - self.init_term_title() - - def init_term_title(self): - # Enable or disable the terminal title. - if self.term_title: - toggle_set_term_title(True) - set_term_title('IPython: ' + abbrev_cwd()) - else: - toggle_set_term_title(False) - - #------------------------------------------------------------------------- - # Things related to aliases - #------------------------------------------------------------------------- - - def init_alias(self): - # The parent class defines aliases that can be safely used with any - # frontend. - super(TerminalInteractiveShell, self).init_alias() - - # Now define aliases that only make sense on the terminal, because they - # need direct access to the console in a way that we can't emulate in - # GUI or web frontend - if os.name == 'posix': - aliases = [('clear', 'clear'), ('more', 'more'), ('less', 'less'), - ('man', 'man')] - else : - aliases = [] - - for name, cmd in aliases: - self.alias_manager.soft_define_alias(name, cmd) - - #------------------------------------------------------------------------- - # Mainloop and code execution logic - #------------------------------------------------------------------------- - - def mainloop(self, display_banner=None): - """Start the mainloop. - - If an optional banner argument is given, it will override the - internally created default banner. - """ - - with self.builtin_trap, self.display_trap: - - while 1: - try: - self.interact(display_banner=display_banner) - #self.interact_with_readline() - # XXX for testing of a readline-decoupled repl loop, call - # interact_with_readline above - break - except KeyboardInterrupt: - # this should not be necessary, but KeyboardInterrupt - # handling seems rather unpredictable... - self.write("\nKeyboardInterrupt in interact()\n") - - def _replace_rlhist_multiline(self, source_raw, hlen_before_cell): - """Store multiple lines as a single entry in history""" - - # do nothing without readline or disabled multiline - if not self.has_readline or not self.multiline_history: - return hlen_before_cell - - # windows rl has no remove_history_item - if not hasattr(self.readline, "remove_history_item"): - return hlen_before_cell - - # skip empty cells - if not source_raw.rstrip(): - return hlen_before_cell - - # nothing changed do nothing, e.g. when rl removes consecutive dups - hlen = self.readline.get_current_history_length() - if hlen == hlen_before_cell: - return hlen_before_cell - - for i in range(hlen - hlen_before_cell): - self.readline.remove_history_item(hlen - i - 1) - stdin_encoding = get_stream_enc(sys.stdin, 'utf-8') - self.readline.add_history(py3compat.unicode_to_str(source_raw.rstrip(), - stdin_encoding)) - return self.readline.get_current_history_length() - - def interact(self, display_banner=None): - """Closely emulate the interactive Python console.""" - - # batch run -> do not interact - if self.exit_now: - return - - if display_banner is None: - display_banner = self.display_banner - - if isinstance(display_banner, py3compat.string_types): - self.show_banner(display_banner) - elif display_banner: - self.show_banner() - - more = False - - if self.has_readline: - self.readline_startup_hook(self.pre_readline) - hlen_b4_cell = self.readline.get_current_history_length() - else: - hlen_b4_cell = 0 - # exit_now is set by a call to %Exit or %Quit, through the - # ask_exit callback. - - while not self.exit_now: - self.hooks.pre_prompt_hook() - if more: - try: - prompt = ' ...: ' - except: - self.showtraceback() - if self.autoindent: - self.rl_do_indent = True - - else: - try: - prompt = self.separate_in + 'In [{}]: '.format(self.execution_count) - except: - self.showtraceback() - try: - line = self.raw_input(prompt) - if self.exit_now: - # quick exit on sys.std[in|out] close - break - if self.autoindent: - self.rl_do_indent = False - - except KeyboardInterrupt: - #double-guard against keyboardinterrupts during kbdint handling - try: - self.write('\n' + self.get_exception_only()) - source_raw = self.input_splitter.raw_reset() - hlen_b4_cell = \ - self._replace_rlhist_multiline(source_raw, hlen_b4_cell) - more = False - except KeyboardInterrupt: - pass - except EOFError: - if self.autoindent: - self.rl_do_indent = False - if self.has_readline: - self.readline_startup_hook(None) - self.write('\n') - self.exit() - except bdb.BdbQuit: - warn('The Python debugger has exited with a BdbQuit exception.\n' - 'Because of how pdb handles the stack, it is impossible\n' - 'for IPython to properly format this particular exception.\n' - 'IPython will resume normal operation.') - except: - # exceptions here are VERY RARE, but they can be triggered - # asynchronously by signal handlers, for example. - self.showtraceback() - else: - try: - self.input_splitter.push(line) - more = self.input_splitter.push_accepts_more() - except SyntaxError: - # Run the code directly - run_cell takes care of displaying - # the exception. - more = False - if (self.SyntaxTB.last_syntax_error and - self.autoedit_syntax): - self.edit_syntax_error() - if not more: - source_raw = self.input_splitter.raw_reset() - self.run_cell(source_raw, store_history=True) - hlen_b4_cell = \ - self._replace_rlhist_multiline(source_raw, hlen_b4_cell) - - # Turn off the exit flag, so the mainloop can be restarted if desired - self.exit_now = False - - def raw_input(self, prompt=''): - """Write a prompt and read a line. - - The returned line does not include the trailing newline. - When the user enters the EOF key sequence, EOFError is raised. - - Parameters - ---------- - - prompt : str, optional - A string to be printed to prompt the user. - """ - # raw_input expects str, but we pass it unicode sometimes - prompt = py3compat.cast_bytes_py2(prompt) - - try: - line = py3compat.cast_unicode_py2(self.raw_input_original(prompt)) - except ValueError: - warn("\n********\nYou or a %run:ed script called sys.stdin.close()" - " or sys.stdout.close()!\nExiting IPython!\n") - self.ask_exit() - return "" - - # Try to be reasonably smart about not re-indenting pasted input more - # than necessary. We do this by trimming out the auto-indent initial - # spaces, if the user's actual input started itself with whitespace. - if self.autoindent: - if num_ini_spaces(line) > self.indent_current_nsp: - line = line[self.indent_current_nsp:] - self.indent_current_nsp = 0 - - return line - - #------------------------------------------------------------------------- - # Methods to support auto-editing of SyntaxErrors. - #------------------------------------------------------------------------- - - def edit_syntax_error(self): - """The bottom half of the syntax error handler called in the main loop. - - Loop until syntax error is fixed or user cancels. - """ - - while self.SyntaxTB.last_syntax_error: - # copy and clear last_syntax_error - err = self.SyntaxTB.clear_err_state() - if not self._should_recompile(err): - return - try: - # may set last_syntax_error again if a SyntaxError is raised - self.safe_execfile(err.filename,self.user_ns) - except: - self.showtraceback() - else: - try: - f = open(err.filename) - try: - # This should be inside a display_trap block and I - # think it is. - sys.displayhook(f.read()) - finally: - f.close() - except: - self.showtraceback() - - def _should_recompile(self,e): - """Utility routine for edit_syntax_error""" - - if e.filename in ('','','', - '','', - None): - - return False - try: - if (self.autoedit_syntax and - not self.ask_yes_no('Return to editor to correct syntax error? ' - '[Y/n] ','y')): - return False - except EOFError: - return False - - def int0(x): - try: - return int(x) - except TypeError: - return 0 - # always pass integer line and offset values to editor hook - try: - self.hooks.fix_error_editor(e.filename, - int0(e.lineno),int0(e.offset),e.msg) - except TryNext: - warn('Could not open editor') - return False - return True - - #------------------------------------------------------------------------- - # Things related to exiting - #------------------------------------------------------------------------- - - def ask_exit(self): - """ Ask the shell to exit. Can be overiden and used as a callback. """ - self.exit_now = True - - def exit(self): - """Handle interactive exit. - - This method calls the ask_exit callback.""" - if self.confirm_exit: - if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): - self.ask_exit() - else: - self.ask_exit() - - #------------------------------------------------------------------------- - # Things related to magics - #------------------------------------------------------------------------- - - def init_magics(self): - super(TerminalInteractiveShell, self).init_magics() - self.register_magics(TerminalMagics) - - def showindentationerror(self): - super(TerminalInteractiveShell, self).showindentationerror() - if not self.using_paste_magics: - print("If you want to paste code into IPython, try the " - "%paste and %cpaste magic functions.") - - -InteractiveShellABC.register(TerminalInteractiveShell) +class TerminalInteractiveShell(PromptToolkitShell): + def __init__(self, *args, **kwargs): + warn("This is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. " + "The terminal interface of this class now uses prompt_toolkit instead of readline.", + DeprecationWarning, stacklevel=2) + PromptToolkitShell.__init__(self, *args, **kwargs) diff --git a/IPython/terminal/magics.py b/IPython/terminal/magics.py new file mode 100644 index 00000000000..d5ea51f72b8 --- /dev/null +++ b/IPython/terminal/magics.py @@ -0,0 +1,207 @@ +"""Extra magics for terminal use.""" + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + +from __future__ import print_function + +from logging import error +import os +import sys + +from IPython.core.error import TryNext, UsageError +from IPython.core.inputsplitter import IPythonInputSplitter +from IPython.core.magic import Magics, magics_class, line_magic +from IPython.lib.clipboard import ClipboardEmpty +from IPython.utils.text import SList, strip_email_quotes +from IPython.utils import py3compat + +def get_pasted_lines(sentinel, l_input=py3compat.input, quiet=False): + """ Yield pasted lines until the user enters the given sentinel value. + """ + if not quiet: + print("Pasting code; enter '%s' alone on the line to stop or use Ctrl-D." \ + % sentinel) + prompt = ":" + else: + prompt = "" + while True: + try: + l = py3compat.str_to_unicode(l_input(prompt)) + if l == sentinel: + return + else: + yield l + except EOFError: + print('') + return + + +@magics_class +class TerminalMagics(Magics): + def __init__(self, shell): + super(TerminalMagics, self).__init__(shell) + self.input_splitter = IPythonInputSplitter() + + def store_or_execute(self, block, name): + """ Execute a block, or store it in a variable, per the user's request. + """ + if name: + # If storing it for further editing + self.shell.user_ns[name] = SList(block.splitlines()) + print("Block assigned to '%s'" % name) + else: + b = self.preclean_input(block) + self.shell.user_ns['pasted_block'] = b + self.shell.using_paste_magics = True + try: + self.shell.run_cell(b) + finally: + self.shell.using_paste_magics = False + + def preclean_input(self, block): + lines = block.splitlines() + while lines and not lines[0].strip(): + lines = lines[1:] + return strip_email_quotes('\n'.join(lines)) + + def rerun_pasted(self, name='pasted_block'): + """ Rerun a previously pasted command. + """ + b = self.shell.user_ns.get(name) + + # Sanity checks + if b is None: + raise UsageError('No previous pasted block available') + if not isinstance(b, py3compat.string_types): + raise UsageError( + "Variable 'pasted_block' is not a string, can't execute") + + print("Re-executing '%s...' (%d chars)"% (b.split('\n',1)[0], len(b))) + self.shell.run_cell(b) + + @line_magic + def autoindent(self, parameter_s = ''): + """Toggle autoindent on/off (if available).""" + + self.shell.set_autoindent() + print("Automatic indentation is:",['OFF','ON'][self.shell.autoindent]) + + @line_magic + def cpaste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + You must terminate the block with '--' (two minus-signs) or Ctrl-D + alone on the line. You can also provide your own sentinel with '%paste + -s %%' ('%%' is the new sentinel for this operation). + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%cpaste foo'. + This assigns the pasted block to variable 'foo' as string, without + dedenting or executing it (preceding >>> and + is still stripped) + + '%cpaste -r' re-executes the block previously entered by cpaste. + '%cpaste -q' suppresses any additional output messages. + + Do not be alarmed by garbled output on Windows (it's a readline bug). + Just press enter and type -- (and press enter again) and the block + will be what was just pasted. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + paste: automatically pull code from clipboard. + + Examples + -------- + :: + + In [8]: %cpaste + Pasting code; enter '--' alone on the line to stop. + :>>> a = ["world!", "Hello"] + :>>> print " ".join(sorted(a)) + :-- + Hello world! + """ + opts, name = self.parse_options(parameter_s, 'rqs:', mode='string') + if 'r' in opts: + self.rerun_pasted() + return + + quiet = ('q' in opts) + + sentinel = opts.get('s', u'--') + block = '\n'.join(get_pasted_lines(sentinel, quiet=quiet)) + self.store_or_execute(block, name) + + @line_magic + def paste(self, parameter_s=''): + """Paste & execute a pre-formatted code block from clipboard. + + The text is pulled directly from the clipboard without user + intervention and printed back on the screen before execution (unless + the -q flag is given to force quiet mode). + + The block is dedented prior to execution to enable execution of method + definitions. '>' and '+' characters at the beginning of a line are + ignored, to allow pasting directly from e-mails, diff files and + doctests (the '...' continuation prompt is also stripped). The + executed block is also assigned to variable named 'pasted_block' for + later editing with '%edit pasted_block'. + + You can also pass a variable name as an argument, e.g. '%paste foo'. + This assigns the pasted block to variable 'foo' as string, without + executing it (preceding >>> and + is still stripped). + + Options: + + -r: re-executes the block previously entered by cpaste. + + -q: quiet mode: do not echo the pasted text back to the terminal. + + IPython statements (magics, shell escapes) are not supported (yet). + + See also + -------- + cpaste: manually paste code into terminal until you mark its end. + """ + opts, name = self.parse_options(parameter_s, 'rq', mode='string') + if 'r' in opts: + self.rerun_pasted() + return + try: + block = self.shell.hooks.clipboard_get() + except TryNext as clipboard_exc: + message = getattr(clipboard_exc, 'args') + if message: + error(message[0]) + else: + error('Could not get text from the clipboard.') + return + except ClipboardEmpty: + raise UsageError("The clipboard appears to be empty") + + # By default, echo back to terminal unless quiet mode is requested + if 'q' not in opts: + write = self.shell.write + write(self.shell.pycolorize(block)) + if not block.endswith('\n'): + write('\n') + write("## -- End pasted text --\n") + + self.store_or_execute(block, name) + + # Class-level: add a '%cls' magic only on Windows + if sys.platform == 'win32': + @line_magic + def cls(self, s): + """Clear screen. + """ + os.system("cls") diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3c34d7c2fb8..8af3627f580 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -7,8 +7,8 @@ from warnings import warn from IPython.core.error import TryNext -from IPython.core.interactiveshell import InteractiveShell -from IPython.utils.py3compat import cast_unicode_py2, input +from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC +from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 @@ -27,11 +27,29 @@ from pygments.token import Token from .debugger import TerminalPdb, Pdb +from .magics import TerminalMagics from .pt_inputhooks import get_inputhook_func -from .interactiveshell import get_default_editor, TerminalMagics from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer + +def get_default_editor(): + try: + ed = os.environ['EDITOR'] + if not PY3: + ed = ed.decode() + return ed + except KeyError: + pass + except UnicodeError: + warn("$EDITOR environment variable is not pure ASCII. Using platform " + "default editor.") + + if os.name == 'posix': + return 'vi' # the only one guaranteed to be there! + else: + return 'notepad' # same in Windows! + _use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() class TerminalInteractiveShell(InteractiveShell): @@ -466,5 +484,7 @@ def switch_doctest_mode(self, mode): self._prompts_before = None +InteractiveShellABC.register(TerminalInteractiveShell) + if __name__ == '__main__': TerminalInteractiveShell.instance().interact() diff --git a/IPython/terminal/tests/test_interactivshell.py b/IPython/terminal/tests/test_interactivshell.py index 9437aff82a5..6eebf79ceea 100644 --- a/IPython/terminal/tests/test_interactivshell.py +++ b/IPython/terminal/tests/test_interactivshell.py @@ -1,10 +1,5 @@ # -*- coding: utf-8 -*- -"""Tests for the key interactiveshell module. - -Authors -------- -* Julian Taylor -""" +"""Tests for the TerminalInteractiveShell and related pieces.""" #----------------------------------------------------------------------------- # Copyright (C) 2011 The IPython Development Team # @@ -12,17 +7,10 @@ # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -# stdlib import sys -import types import unittest from IPython.core.inputtransformer import InputTransformer -from IPython.testing.decorators import skipif -from IPython.utils import py3compat from IPython.testing import tools as tt # Decorator for interaction loop tests ----------------------------------------- @@ -38,22 +26,22 @@ def __init__(self, testgen): self.ip = get_ipython() def __enter__(self): - self.orig_raw_input = self.ip.raw_input - self.ip.raw_input = self.fake_input + self.orig_prompt_for_code = self.ip.prompt_for_code + self.ip.prompt_for_code = self.fake_input return self def __exit__(self, etype, value, tb): - self.ip.raw_input = self.orig_raw_input + self.ip.prompt_for_code = self.orig_prompt_for_code - def fake_input(self, prompt): + def fake_input(self): try: return next(self.testgen) except StopIteration: - self.ip.exit_now = True + self.ip.keep_running = False return u'' except: self.exception = sys.exc_info() - self.ip.exit_now = True + self.ip.keep_running = False return u'' def mock_input(testfunc): @@ -65,7 +53,7 @@ def mock_input(testfunc): def test_method(self): testgen = testfunc(self) with mock_input_helper(testgen) as mih: - mih.ip.interact(display_banner=False) + mih.ip.interact() if mih.exception is not None: # Re-raise captured exception @@ -84,148 +72,6 @@ def rl_hist_entries(self, rl, n): """Get last n readline history entries as a list""" return [rl.get_history_item(rl.get_current_history_length() - x) for x in range(n - 1, -1, -1)] - - def test_runs_without_rl(self): - """Test that function does not throw without readline""" - ip = get_ipython() - ip.has_readline = False - ip.readline = None - ip._replace_rlhist_multiline(u'source', 0) - - @skipif(not get_ipython().has_readline, 'no readline') - def test_runs_without_remove_history_item(self): - """Test that function does not throw on windows without - remove_history_item""" - ip = get_ipython() - if hasattr(ip.readline, 'remove_history_item'): - del ip.readline.remove_history_item - ip._replace_rlhist_multiline(u'source', 0) - - @skipif(not get_ipython().has_readline, 'no readline') - @skipif(not hasattr(get_ipython().readline, 'remove_history_item'), - 'no remove_history_item') - def test_replace_multiline_hist_disabled(self): - """Test that multiline replace does nothing if disabled""" - ip = get_ipython() - ip.multiline_history = False - - ghist = [u'line1', u'line2'] - for h in ghist: - ip.readline.add_history(h) - hlen_b4_cell = ip.readline.get_current_history_length() - hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2', - hlen_b4_cell) - - self.assertEqual(ip.readline.get_current_history_length(), - hlen_b4_cell) - hist = self.rl_hist_entries(ip.readline, 2) - self.assertEqual(hist, ghist) - - @skipif(not get_ipython().has_readline, 'no readline') - @skipif(not hasattr(get_ipython().readline, 'remove_history_item'), - 'no remove_history_item') - def test_replace_multiline_hist_adds(self): - """Test that multiline replace function adds history""" - ip = get_ipython() - - hlen_b4_cell = ip.readline.get_current_history_length() - hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€', hlen_b4_cell) - - self.assertEqual(hlen_b4_cell, - ip.readline.get_current_history_length()) - - @skipif(not get_ipython().has_readline, 'no readline') - @skipif(not hasattr(get_ipython().readline, 'remove_history_item'), - 'no remove_history_item') - def test_replace_multiline_hist_keeps_history(self): - """Test that multiline replace does not delete history""" - ip = get_ipython() - ip.multiline_history = True - - ghist = [u'line1', u'line2'] - for h in ghist: - ip.readline.add_history(h) - - #start cell - hlen_b4_cell = ip.readline.get_current_history_length() - # nothing added to rl history, should do nothing - hlen_b4_cell = ip._replace_rlhist_multiline(u'sourc€\nsource2', - hlen_b4_cell) - - self.assertEqual(ip.readline.get_current_history_length(), - hlen_b4_cell) - hist = self.rl_hist_entries(ip.readline, 2) - self.assertEqual(hist, ghist) - - - @skipif(not get_ipython().has_readline, 'no readline') - @skipif(not hasattr(get_ipython().readline, 'remove_history_item'), - 'no remove_history_item') - def test_replace_multiline_hist_replaces_twice(self): - """Test that multiline entries are replaced twice""" - ip = get_ipython() - ip.multiline_history = True - - ip.readline.add_history(u'line0') - #start cell - hlen_b4_cell = ip.readline.get_current_history_length() - ip.readline.add_history('l€ne1') - ip.readline.add_history('line2') - #replace cell with single line - hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2', - hlen_b4_cell) - ip.readline.add_history('l€ne3') - ip.readline.add_history('line4') - #replace cell with single line - hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3\nline4', - hlen_b4_cell) - - self.assertEqual(ip.readline.get_current_history_length(), - hlen_b4_cell) - hist = self.rl_hist_entries(ip.readline, 3) - expected = [u'line0', u'l€ne1\nline2', u'l€ne3\nline4'] - # perform encoding, in case of casting due to ASCII locale - enc = sys.stdin.encoding or "utf-8" - expected = [ py3compat.unicode_to_str(e, enc) for e in expected ] - self.assertEqual(hist, expected) - - - @skipif(not get_ipython().has_readline, 'no readline') - @skipif(not hasattr(get_ipython().readline, 'remove_history_item'), - 'no remove_history_item') - def test_replace_multiline_hist_replaces_empty_line(self): - """Test that multiline history skips empty line cells""" - ip = get_ipython() - ip.multiline_history = True - - ip.readline.add_history(u'line0') - #start cell - hlen_b4_cell = ip.readline.get_current_history_length() - ip.readline.add_history('l€ne1') - ip.readline.add_history('line2') - hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne1\nline2', - hlen_b4_cell) - ip.readline.add_history('') - hlen_b4_cell = ip._replace_rlhist_multiline(u'', hlen_b4_cell) - ip.readline.add_history('l€ne3') - hlen_b4_cell = ip._replace_rlhist_multiline(u'l€ne3', hlen_b4_cell) - ip.readline.add_history(' ') - hlen_b4_cell = ip._replace_rlhist_multiline(' ', hlen_b4_cell) - ip.readline.add_history('\t') - ip.readline.add_history('\t ') - hlen_b4_cell = ip._replace_rlhist_multiline('\t', hlen_b4_cell) - ip.readline.add_history('line4') - hlen_b4_cell = ip._replace_rlhist_multiline(u'line4', hlen_b4_cell) - - self.assertEqual(ip.readline.get_current_history_length(), - hlen_b4_cell) - hist = self.rl_hist_entries(ip.readline, 4) - # expect no empty cells in history - expected = [u'line0', u'l€ne1\nline2', u'l€ne3', u'line4'] - # perform encoding, in case of casting due to ASCII locale - enc = sys.stdin.encoding or "utf-8" - expected = [ py3compat.unicode_to_str(e, enc) for e in expected ] - self.assertEqual(hist, expected) @mock_input def test_inputtransformer_syntaxerror(self): @@ -264,23 +110,6 @@ def reset(self): pass class TerminalMagicsTestCase(unittest.TestCase): - def test_paste_magics_message(self): - """Test that an IndentationError while using paste magics doesn't - trigger a message about paste magics and also the opposite.""" - - ip = get_ipython() - s = ('for a in range(5):\n' - 'print(a)') - - tm = ip.magics_manager.registry['TerminalMagics'] - with tt.AssertPrints("If you want to paste code into IPython, try the " - "%paste and %cpaste magic functions."): - ip.run_cell(s) - - with tt.AssertNotPrints("If you want to paste code into IPython, try the " - "%paste and %cpaste magic functions."): - tm.store_or_execute(s, name=None) - def test_paste_magics_blankline(self): """Test that code with a blank line doesn't get split (gh-3246).""" ip = get_ipython() From 54671e0844e44c951e95aa25e4b48d7b039b9571 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Thu, 2 Jun 2016 05:21:43 -0700 Subject: [PATCH 0382/4859] PR cleanup according to comments. --- IPython/core/completer.py | 2 +- IPython/utils/path.py | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index a969045f9fc..4928b9236e4 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -121,7 +121,7 @@ def protect_filename(s): if sys.platform == "win32": return '"' + s + '"' else: - return "".join("\\" + c if c in PROTECTABLES else c for c in s) + return "".join(("\\" + c if c in PROTECTABLES else c) for c in s) else: return s diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 1a6cd8e673a..1d2c9e87e37 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -73,6 +73,9 @@ def get_long_path_name(path): def unquote_filename(name, win32=(sys.platform=='win32')): """ On Windows, remove leading and trailing quotes from filenames. + + This function has been deprecated and should not be used any more: + unquoting is now taken care of by :func:`IPython.utils.process.arg_split`. """ warn("'unquote_filename' is deprecated", DeprecationWarning) if win32: @@ -83,7 +86,7 @@ def unquote_filename(name, win32=(sys.platform=='win32')): def compress_user(path): """Reverse of :func:`os.path.expanduser` - """ + """ path = py3compat.unicode_to_str(path, sys.getfilesystemencoding()) home = os.path.expanduser('~') if path.startswith(home): From 7aff37ddd845c353a28f5d247aa72a3d00ad0f7b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 2 Jun 2016 10:22:40 -0700 Subject: [PATCH 0383/4859] Don't update PTK layout if --simple-shell As there is no prompt_toolkit app instance. closes #9524 --- IPython/terminal/ptshell.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 3c34d7c2fb8..9ea1b373534 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -134,6 +134,7 @@ def init_term_title(self, change=None): toggle_set_term_title(False) def init_prompt_toolkit_cli(self): + self._app = None if self.simple_prompt: # Fall back to plain non-interactive output for tests. # This is very limited, and only accepts a single line. @@ -282,7 +283,8 @@ def _update_layout(self): Ask for a re computation of the application layout, if for example , some configuration options have changed. """ - self._app.layout = create_prompt_layout(**self._layout_options()) + if self._app: + self._app.layout = create_prompt_layout(**self._layout_options()) def prompt_for_code(self): document = self.pt_cli.run( From 2acc44a5b9c92768691e282198e3a705383d990f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 2 Jun 2016 10:29:21 -0700 Subject: [PATCH 0384/4859] Improve deprecation warning. Raise a warning no import, as it is common to have import that are unused. Also add since when this is deprecated. Close #9526 --- IPython/terminal/interactiveshell.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index a294a9d99ab..5c89ca0c64b 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -9,10 +9,13 @@ from IPython.utils.decorators import undoc from .ptshell import TerminalInteractiveShell as PromptToolkitShell +warn("Since IPython 5.0 `IPython.terminal.interactiveshell` is deprecated in favor of `IPython.terminal.ptshell`.", + DeprecationWarning) + @undoc class TerminalInteractiveShell(PromptToolkitShell): def __init__(self, *args, **kwargs): - warn("This is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. " + warn("Since IPython 5.0 this is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. " "The terminal interface of this class now uses prompt_toolkit instead of readline.", DeprecationWarning, stacklevel=2) PromptToolkitShell.__init__(self, *args, **kwargs) From 7ff24d006dfac05d327d5d78bd11e4b249859580 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 2 Jun 2016 22:17:30 +0100 Subject: [PATCH 0385/4859] Protect against completion machinery returning an empty string Closes gh-9492 --- IPython/terminal/ptutils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 4dafab19800..312ba1268d6 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -24,6 +24,10 @@ def get_completions(self, document, complete_event): ) start_pos = -len(used) for m in matches: + if not m: + # Guard against completion machinery giving us an empty string. + continue + m = unicodedata.normalize('NFC', m) # When the first character of the completion has a zero length, From ca22cbd663019b688799995e1e5e84e8bdb2aefb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 2 Jun 2016 11:55:42 -0700 Subject: [PATCH 0386/4859] Remove a few usage of PromptManager in example Make PromptClass Configurable. --- IPython/core/interactiveshell.py | 24 +++++++----------- IPython/core/magics/config.py | 1 - IPython/lib/lexers.py | 9 ++++--- IPython/terminal/ipapp.py | 4 +-- IPython/terminal/ptshell.py | 8 +++--- examples/Embedding/embed_class_long.py | 35 +++++++++++++++++--------- 6 files changed, 44 insertions(+), 37 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 1ade6880fea..99e4af12cbe 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -318,34 +318,25 @@ def _exiter_default(self): # deprecated prompt traits: prompt_in1 = Unicode('In [\\#]: ', - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in_template" + help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompt_in2 = Unicode(' .\\D.: ', - help="Deprecated, will be removed in IPython 5.0, use PromptManager.in2_template" + help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompt_out = Unicode('Out[\\#]: ', - help="Deprecated, will be removed in IPython 5.0, use PromptManager.out_template" + help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompts_pad_left = Bool(True, - help="Deprecated, will be removed in IPython 5.0, use PromptManager.justify" + help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." ).tag(config=True) @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left') def _prompt_trait_changed(self, change): - table = { - 'prompt_in1' : 'in_template', - 'prompt_in2' : 'in2_template', - 'prompt_out' : 'out_template', - 'prompts_pad_left' : 'justify', - } name = change['name'] - warn("InteractiveShell.{name} is deprecated, use PromptManager.{newname}".format( - name=name, newname=table[name]) + warn("InteractiveShell.{name} is deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly.".format( + name=name) ) # protect against weird cases where self.config may not exist: - if self.config is not None: - # propagate to corresponding PromptManager trait - setattr(self.config.PromptManager, table[name], change['new']) show_rewritten_input = Bool(True, help="Show rewritten input, e.g. for autocall." @@ -441,6 +432,9 @@ def __init__(self, ipython_dir=None, profile_dir=None, # This is where traits with a config_key argument are updated # from the values on config. super(InteractiveShell, self).__init__(**kwargs) + if 'PromptManager' in self.config: + warn('As of IPython 5.0 `PromptManager` config will have no effect' + ' and has been replaced by TerminalInteractiveShell.prompts_class') self.configurables = [self] # These are relatively independent and stateless diff --git a/IPython/core/magics/config.py b/IPython/core/magics/config.py index 4a17ba5d939..9505697791d 100644 --- a/IPython/core/magics/config.py +++ b/IPython/core/magics/config.py @@ -61,7 +61,6 @@ def config(self, s): PrefilterManager AliasManager IPCompleter - PromptManager DisplayFormatter To view what is configurable on a given class, just pass the class diff --git a/IPython/lib/lexers.py b/IPython/lib/lexers.py index f983a3ddc80..82cc1a74240 100644 --- a/IPython/lib/lexers.py +++ b/IPython/lib/lexers.py @@ -230,9 +230,12 @@ class IPythonConsoleLexer(Lexer): # The regexps used to determine what is input and what is output. # The default prompts for IPython are: # - # c.PromptManager.in_template = 'In [\#]: ' - # c.PromptManager.in2_template = ' .\D.: ' - # c.PromptManager.out_template = 'Out[\#]: ' + # in = 'In [#]: ' + # continuation = ' .D.: ' + # template = 'Out[#]: ' + # + # Where '#' is the 'prompt number' or 'execution count' and 'D' + # D is a number of dots matching the width of the execution count # in1_regex = r'In \[[0-9]+\]: ' in2_regex = r' \.\.+\.: ' diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index d0470a1026b..1d89a18f65b 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -123,9 +123,7 @@ def make_report(self,traceback): classic_config = Config() classic_config.InteractiveShell.cache_size = 0 classic_config.PlainTextFormatter.pprint = False -classic_config.PromptManager.in_template = '>>> ' -classic_config.PromptManager.in2_template = '... ' -classic_config.PromptManager.out_template = '' +classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts' classic_config.InteractiveShell.separate_in = '' classic_config.InteractiveShell.separate_out = '' classic_config.InteractiveShell.separate_out2 = '' diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index cf7fac1c062..dfeabcc24e1 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -11,7 +11,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 +from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone @@ -118,10 +118,12 @@ def _highlighting_style_changed(self, change): help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ).tag(config=True) + prompts_class = Type(Prompts, config=True, help='Class used to generate Prompt token for prompt_toolkit') + prompts = Instance(Prompts) def _prompts_default(self): - return Prompts(self) + return self.prompts_class(self) @observe('prompts') def _(self, change): @@ -301,7 +303,7 @@ def _update_layout(self): Ask for a re computation of the application layout, if for example , some configuration options have changed. """ - if self._app: + if getattr(self, '._app', None): self._app.layout = create_prompt_layout(**self._layout_options()) def prompt_for_code(self): diff --git a/examples/Embedding/embed_class_long.py b/examples/Embedding/embed_class_long.py index 3697251e9b3..cbe9acbd1e2 100755 --- a/examples/Embedding/embed_class_long.py +++ b/examples/Embedding/embed_class_long.py @@ -17,16 +17,34 @@ # Try running this code both at the command line and from inside IPython (with # %run example-embed.py) + +from IPython.terminal.prompts import Prompts, Token + +class CustomPrompt(Prompts): + + def in_prompt_tokens(self, cli=None): + + return [ + (Token.Prompt, 'In <'), + (Token.PromptNum, str(self.shell.execution_count)), + (Token.Prompt, '>: '), + ] + + def out_prompt_tokens(self): + return [ + (Token.OutPrompt, 'Out<'), + (Token.OutPromptNum, str(self.shell.execution_count)), + (Token.OutPrompt, '>: '), + ] + + from traitlets.config.loader import Config try: get_ipython except NameError: nested = 0 cfg = Config() - prompt_config = cfg.PromptManager - prompt_config.in_template = 'In <\\#>: ' - prompt_config.in2_template = ' .\\D.: ' - prompt_config.out_template = 'Out<\\#>: ' + cfg.TerminalInteractiveShell.prompts_class=CustomPrompt else: print("Running nested copies of IPython.") print("The prompts for the nested copy have been modified") @@ -45,13 +63,6 @@ exit_msg = 'Leaving Interpreter, back to program.') # Make a second instance, you can have as many as you want. -cfg2 = cfg.copy() -prompt_config = cfg2.PromptManager -prompt_config.in_template = 'In2<\\#>: ' -if not nested: - prompt_config.in_template = 'In2<\\#>: ' - prompt_config.in2_template = ' .\\D.: ' - prompt_config.out_template = 'Out<\\#>: ' ipshell2 = InteractiveShellEmbed(config=cfg, banner1 = 'Second IPython instance.') @@ -95,7 +106,7 @@ # This is how the global banner and exit_msg can be reset at any point -ipshell.banner = 'Entering interpreter - New Banner' +ipshell.banner2 = 'Entering interpreter - New Banner' ipshell.exit_msg = 'Leaving interpreter - New exit_msg' def foo(m): From a55f1f68ee2fac03b6402a244af88b839c6c4644 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 1 Jun 2016 11:19:15 -0700 Subject: [PATCH 0387/4859] Keep a reference to last execution result on the shell. In particular to know if the last command has failed. Note: Cannot keep a handle on the result object, or it does not get garbage collected until end of next run, which break some assumption about when __del__ is called. --- IPython/core/interactiveshell.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 7c20eed625c..3015048ed64 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -166,6 +166,10 @@ def raise_error(self): if self.error_in_exec is not None: raise self.error_in_exec + def __repr__(self): + return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s result=%s>' %\ + (self.__class__.__qualname__, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.result)) + class InteractiveShell(SingletonConfigurable): """An enhanced, interactive shell for Python.""" @@ -434,6 +438,8 @@ def profile(self): # Tracks any GUI loop loaded for pylab pylab_gui_select = None + last_execution_succeeded = Bool(True, help='Did last executed command succeeded') + def __init__(self, ipython_dir=None, profile_dir=None, user_module=None, user_ns=None, custom_exceptions=((), None), **kwargs): @@ -2607,6 +2613,7 @@ def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=Tr result = ExecutionResult() if (not raw_cell) or raw_cell.isspace(): + self.last_execution_succeeded = True return result if silent: @@ -2617,6 +2624,7 @@ def run_cell(self, raw_cell, store_history=False, silent=False, shell_futures=Tr def error_before_exec(value): result.error_before_exec = value + self.last_execution_succeeded = False return result self.events.trigger('pre_execute') @@ -2703,8 +2711,10 @@ def error_before_exec(value): # Execute the user code interactivity = "none" if silent else self.ast_node_interactivity - self.run_ast_nodes(code_ast.body, cell_name, + has_raised = self.run_ast_nodes(code_ast.body, cell_name, interactivity=interactivity, compiler=compiler, result=result) + + self.last_execution_succeeded = not has_raised # Reset this so later displayed values do not modify the # ExecutionResult From 195dd4086a6e62fc5425c4830874a29bdc176cbd Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 3 Jun 2016 11:47:15 -0700 Subject: [PATCH 0388/4859] Start writing up 5.0 changes. --- docs/source/whatsnew/development.rst | 3 -- .../pr/incompat-deleted-install_ext.rst | 1 - .../whatsnew/pr/incompat-event-triggering.rst | 7 --- docs/source/whatsnew/pr/incompat-readline.rst | 3 -- .../whatsnew/pr/incompat-remove-pydb.rst | 1 - docs/source/whatsnew/pr/simple_prompt.rst | 4 -- docs/source/whatsnew/version5.rst | 43 +++++++++++++++++++ 7 files changed, 43 insertions(+), 19 deletions(-) delete mode 100644 docs/source/whatsnew/pr/incompat-deleted-install_ext.rst delete mode 100644 docs/source/whatsnew/pr/incompat-event-triggering.rst delete mode 100644 docs/source/whatsnew/pr/incompat-readline.rst delete mode 100644 docs/source/whatsnew/pr/incompat-remove-pydb.rst delete mode 100644 docs/source/whatsnew/pr/simple_prompt.rst create mode 100644 docs/source/whatsnew/version5.rst diff --git a/docs/source/whatsnew/development.rst b/docs/source/whatsnew/development.rst index a07ee1ecb4d..3bdbc3e9e20 100644 --- a/docs/source/whatsnew/development.rst +++ b/docs/source/whatsnew/development.rst @@ -11,13 +11,10 @@ This document describes in-flight development work. `docs/source/whatsnew/pr` folder - - .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. Backwards incompatible changes ------------------------------ - .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. diff --git a/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst b/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst deleted file mode 100644 index 01b6d750497..00000000000 --- a/docs/source/whatsnew/pr/incompat-deleted-install_ext.rst +++ /dev/null @@ -1 +0,0 @@ -Deleted the install_ext magic function diff --git a/docs/source/whatsnew/pr/incompat-event-triggering.rst b/docs/source/whatsnew/pr/incompat-event-triggering.rst deleted file mode 100644 index 432af687df5..00000000000 --- a/docs/source/whatsnew/pr/incompat-event-triggering.rst +++ /dev/null @@ -1,7 +0,0 @@ -Update IPython event triggering to ensure callback registration and -unregistration only affects the set of callbacks the *next* time that event is -triggered. See :ghissue:`9447` and :ghpull:`9453`. - -This is a change to the existing semantics, wherein one callback registering a -second callback when triggered for an event would previously be invoked for -that same event. diff --git a/docs/source/whatsnew/pr/incompat-readline.rst b/docs/source/whatsnew/pr/incompat-readline.rst deleted file mode 100644 index 04272ce9db1..00000000000 --- a/docs/source/whatsnew/pr/incompat-readline.rst +++ /dev/null @@ -1,3 +0,0 @@ -IPython 5.0 now uses prompt_toolkit, so any setting that affects ``readline`` will -have no effect, and has likely been replaced by a configuration option on -IPython itself. diff --git a/docs/source/whatsnew/pr/incompat-remove-pydb.rst b/docs/source/whatsnew/pr/incompat-remove-pydb.rst deleted file mode 100644 index 4fe0fa5f5bf..00000000000 --- a/docs/source/whatsnew/pr/incompat-remove-pydb.rst +++ /dev/null @@ -1 +0,0 @@ -Integration with pydb has been removed since pydb development has been stopped since 2012, and pydb is not installable from PyPI diff --git a/docs/source/whatsnew/pr/simple_prompt.rst b/docs/source/whatsnew/pr/simple_prompt.rst deleted file mode 100644 index c9d3ec5e35e..00000000000 --- a/docs/source/whatsnew/pr/simple_prompt.rst +++ /dev/null @@ -1,4 +0,0 @@ -when using IPython as a subprocess, like for emacs inferior-shell, IPython can -be started with --simple-prompt flag, which will bypass the prompt_toolkit -input layer. In this mode completion, prompt color and many other features are -disabled. diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst new file mode 100644 index 00000000000..fe83f2707d0 --- /dev/null +++ b/docs/source/whatsnew/version5.rst @@ -0,0 +1,43 @@ +============ + 5.x Series +============ + +IPython 5.0 +=========== + +Released June, 2016 + +IPython 5.0 now uses `promt-toolkit` for the command line interface, thus +allowing real multi-line editing and syntactic coloration as you type. + + +When using IPython as a subprocess, like for emacs inferior-shell, IPython can +be started with --simple-prompt flag, which will bypass the prompt_toolkit +input layer. In this mode completion, prompt color and many other features are +disabled. + +Backwards incompatible changes +------------------------------ + + +The `install_ext magic` function which was deprecated since 4.0 have now been deleted. +You can still distribute and install extension as packages on PyPI. + +Update IPython event triggering to ensure callback registration and +unregistration only affects the set of callbacks the *next* time that event is +triggered. See :ghissue:`9447` and :ghpull:`9453`. + +This is a change to the existing semantics, wherein one callback registering a +second callback when triggered for an event would previously be invoked for +that same event. + +Integration with pydb has been removed since pydb development has been stopped +since 2012, and pydb is not installable from PyPI + +IPython 5.0 now uses prompt_toolkit, so any setting that affects ``readline`` will +have no effect, and has likely been replaced by a configuration option on +IPython itself. + +the `PromptManager` class have been removed, and the prompt machinery simplified. +See `TerminalINteractiveShell.prompts` configurable for how to setup your prompts. + From 171a542f269aac28483a639b34ee56938f87577f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 3 Jun 2016 11:58:16 -0700 Subject: [PATCH 0389/4859] release 5.0.0b1 --- IPython/core/release.py | 2 +- setup.cfg | 2 ++ tools/toollib.py | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 setup.cfg diff --git a/IPython/core/release.py b/IPython/core/release.py index a267d6bda83..10acc23ebdd 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'rc2' +_version_extra = 'b1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 00000000000..3c6e79cf31d --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal=1 diff --git a/tools/toollib.py b/tools/toollib.py index ad71bd063a3..aeb0223cf35 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('python setupegg.py bdist_wheel') # Utility functions def sh(cmd): From 1da789b5bdec1d39a7dc6befe32dc13248f57381 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 3 Jun 2016 14:09:26 -0700 Subject: [PATCH 0390/4859] Back to dev. --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 10acc23ebdd..378ad55a95c 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'b1' +# _version_extra = 'b1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 0a253274fc5b658d4ddc99be3d7e681fe86da204 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 3 Jun 2016 15:30:56 -0700 Subject: [PATCH 0391/4859] Do not assume stdin/err/out are tty Should close 9539 --- IPython/terminal/ptshell.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index dfeabcc24e1..169bffb21d5 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -50,7 +50,14 @@ def get_default_editor(): else: return 'notepad' # same in Windows! -_use_simple_prompt = 'IPY_TEST_SIMPLE_PROMPT' in os.environ or not sys.stdin.isatty() + +if sys.stdin and sys.stdout and sys.stderr: + _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty()) +else: + _is_tty = False + + +_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) class TerminalInteractiveShell(InteractiveShell): colors_force = True From aa2e250d80b93783eacd71bb64b7bdede864ab8b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 6 Jun 2016 11:16:43 -0700 Subject: [PATCH 0392/4859] Fix test on Python nightly --- IPython/core/tests/test_oinspect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index ed6c08a2b21..b4d69457ad9 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -270,7 +270,8 @@ def test_info(): nt.assert_equal(i['type_name'], 'type') expted_class = str(type(type)) # (Python 3) or nt.assert_equal(i['base_class'], expted_class) - nt.assert_equal(i['string_form'], "") + if sys.version_info > (3,): + nt.assert_regex(i['string_form'], "") fname = __file__ if fname.endswith(".pyc"): fname = fname[:-1] From 9e0c0aadc95919f34ec573239b87a5aaa0fc54c6 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Mon, 6 Jun 2016 14:19:39 -0700 Subject: [PATCH 0393/4859] Finish getting rid of unquote_filename... ... and associated tests. --- IPython/utils/path.py | 16 ++++++---------- IPython/utils/tests/test_path.py | 33 ++++++++++++++------------------ 2 files changed, 20 insertions(+), 29 deletions(-) diff --git a/IPython/utils/path.py b/IPython/utils/path.py index 1d2c9e87e37..cca7a8e1edc 100644 --- a/IPython/utils/path.py +++ b/IPython/utils/path.py @@ -77,7 +77,8 @@ def unquote_filename(name, win32=(sys.platform=='win32')): This function has been deprecated and should not be used any more: unquoting is now taken care of by :func:`IPython.utils.process.arg_split`. """ - warn("'unquote_filename' is deprecated", DeprecationWarning) + warn("'unquote_filename' is deprecated since IPython 5.0 and should not " + "be used anymore", DeprecationWarning) if win32: if name.startswith(("'", '"')) and name.endswith(("'", '"')): name = name[1:-1] @@ -98,18 +99,13 @@ def get_py_filename(name, force_win32=None): If the given name is not a file, it adds '.py' and searches again. Raises IOError with an informative message if the file isn't found. - - On Windows, apply Windows semantics to the filename. In particular, remove - any quoting that has been applied to it. This option can be forced for - testing purposes. """ name = os.path.expanduser(name) - if force_win32 is None: - win32 = (sys.platform == 'win32') - else: - win32 = force_win32 - name = unquote_filename(name, win32=win32) + 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) if not os.path.isfile(name) and not name.endswith('.py'): name += '.py' if os.path.isfile(name): diff --git a/IPython/utils/tests/test_path.py b/IPython/utils/tests/test_path.py index 2378e5134f9..4aba13fe287 100644 --- a/IPython/utils/tests/test_path.py +++ b/IPython/utils/tests/test_path.py @@ -305,25 +305,20 @@ def test_not_writable_ipdir(): @with_environment def test_get_py_filename(): os.chdir(TMP_TEST_DIR) - for win32 in (True, False): - with make_tempfile('foo.py'): - nt.assert_equal(path.get_py_filename('foo.py', force_win32=win32), 'foo.py') - nt.assert_equal(path.get_py_filename('foo', force_win32=win32), 'foo.py') - with make_tempfile('foo'): - nt.assert_equal(path.get_py_filename('foo', force_win32=win32), 'foo') - nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32) - nt.assert_raises(IOError, path.get_py_filename, 'foo', force_win32=win32) - nt.assert_raises(IOError, path.get_py_filename, 'foo.py', force_win32=win32) - true_fn = 'foo with spaces.py' - with make_tempfile(true_fn): - nt.assert_equal(path.get_py_filename('foo with spaces', force_win32=win32), true_fn) - nt.assert_equal(path.get_py_filename('foo with spaces.py', force_win32=win32), true_fn) - if win32: - nt.assert_equal(path.get_py_filename('"foo with spaces.py"', force_win32=True), true_fn) - nt.assert_equal(path.get_py_filename("'foo with spaces.py'", force_win32=True), true_fn) - else: - nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"', force_win32=False) - nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'", force_win32=False) + with make_tempfile('foo.py'): + nt.assert_equal(path.get_py_filename('foo.py'), 'foo.py') + nt.assert_equal(path.get_py_filename('foo'), 'foo.py') + with make_tempfile('foo'): + nt.assert_equal(path.get_py_filename('foo'), 'foo') + nt.assert_raises(IOError, path.get_py_filename, 'foo.py') + nt.assert_raises(IOError, path.get_py_filename, 'foo') + nt.assert_raises(IOError, path.get_py_filename, 'foo.py') + true_fn = 'foo with spaces.py' + with make_tempfile(true_fn): + nt.assert_equal(path.get_py_filename('foo with spaces'), true_fn) + nt.assert_equal(path.get_py_filename('foo with spaces.py'), true_fn) + nt.assert_raises(IOError, path.get_py_filename, '"foo with spaces.py"') + nt.assert_raises(IOError, path.get_py_filename, "'foo with spaces.py'") @onlyif_unicode_paths def test_unicode_in_filename(): From 4de715d00076238e701781723a3e693c0b4f721e Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Mon, 7 Mar 2016 19:59:34 -0500 Subject: [PATCH 0394/4859] Sphinxify docstrings --- IPython/core/interactiveshell.py | 14 +++++++++++++- IPython/core/oinspect.py | 9 +++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 91854a909c4..d987db3cf45 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -83,6 +83,18 @@ from logging import error import IPython.core.hooks +try: + import docrepr.sphinxify as sphx + + def docformat(doc): + dirname = tempfile.mkdtemp(prefix='ipython_sphinxify_') + return { + 'text/html': sphx.sphinxify(doc, dirname), + 'text/plain': doc + } +except: + docformat = None + #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -1528,7 +1540,7 @@ def _inspect(self, meth, oname, namespaces=None, **kw): info = self._object_find(oname, namespaces) if info.found: pmethod = getattr(self.inspector, meth) - formatter = format_screen if info.ismagic else None + formatter = format_screen if info.ismagic else docformat if meth == 'pdoc': pmethod(info.obj, oname, formatter) elif meth == 'pinfo': diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index d1a122e1bef..ed4970c3fa2 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -546,11 +546,16 @@ def _format_fields(self, fields, title_width=0): title = header((title+":").ljust(title_width)) out.append(cast_unicode(title) + cast_unicode(content)) return "\n".join(out) - + def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0): """Format an info dict as text""" - info = self.info(obj, oname=oname, formatter=formatter, + + # hack docstring rendering + info = self.info(obj, oname=oname, formatter=None, info=info, detail_level=detail_level) + if formatter: + return formatter(info["docstring"]) + displayfields = [] def add_fields(fields): for title, key in fields: From 9edc98d4009e698ffee885ed359c2b1626726e62 Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Mon, 4 Apr 2016 01:22:41 -0400 Subject: [PATCH 0395/4859] pinfo magic return mime bundle --- IPython/core/interactiveshell.py | 2 +- IPython/core/oinspect.py | 200 +++++++++++++++++----------- IPython/core/tests/test_oinspect.py | 4 +- 3 files changed, 124 insertions(+), 82 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index d987db3cf45..8d5c7437dbe 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1567,7 +1567,7 @@ def object_inspect_text(self, oname, detail_level=0): with self.builtin_trap: info = self._object_find(oname) if info.found: - return self.inspector._format_info(info.obj, oname, info=info, + return self.inspector._get_info(info.obj, oname, info=info, detail_level=detail_level ) else: diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index ed4970c3fa2..118dc2ce37b 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -112,7 +112,8 @@ def getdoc(obj): It also attempts to call a getdoc() method on the given object. This allows objects which provide their docstrings via non-standard mechanisms - (like Pyro proxies) to still be inspected by ipython's ? system.""" + (like Pyro proxies) to still be inspected by ipython's ? system. + """ # Allow objects to offer customized documentation via a getdoc method: try: ds = obj.getdoc() @@ -122,14 +123,13 @@ def getdoc(obj): # if we get extra info, we add it to the normal docstring. if isinstance(ds, string_types): return inspect.cleandoc(ds) - try: docstr = inspect.getdoc(obj) encoding = get_encoding(obj) return py3compat.cast_unicode(docstr, encoding=encoding) except Exception: # Harden against an inspect failure, which can occur with - # SWIG-wrapped extensions. + # extensions modules. raise return None @@ -366,10 +366,11 @@ def find_source_lines(obj): class Inspector(Colorable): + def __init__(self, color_table=InspectColors, code_color_table=PyColorize.ANSICodeColors, scheme='NoColor', - str_detail_level=0, + str_detail_level=0, parent=None, config=None): super(Inspector, self).__init__(parent=parent, config=config) self.color_table = color_table @@ -430,7 +431,7 @@ def pdef(self, obj, oname=''): # In Python 3, all classes are new-style, so they all have __init__. @skip_doctest_py3 - def pdoc(self,obj,oname='',formatter = None): + def pdoc(self, obj, oname='', formatter=None): """Print the docstring for any object. Optional: @@ -505,7 +506,7 @@ def psource(self, obj, oname=''): def pfile(self, obj, oname=''): """Show the whole file where an object was defined.""" - + lineno = find_source_lines(obj) if lineno is None: self.noinfo('file', oname) @@ -541,96 +542,128 @@ def _format_fields(self, fields, title_width=0): title_width = max(len(title) + 2 for title, _ in fields) for title, content in fields: if len(content.splitlines()) > 1: - title = header(title + ":") + "\n" + title = header(title + ':') + '\n' else: - title = header((title+":").ljust(title_width)) + title = header((title + ':').ljust(title_width)) out.append(cast_unicode(title) + cast_unicode(content)) return "\n".join(out) - def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0): - """Format an info dict as text""" + def _mime_format(self, text, formatter=None): + """Return a mime bundle representation of the input text. - # hack docstring rendering - info = self.info(obj, oname=oname, formatter=None, - info=info, detail_level=detail_level) - if formatter: - return formatter(info["docstring"]) - - displayfields = [] - def add_fields(fields): - for title, key in fields: - field = info[key] - if field is not None: - if key == "source": - displayfields.append((title, self.format(cast_unicode(field.rstrip())))) - else: - displayfields.append((title, field.rstrip())) + - if `formatter` is None, the returned mime bundle has + a `text/plain` field, with the input text. + a `text/html` field with a `
` tag containing the input text.
+
+        - if `formatter` is not None, it must be a callable transforming the
+          input text into a mime bundle. Default values for `text/plain` and
+          `text/html` representations are the ones described above.
+
+        Note:
+
+        Formatters returning strings are supported but this behavior is deprecated.
+
+        """
+        text = cast_unicode(text)
+        defaults = {
+            'text/plain': text,
+            'text/html': '
' + text + '
' + } + + if formatter is None: + return defaults + else: + formatted = formatter(text) + + if not isinstance(formatted, dict): + # Handle the deprecated behavior of a formatter returning + # a string instead of a mime bundle. + return { + 'text/plain': formatted, + 'text/html': '
' + formatted + '
' + } + + else: + return dict(defaults, **formatted) + + def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0): + """Retrieve an info dict and format it.""" + + info = self._info(obj, oname=oname, info=info, detail_level=detail_level) + + mime = { + 'text/plain': '', + 'text/html': '', + } + + def append_field(bundle, title, key, formatter=None): + field = info[key] + if field is not None: + formatted_field = self._mime_format(field, formatter) + bundle['text/plain'] += self.__head(title) + ':\n' + formatted_field['text/plain'] + '\n' + bundle['text/html'] += '

' + title + '

\n' + formatted_field['text/html'] + '\n' + + def code_formatter(text): + return { + 'text/plain': self.format(text), + 'text/html': '
' + text + '
' + } if info['isalias']: - add_fields([('Repr', "string_form")]) + append_field(mime, 'Repr', 'string_form') elif info['ismagic']: - if detail_level > 0 and info['source'] is not None: - add_fields([("Source", "source")]) + if detail_level > 0: + append_field(mime, 'Source', 'source', code_formatter) else: - add_fields([("Docstring", "docstring")]) - - add_fields([("File", "file"), - ]) + append_field(mime, 'Docstring', 'docstring', formatter) + append_field(mime, 'File', 'file') elif info['isclass'] or is_simple_callable(obj): # Functions, methods, classes - add_fields([("Signature", "definition"), - ("Init signature", "init_definition"), - ]) - if detail_level > 0 and info['source'] is not None: - add_fields([("Source", "source")]) + append_field(mime, 'Signature', 'definition', code_formatter) + append_field(mime, 'Init signature', 'init_definition', code_formatter) + if detail_level > 0: + append_field(mime, 'Source', 'source', code_formatter) else: - add_fields([("Docstring", "docstring"), - ("Init docstring", "init_docstring"), - ]) + append_field(mime, 'Docstring', 'docstring', formatter) + append_field(mime, 'Init docstring', 'init_docstring', formatter) - add_fields([('File', 'file'), - ('Type', 'type_name'), - ]) + append_field(mime, 'File', 'file') + append_field(mime, 'Type', 'type_name') else: # General Python objects - add_fields([("Type", "type_name")]) + append_field(mime, 'Type', 'type_name') # Base class for old-style instances if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']: - displayfields.append(("Base Class", info['base_class'].rstrip())) + append_field(mime, 'Base Class', 'base_class') - add_fields([("String form", "string_form")]) + append_field(mime, 'String form', 'string_form') # Namespace if info['namespace'] != 'Interactive': - displayfields.append(("Namespace", info['namespace'].rstrip())) + append_field(mime, 'Namespace', 'namespace') - add_fields([("Length", "length"), - ("File", "file"), - ("Signature", "definition"), - ]) + append_field(mime, 'Length', 'length') + append_field(mime, 'File', 'file'), + append_field(mime, 'Signature', 'definition', code_formatter) # Source or docstring, depending on detail level and whether # source found. - if detail_level > 0 and info['source'] is not None: - displayfields.append(("Source", - self.format(cast_unicode(info['source'])))) - elif info['docstring'] is not None: - displayfields.append(("Docstring", info["docstring"])) - - add_fields([("Class docstring", "class_docstring"), - ("Init docstring", "init_docstring"), - ("Call signature", "call_def"), - ("Call docstring", "call_docstring")]) - - if displayfields: - return self._format_fields(displayfields) - else: - return u'' - + if detail_level > 0: + append_field(mime, 'Source', 'source', code_formatter) + else: + append_field(mime, 'Docstring', 'docstring', formatter) + + 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 mime + def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): """Show detailed information about an object. @@ -638,26 +671,37 @@ def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): - oname: name of the variable pointing to the object. - - formatter: special formatter for docstrings (see pdoc) + - formatter: callable (optional) + A special formatter for docstrings. + + The formatter is a callable that takes a string as an input + and returns either a formatted string or a mime type bundle + in the form of a dictionnary. + + Although the support of custom formatter returning a string + instead of a mime type bundle is deprecated. - info: a structure with some information fields which may have been precomputed already. - detail_level: if set to 1, more information is given. """ - text = self._format_info(obj, oname, formatter, info, detail_level) - if text: - page.page(text) - + info = self._get_info(obj, oname, formatter, info, detail_level) + if info: + page.page(info) + def info(self, obj, oname='', formatter=None, info=None, detail_level=0): + """DEPRECATED. Compute a dict with detailed information about an object. + """ + return self._info(obj, oname=oname, info=info, detail_level=detail_level) + + def _info(self, obj, oname='', info=None, detail_level=0): """Compute a dict with detailed information about an object. Optional arguments: - oname: name of the variable pointing to the object. - - formatter: special formatter for docstrings (see pdoc) - - info: a structure with some information fields which may have been precomputed already. @@ -690,14 +734,12 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): ds = getdoc(obj) if ds is None: ds = '' - if formatter is not None: - ds = formatter(ds) # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) string_max = 200 # max size of strings to show (snipped if longer) - shalf = int((string_max -5)/2) + shalf = int((string_max - 5) / 2) if ismagic: obj_type_name = 'Magic function' @@ -798,7 +840,7 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): # reconstruct the function definition and print it: defln = self._getdef(obj, oname) if defln: - out['definition'] = self.format(defln) + out['definition'] = defln # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In @@ -832,7 +874,7 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) if call_def: - call_def = self.format(call_def) + call_def = call_def # it may never be the case that call def and definition differ, # but don't include the same signature twice if call_def != out.get('definition'): diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index ed6c08a2b21..f1d1bd6eaf3 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -340,13 +340,13 @@ def test_calldef_none(): @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)\n") + nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)") def test_getdoc(): class A(object): """standard docstring""" pass - + class B(object): """standard docstring""" def getdoc(self): From 9ba6f4878534de6b698fe499f2cb0eaeacc5bbd3 Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Mon, 4 Apr 2016 18:20:28 -0400 Subject: [PATCH 0396/4859] Use TemporaryDirectory context manager --- IPython/core/interactiveshell.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 8d5c7437dbe..9d0e585b7ad 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -75,6 +75,7 @@ from IPython.utils.syspathcontext import prepended_to_syspath from IPython.utils.text import (format_screen, LSString, SList, DollarFormatter) +from IPython.utils.tempdir import TemporaryDirectory from traitlets import ( Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type, observe, default, @@ -87,11 +88,11 @@ import docrepr.sphinxify as sphx def docformat(doc): - dirname = tempfile.mkdtemp(prefix='ipython_sphinxify_') - return { - 'text/html': sphx.sphinxify(doc, dirname), - 'text/plain': doc - } + with TemporaryDirectory() as dirname: + return { + 'text/html': sphx.sphinxify(doc, dirname), + 'text/plain': doc + } except: docformat = None From 3c1ce318117e6b2630f7c5d2379e6d269f98a124 Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Mon, 4 Apr 2016 22:01:15 -0400 Subject: [PATCH 0397/4859] Add deprecation warning --- IPython/core/oinspect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 118dc2ce37b..fb6ab06d2a5 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -17,6 +17,7 @@ # stdlib modules import inspect import linecache +import warnings import os from textwrap import dedent import types @@ -693,6 +694,8 @@ def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """DEPRECATED. Compute a dict with detailed information about an object. """ + warnings.warn('Inspector.info is deprecated as of IPython 5.0', + DeprecationWarning, stacklevel=2) return self._info(obj, oname=oname, info=info, detail_level=detail_level) def _info(self, obj, oname='', info=None, detail_level=0): From df192f12d281893d5a9c75e17f3df52bf75c3654 Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Mon, 4 Apr 2016 22:19:59 -0400 Subject: [PATCH 0398/4859] page_dumb mime bundle --- IPython/core/page.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/IPython/core/page.py b/IPython/core/page.py index ec2e07744e0..6d213c9f29d 100644 --- a/IPython/core/page.py +++ b/IPython/core/page.py @@ -38,7 +38,7 @@ def display_page(strng, start=0, screen_lines=25): else: if start: strng = u'\n'.join(strng.splitlines()[start:]) - data = {'text/plain': strng} + data = { 'text/plain': strng } display(data, raw=True) @@ -56,8 +56,10 @@ def page_dumb(strng, start=0, screen_lines=25): """Very dumb 'pager' in Python, for when nothing else works. Only moves forward, same interface as page(), except for pager_cmd and - mode.""" - + mode. + """ + if isinstance(strng, dict): + strng = strng.get('text/plain', '') out_ln = strng.splitlines()[start:] screens = chop(out_ln,screen_lines-1) if len(screens) == 1: From 3f12bc050392d3b07c7c77d573d30f3ce7264a96 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 8 Apr 2016 11:45:24 -0700 Subject: [PATCH 0399/4859] Fix test mimebundle paging Test replace paging by print. --- IPython/testing/globalipapp.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/testing/globalipapp.py b/IPython/testing/globalipapp.py index 6214edbb0ca..635921a2843 100644 --- a/IPython/testing/globalipapp.py +++ b/IPython/testing/globalipapp.py @@ -20,7 +20,6 @@ #----------------------------------------------------------------------------- # stdlib -import os import sys # our own @@ -141,6 +140,8 @@ def start_ipython(): # Override paging, so we don't require user interaction during the tests. def nopage(strng, start=0, screen_lines=0, pager_cmd=None): + if isinstance(strng, dict): + strng = strng.get('text/plain', '') print(strng) page.orig_page = page.pager_page From 0395ccf9181e544c35c64027c88dba49be875953 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 8 Apr 2016 12:16:33 -0700 Subject: [PATCH 0400/4859] 'Simplify affectation' --- IPython/core/oinspect.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index fb6ab06d2a5..289efbcc3d0 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -876,12 +876,10 @@ def _info(self, obj, oname='', info=None, detail_level=0): # Call form docstring for callable instances if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) - if call_def: - call_def = call_def + if call_def and (call_def != out.get('definition')): # it may never be the case that call def and definition differ, # but don't include the same signature twice - if call_def != out.get('definition'): - out['call_def'] = call_def + out['call_def'] = call_def call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds == _func_call_docstring: From 9412553b1d12e84ea7155044e775432bbee164b7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 8 Apr 2016 13:14:23 -0700 Subject: [PATCH 0401/4859] Deprecate only if not None passed as formatter. --- IPython/core/oinspect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 289efbcc3d0..5045e23bddb 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -694,7 +694,8 @@ def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """DEPRECATED. Compute a dict with detailed information about an object. """ - warnings.warn('Inspector.info is deprecated as of IPython 5.0', + if formatter is not None: + warnings.warn('Inspector.info(formatter) keyword is deprecated as of IPython 5.0 and will have no effects.', DeprecationWarning, stacklevel=2) return self._info(obj, oname=oname, info=info, detail_level=detail_level) From cdc3d09f1ea44e97bf5818d34e7a0d0239d1b796 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 8 Apr 2016 13:21:36 -0700 Subject: [PATCH 0402/4859] Catch only ImportError --- IPython/core/interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 9d0e585b7ad..d9cde7a02af 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -93,7 +93,7 @@ def docformat(doc): 'text/html': sphx.sphinxify(doc, dirname), 'text/plain': doc } -except: +except ImportError: docformat = None #----------------------------------------------------------------------------- From d73ed524b737ffc767119ddcf77558ae07b84969 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 8 Apr 2016 13:32:55 -0700 Subject: [PATCH 0403/4859] Reword deprecation warning. --- IPython/core/oinspect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 5045e23bddb..d4a019dcb83 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -695,7 +695,8 @@ def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """DEPRECATED. Compute a dict with detailed information about an object. """ if formatter is not None: - warnings.warn('Inspector.info(formatter) keyword is deprecated as of IPython 5.0 and will have no effects.', + warnings.warn('The `formatter` keyword argument to `Inspector.info`' + 'is deprecated as of IPython 5.0 and will have no effects.', DeprecationWarning, stacklevel=2) return self._info(obj, oname=oname, info=info, detail_level=detail_level) From f9eac25d456c03280efa8c1edf9ebbda7476fd74 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 15 Apr 2016 13:36:59 +0200 Subject: [PATCH 0404/4859] rehighlight in html --- IPython/core/oinspect.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index d4a019dcb83..3556ac5e738 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -365,6 +365,13 @@ def find_source_lines(obj): return lineno +from pygments import highlight +from pygments.lexers import PythonLexer +from pygments.formatters import HtmlFormatter + +def pylight(code): + return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True)) + class Inspector(Colorable): @@ -470,7 +477,7 @@ def pdoc(self, obj, oname='', formatter=None): lines = [] ds = getdoc(obj) if formatter: - ds = formatter(ds) + ds = formatter(ds).get('plain/text', ds) if ds: lines.append(head("Class docstring:")) lines.append(indent(ds)) @@ -607,7 +614,7 @@ def append_field(bundle, title, key, formatter=None): def code_formatter(text): return { 'text/plain': self.format(text), - 'text/html': '
' + text + '
' + 'text/html': pylight(text) } if info['isalias']: From 365c6105229872598636a032978af0f9c9b6dfa3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 6 Jun 2016 12:32:36 -0700 Subject: [PATCH 0405/4859] Use enter to select completion, but do not submit code. 1/2 fix for #9543 --- IPython/terminal/ptshell.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 169bffb21d5..0f8bcf54555 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -181,6 +181,12 @@ def prompt(): def _(event): b = event.current_buffer d = b.document + + if b.complete_state: + cs = b.complete_state + b.apply_completion(cs.current_completion) + return + if not (d.on_last_line or d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()): b.newline() From d95a1efb3d2768e3c434b97b61feaa7aa110484d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 1 Jun 2016 13:56:57 -0700 Subject: [PATCH 0406/4859] Don't compute length of ZeroWidthTokens. This simplify subclassing of prompt that inject escape sequences for prompt toolkit. --- IPython/terminal/prompts.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/prompts.py b/IPython/terminal/prompts.py index 95471286846..732a711ac1e 100644 --- a/IPython/terminal/prompts.py +++ b/IPython/terminal/prompts.py @@ -6,6 +6,8 @@ from IPython.core.displayhook import DisplayHook +from prompt_toolkit.layout.utils import token_list_width + class Prompts(object): def __init__(self, shell): self.shell = shell @@ -18,8 +20,7 @@ def in_prompt_tokens(self, cli=None): ] def _width(self): - in_tokens = self.in_prompt_tokens() - return sum(len(s) for (t, s) in in_tokens) + return token_list_width(self.in_prompt_tokens()) def continuation_prompt_tokens(self, cli=None, width=None): if width is None: From 14d40a4db875797e82959327f25ad58e21829427 Mon Sep 17 00:00:00 2001 From: Sylvain Corlay Date: Tue, 7 Jun 2016 00:38:41 -0400 Subject: [PATCH 0407/4859] Add provisial config attribute to disable html display by default --- IPython/core/interactiveshell.py | 36 ++++++++++++++++++++++---------- IPython/core/oinspect.py | 7 ++++--- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index d9cde7a02af..aca1a549ac4 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -73,8 +73,7 @@ with_metaclass, iteritems) from IPython.utils.strdispatch import StrDispatch from IPython.utils.syspathcontext import prepended_to_syspath -from IPython.utils.text import (format_screen, LSString, SList, - DollarFormatter) +from IPython.utils.text import format_screen, LSString, SList, DollarFormatter from IPython.utils.tempdir import TemporaryDirectory from traitlets import ( Integer, Bool, CaselessStrEnum, Enum, List, Dict, Unicode, Instance, Type, @@ -87,14 +86,14 @@ try: import docrepr.sphinxify as sphx - def docformat(doc): + def sphinxify(doc): with TemporaryDirectory() as dirname: return { 'text/html': sphx.sphinxify(doc, dirname), 'text/plain': doc } except ImportError: - docformat = None + sphinxify = None #----------------------------------------------------------------------------- # Globals @@ -278,6 +277,16 @@ class InteractiveShell(SingletonConfigurable): display_formatter = Instance(DisplayFormatter, allow_none=True) displayhook_class = Type(DisplayHook) display_pub_class = Type(DisplayPublisher) + sphinxify_docstring = Bool(False, help= + """ + Enables rich html representation of docstrings. (This requires the + docrepr module). + """).tag(config=True) + enable_html_pager = Bool(False, help= + """ + (Provisional API) enables html representation in mime bundles sent + to pagers. + """).tag(config=True) data_pub_class = None exit_now = Bool(False) @@ -294,12 +303,12 @@ def _exiter_default(self): # is ready to be executed. input_splitter = Instance('IPython.core.inputsplitter.IPythonInputSplitter', (), {'line_input_checker': True}) - + # This InputSplitter instance is used to transform completed cells before # running them. It allows cell magics to contain blank lines. input_transformer_manager = Instance('IPython.core.inputsplitter.IPythonInputSplitter', (), {'line_input_checker': False}) - + logstart = Bool(False, help= """ Start logging to the default log file in overwrite mode. @@ -354,11 +363,11 @@ def _prompt_trait_changed(self, change): name=name) ) # protect against weird cases where self.config may not exist: - + show_rewritten_input = Bool(True, help="Show rewritten input, e.g. for autocall." ).tag(config=True) - + quiet = Bool(False).tag(config=True) history_length = Integer(10000, @@ -1371,7 +1380,7 @@ def push(self, variables, interactive=True): user_ns_hidden.pop(name, None) else: user_ns_hidden.update(vdict) - + def drop_by_id(self, variables): """Remove a dict of variables from the user namespace, if they are the same as the values in the dictionary. @@ -1537,15 +1546,20 @@ def _object_find(self, oname, namespaces=None): def _inspect(self, meth, oname, namespaces=None, **kw): """Generic interface to the inspector system. - This function is meant to be called by pdef, pdoc & friends.""" + This function is meant to be called by pdef, pdoc & friends. + """ info = self._object_find(oname, namespaces) + docformat = sphinxify if self.sphinxify_docstring else None if info.found: pmethod = getattr(self.inspector, meth) + # TODO: only apply format_screen to the plain/text repr of the mime + # bundle. formatter = format_screen if info.ismagic else docformat if meth == 'pdoc': pmethod(info.obj, oname, formatter) elif meth == 'pinfo': - pmethod(info.obj, oname, formatter, info, **kw) + pmethod(info.obj, oname, formatter, info, + enable_html_pager=self.enable_html_pager, **kw) else: pmethod(info.obj, oname) else: diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 3556ac5e738..88093af0c6f 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -672,7 +672,7 @@ def code_formatter(text): return mime - def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): + def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True): """Show detailed information about an object. Optional arguments: @@ -695,8 +695,9 @@ def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0): - detail_level: if set to 1, more information is given. """ info = self._get_info(obj, oname, formatter, info, detail_level) - if info: - page.page(info) + if not enable_html_pager: + del info['text/html'] + page.page(info) def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """DEPRECATED. Compute a dict with detailed information about an object. From 2b41af28e9168d439986eb08d3d031955019952c Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 7 Jun 2016 11:23:03 +0200 Subject: [PATCH 0408/4859] allow failures on nightly Python while it's useful to run the tests, failures on Python nightly are likely to be not our bugs, and shouldn't generally be considered CI failures. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 12aedd744f1..b7e3d121138 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,3 +20,7 @@ after_success: - cp /tmp/ipy_coverage.xml ./ - cp /tmp/.coverage ./ - codecov + +matrix: + allow_failures: + python: nightly From 2b1dc589f862ad18277283c434cccaa7efcfde9c Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 12:34:10 +0200 Subject: [PATCH 0409/4859] Fix code/code-block errors --- docs/source/interactive/reference.rst | 54 ++++++++++++++------------- docs/source/interactive/shell.rst | 10 ++--- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 492c8830eda..eb69294a086 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -19,7 +19,7 @@ file and ignore your configuration setup. Please note that some of the configuration options are not available at the command line, simply because they are not practical here. Look into -your configuration files for details on those. There are separate configuration +your configuration files for details on those. There are separate configuration files for each profile, and the files look like :file:`ipython_config.py` or :file:`ipython_config_{frontendname}.py`. Profile directories look like :file:`profile_{profilename}` and are typically installed in the :envvar:`IPYTHONDIR` directory, @@ -95,17 +95,17 @@ the same name:: /home/fperez The following uses the builtin :magic:`timeit` in cell mode:: - + In [10]: %%timeit x = range(10000) ...: min(x) ...: max(x) - ...: + ...: 1000 loops, best of 3: 438 us per loop In this case, ``x = range(10000)`` is called as the line argument, and the block with ``min(x)`` and ``max(x)`` is called as the cell body. The :magic:`timeit` magic receives both. - + If you have 'automagic' enabled (as it is by default), you don't need to type in the single ``%`` explicitly for line magics; IPython will scan its internal list of magic functions and call one if it exists. With automagic on you can @@ -116,7 +116,7 @@ then just type ``cd mydir`` to go to directory 'mydir':: Cell magics *always* require an explicit ``%%`` prefix, automagic calling only works for line magics. - + The automagic system has the lowest possible precedence in name searches, so you can freely use variables with the same names as magic commands. If a magic command is 'shadowed' by a variable, you will need the explicit ``%`` prefix to @@ -146,7 +146,7 @@ use it: /home/fperez/ipython Line magics, if they return a value, can be assigned to a variable using the syntax -``l = %sx ls`` (which in this particular case returns the result of `ls` as a python list). +``l = %sx ls`` (which in this particular case returns the result of `ls` as a python list). See :ref:`below ` for more information. Type ``%magic`` for more information, including a list of all available magic @@ -326,9 +326,9 @@ You can assign the result of a system command to a Python variable with the syntax ``myfiles = !ls``. Similarly, the result of a magic (as long as it returns a value) can be assigned to a variable. For example, the syntax ``myfiles = %sx ls`` is equivalent to the above system command example (the :magic:`sx` magic runs a shell command -and captures the output). Each of these gets machine -readable output from stdout (e.g. without colours), and splits on newlines. To -explicitly get this sort of output without assigning to a variable, use two +and captures the output). Each of these gets machine +readable output from stdout (e.g. without colours), and splits on newlines. To +explicitly get this sort of output without assigning to a variable, use two exclamation marks (``!!ls``) or the :magic:`sx` magic command without an assignment. (However, ``!!`` commands cannot be assigned to a variable.) @@ -340,8 +340,8 @@ See :ref:`string_lists` for details. IPython also allows you to expand the value of python variables when making system calls. Wrap variables or expressions in {braces}:: - In [1]: pyvar = 'Hello world' - In [2]: !echo "A python variable: {pyvar}" + In [1]: pyvar = 'Hello world' + In [2]: !echo "A python variable: {pyvar}" A python variable: Hello world In [3]: import math In [4]: x = 8 @@ -350,7 +350,7 @@ making system calls. Wrap variables or expressions in {braces}:: For simple cases, you can alternatively prepend $ to a variable name:: - In [6]: !echo $sys.argv + In [6]: !echo $sys.argv [/home/fperez/usr/bin/ipython] In [7]: !echo "A system variable: $$HOME" # Use $$ for literal $ A system variable: /home/fperez @@ -376,7 +376,7 @@ replaced by a positional parameter to the call to %parts:: In [1]: %alias parts echo first %s second %s In [2]: parts A B first A second B - In [3]: parts A + In [3]: parts A ERROR: Alias requires 2 arguments, 1 given. If called with no parameters, :magic:`alias` prints the table of currently @@ -420,8 +420,8 @@ Input caching system -------------------- IPython offers numbered prompts (In/Out) with input and output caching -(also referred to as 'input history'). All input is saved and can be -retrieved as variables (besides the usual arrow key recall), in +(also referred to as 'input history'). All input is saved and can be +retrieved as variables (besides the usual arrow key recall), in addition to the :magic:`rep` magic command that brings a history entry up for editing on the next command line. @@ -451,7 +451,7 @@ processing). Type %macro? for more details on the macro system. A history function :magic:`history` allows you to see any part of your input history by printing a range of the _i variables. -You can also search ('grep') through your history by typing +You can also search ('grep') through your history by typing ``%hist -g somestring``. This is handy for searching for URLs, IP addresses, etc. You can bring history entries listed by '%hist -g' up for editing with the %recall command, or run them immediately with :magic:`rerun`. @@ -537,8 +537,8 @@ will confuse IPython):: but this will work:: - In [5]: /zip (1,2,3),(4,5,6) - ------> zip ((1,2,3),(4,5,6)) + In [5]: /zip (1,2,3),(4,5,6) + ------> zip ((1,2,3),(4,5,6)) Out[5]: [(1, 4), (2, 5), (3, 6)] IPython tells you that it has altered your command line by displaying @@ -648,7 +648,7 @@ them separately, for example with different options for data presentation. If you close and open the same instance multiple times, its prompt counters simply continue from each execution to the next. -Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed` +Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed` module for more details on the use of this system. The following sample file illustrating how to use the embedding @@ -682,12 +682,13 @@ For more information on the use of the pdb debugger, see :ref:`debugger-commands in the Python documentation. IPython extends the debugger with a few useful additions, like coloring of -tracebacks. The debugger will adopt the color scheme selected for IPython. +tracebacks. The debugger will adopt the color scheme selected for IPython. The ``where`` command has also been extended to take as argument the number of context line to show. This allows to a many line of context on shallow stack trace: .. code:: + In [5]: def foo(x): ...: 1 ...: 2 @@ -697,7 +698,7 @@ context line to show. This allows to a many line of context on shallow stack tra ...: 6 ...: 7 ...: - + In[6]: foo(1) # ... ipdb> where 8 @@ -728,6 +729,7 @@ context line to show. This allows to a many line of context on shallow stack tra And less context on shallower Stack Trace: .. code:: + ipdb> where 1 (1)() ----> 1 foo(7) @@ -797,7 +799,7 @@ standard Python tutorial:: In [4]: >>> while b < 10: ...: ... print(b) ...: ... a, b = b, a+b - ...: + ...: 1 1 2 @@ -810,7 +812,7 @@ And pasting from IPython sessions works equally well:: In [1]: In [5]: def f(x): ...: ...: "A simple function" ...: ...: return x**2 - ...: ...: + ...: ...: In [2]: f(3) Out[2]: 9 @@ -832,7 +834,7 @@ 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 +* There is a developer API in :mod:`IPython.lib.inputhook` for customizing all of these things. For users, enabling GUI event loop integration is simple. You simple use the @@ -862,7 +864,7 @@ form of a library, these capabilities are exposed in library form in the 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 +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. @@ -918,7 +920,7 @@ neither v2 PyQt nor PySide work. Note that this means for ETS 4 to work with PyQt4, ``QT_API`` *must* be set to work with IPython's qt integration, because otherwise PyQt4 will be loaded in an incompatible mode. - + It also means that you must *not* have ``QT_API`` set if you want to use ``--gui=qt`` with code that requires PyQt4 API v1. diff --git a/docs/source/interactive/shell.rst b/docs/source/interactive/shell.rst index 5724efbf252..be3999d8ba4 100644 --- a/docs/source/interactive/shell.rst +++ b/docs/source/interactive/shell.rst @@ -74,12 +74,12 @@ The class can implement optional methods for each of the available prompt types: - ``rewrite_prompt_tokens(self)`` - ``out_prompt_tokens(self)`` -Each of these methods should return a list of `(TokenType, Token)` pairs. See documentation of `prompt_toolkit` and/or `Pygments`. +Each of these methods should return a list of `(TokenType, Token)` pairs. See documentation of `prompt_toolkit` and/or `Pygments`. Here is an example of Prompt class that will insert the current working directory in front of a prompt: -.. codeblock:: python +.. code-block:: python from IPython.terminal.prompts import Prompts, Token import os @@ -92,7 +92,7 @@ Here is an example of Prompt class that will insert the current working director To set the new prompt, assign it to the `prompts` attribute of the IPython shell: -.. codeblock:: python +.. code-block:: python In[2]: ip = get_ipython() ...: ip.prompts = MyPrompt(ip) @@ -101,7 +101,7 @@ To set the new prompt, assign it to the `prompts` attribute of the IPython shell See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an -extensions that customise prompts. +extensions that customise prompts. Read more about the :ref:`configuration system ` for details @@ -225,7 +225,7 @@ First, capture output of "hg status":: 11: build\bdist.win32\winexe\temp\_hashlib.py 12: build\bdist.win32\winexe\temp\_socket.py -Now we can just remove these files by doing 'rm $junk.s'. +Now we can just remove these files by doing 'rm $junk.s'. The .s, .n, .p properties ------------------------- From 0797d85f76ff4a7c51235e70cabcd13b20ae0cb0 Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 13:09:53 +0200 Subject: [PATCH 0410/4859] Various small fixes to docs --- docs/source/interactive/index.rst | 1 + .../interactive/python-ipython-diff.rst | 12 ++--- docs/source/interactive/reference.rst | 54 +++++++++---------- docs/source/whatsnew/github-stats-3.rst | 4 +- docs/source/whatsnew/index.rst | 1 + 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/docs/source/interactive/index.rst b/docs/source/interactive/index.rst index 26c393d0595..a306258787d 100644 --- a/docs/source/interactive/index.rst +++ b/docs/source/interactive/index.rst @@ -11,6 +11,7 @@ Using IPython for interactive work reference shell tips + python-ipython-diff .. seealso:: diff --git a/docs/source/interactive/python-ipython-diff.rst b/docs/source/interactive/python-ipython-diff.rst index 466eaf5fc40..8bf67c49a84 100644 --- a/docs/source/interactive/python-ipython-diff.rst +++ b/docs/source/interactive/python-ipython-diff.rst @@ -7,7 +7,7 @@ language and what are the specific construct you can do only in IPython. Unless expressed otherwise all of the construct you will see here will raise a ``SyntaxError`` if run in a pure Python shell, or if executing in a Python -script. +script. Each of these features are describe more in details in further part of the documentation. @@ -56,7 +56,7 @@ All the following construct are valid IPython syntax: In [1]: %%perl magic --function ...: @months = ("July", "August", "September"); ...: print $months[0]; - + Each of these construct is compile by IPython into valid python code and will do most of the time what you expect it will do. Let see each of these example @@ -100,7 +100,7 @@ namespace will show help relative to this object: A double question mark will try to pull out more information about the object, -and if possible display the python source code of this object. +and if possible display the python source code of this object. .. code-block:: ipython @@ -143,7 +143,7 @@ Shell Assignment When doing interactive computing it is common to need to access the underlying shell. -This is doable through the use of the exclamation mark ``!`` (or bang). +This is doable through the use of the exclamation mark ``!`` (or bang). This allow to execute simple command when present in beginning of line: @@ -179,7 +179,7 @@ The later form of expansion supports arbitrary python expression: The bang can also be present in the right hand side of an assignment, just after the equal sign, or separated from it by a white space. In which case the standard output of the command after the bang ``!`` will be split out into lines -in a list-like object (:see:`IPython Slist`) and assign to the left hand side. +in a list-like object (:ref:`IPython Slist`) and assign to the left hand side. This allow you for example to put the list of files of the current working directory in a variable: @@ -205,7 +205,7 @@ Magics Magics function are often present in the form of shell-like syntax, but are under the hood python function. The syntax and assignment possibility are similar to the one with the bang (``!``) syntax, but with more flexibility and -power. Magic function start with a percent sign (``%``) or double percent (``%%``). +power. Magic function start with a percent sign (``%``) or double percent (``%%``). A magic call with a sign percent will act only one line: diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 492c8830eda..076bbf4ebda 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -19,7 +19,7 @@ file and ignore your configuration setup. Please note that some of the configuration options are not available at the command line, simply because they are not practical here. Look into -your configuration files for details on those. There are separate configuration +your configuration files for details on those. There are separate configuration files for each profile, and the files look like :file:`ipython_config.py` or :file:`ipython_config_{frontendname}.py`. Profile directories look like :file:`profile_{profilename}` and are typically installed in the :envvar:`IPYTHONDIR` directory, @@ -95,17 +95,17 @@ the same name:: /home/fperez The following uses the builtin :magic:`timeit` in cell mode:: - + In [10]: %%timeit x = range(10000) ...: min(x) ...: max(x) - ...: + ...: 1000 loops, best of 3: 438 us per loop In this case, ``x = range(10000)`` is called as the line argument, and the block with ``min(x)`` and ``max(x)`` is called as the cell body. The :magic:`timeit` magic receives both. - + If you have 'automagic' enabled (as it is by default), you don't need to type in the single ``%`` explicitly for line magics; IPython will scan its internal list of magic functions and call one if it exists. With automagic on you can @@ -116,7 +116,7 @@ then just type ``cd mydir`` to go to directory 'mydir':: Cell magics *always* require an explicit ``%%`` prefix, automagic calling only works for line magics. - + The automagic system has the lowest possible precedence in name searches, so you can freely use variables with the same names as magic commands. If a magic command is 'shadowed' by a variable, you will need the explicit ``%`` prefix to @@ -146,7 +146,7 @@ use it: /home/fperez/ipython Line magics, if they return a value, can be assigned to a variable using the syntax -``l = %sx ls`` (which in this particular case returns the result of `ls` as a python list). +``l = %sx ls`` (which in this particular case returns the result of `ls` as a python list). See :ref:`below ` for more information. Type ``%magic`` for more information, including a list of all available magic @@ -326,9 +326,9 @@ You can assign the result of a system command to a Python variable with the syntax ``myfiles = !ls``. Similarly, the result of a magic (as long as it returns a value) can be assigned to a variable. For example, the syntax ``myfiles = %sx ls`` is equivalent to the above system command example (the :magic:`sx` magic runs a shell command -and captures the output). Each of these gets machine -readable output from stdout (e.g. without colours), and splits on newlines. To -explicitly get this sort of output without assigning to a variable, use two +and captures the output). Each of these gets machine +readable output from stdout (e.g. without colours), and splits on newlines. To +explicitly get this sort of output without assigning to a variable, use two exclamation marks (``!!ls``) or the :magic:`sx` magic command without an assignment. (However, ``!!`` commands cannot be assigned to a variable.) @@ -340,8 +340,8 @@ See :ref:`string_lists` for details. IPython also allows you to expand the value of python variables when making system calls. Wrap variables or expressions in {braces}:: - In [1]: pyvar = 'Hello world' - In [2]: !echo "A python variable: {pyvar}" + In [1]: pyvar = 'Hello world' + In [2]: !echo "A python variable: {pyvar}" A python variable: Hello world In [3]: import math In [4]: x = 8 @@ -350,7 +350,7 @@ making system calls. Wrap variables or expressions in {braces}:: For simple cases, you can alternatively prepend $ to a variable name:: - In [6]: !echo $sys.argv + In [6]: !echo $sys.argv [/home/fperez/usr/bin/ipython] In [7]: !echo "A system variable: $$HOME" # Use $$ for literal $ A system variable: /home/fperez @@ -376,7 +376,7 @@ replaced by a positional parameter to the call to %parts:: In [1]: %alias parts echo first %s second %s In [2]: parts A B first A second B - In [3]: parts A + In [3]: parts A ERROR: Alias requires 2 arguments, 1 given. If called with no parameters, :magic:`alias` prints the table of currently @@ -420,8 +420,8 @@ Input caching system -------------------- IPython offers numbered prompts (In/Out) with input and output caching -(also referred to as 'input history'). All input is saved and can be -retrieved as variables (besides the usual arrow key recall), in +(also referred to as 'input history'). All input is saved and can be +retrieved as variables (besides the usual arrow key recall), in addition to the :magic:`rep` magic command that brings a history entry up for editing on the next command line. @@ -451,7 +451,7 @@ processing). Type %macro? for more details on the macro system. A history function :magic:`history` allows you to see any part of your input history by printing a range of the _i variables. -You can also search ('grep') through your history by typing +You can also search ('grep') through your history by typing ``%hist -g somestring``. This is handy for searching for URLs, IP addresses, etc. You can bring history entries listed by '%hist -g' up for editing with the %recall command, or run them immediately with :magic:`rerun`. @@ -537,8 +537,8 @@ will confuse IPython):: but this will work:: - In [5]: /zip (1,2,3),(4,5,6) - ------> zip ((1,2,3),(4,5,6)) + In [5]: /zip (1,2,3),(4,5,6) + ------> zip ((1,2,3),(4,5,6)) Out[5]: [(1, 4), (2, 5), (3, 6)] IPython tells you that it has altered your command line by displaying @@ -648,7 +648,7 @@ them separately, for example with different options for data presentation. If you close and open the same instance multiple times, its prompt counters simply continue from each execution to the next. -Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed` +Please look at the docstrings in the :mod:`~IPython.frontend.terminal.embed` module for more details on the use of this system. The following sample file illustrating how to use the embedding @@ -682,7 +682,7 @@ For more information on the use of the pdb debugger, see :ref:`debugger-commands in the Python documentation. IPython extends the debugger with a few useful additions, like coloring of -tracebacks. The debugger will adopt the color scheme selected for IPython. +tracebacks. The debugger will adopt the color scheme selected for IPython. The ``where`` command has also been extended to take as argument the number of context line to show. This allows to a many line of context on shallow stack trace: @@ -697,7 +697,7 @@ context line to show. This allows to a many line of context on shallow stack tra ...: 6 ...: 7 ...: - + In[6]: foo(1) # ... ipdb> where 8 @@ -797,7 +797,7 @@ standard Python tutorial:: In [4]: >>> while b < 10: ...: ... print(b) ...: ... a, b = b, a+b - ...: + ...: 1 1 2 @@ -810,7 +810,7 @@ And pasting from IPython sessions works equally well:: In [1]: In [5]: def f(x): ...: ...: "A simple function" ...: ...: return x**2 - ...: ...: + ...: ...: In [2]: f(3) Out[2]: 9 @@ -832,7 +832,7 @@ 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 +* There is a developer API in :mod:`IPython.lib.inputhook` for customizing all of these things. For users, enabling GUI event loop integration is simple. You simple use the @@ -848,7 +848,7 @@ object, do:: %gui wx -You can also start IPython with an event loop set up using the :option:`--gui` +You can also start IPython with an event loop set up using the `--gui` flag:: $ ipython --gui=qt @@ -862,7 +862,7 @@ form of a library, these capabilities are exposed in library form in the 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 +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. @@ -918,7 +918,7 @@ neither v2 PyQt nor PySide work. Note that this means for ETS 4 to work with PyQt4, ``QT_API`` *must* be set to work with IPython's qt integration, because otherwise PyQt4 will be loaded in an incompatible mode. - + It also means that you must *not* have ``QT_API`` set if you want to use ``--gui=qt`` with code that requires PyQt4 API v1. diff --git a/docs/source/whatsnew/github-stats-3.rst b/docs/source/whatsnew/github-stats-3.rst index 2c91ef76b48..c4fb3dff9e4 100644 --- a/docs/source/whatsnew/github-stats-3.rst +++ b/docs/source/whatsnew/github-stats-3.rst @@ -12,7 +12,7 @@ GitHub stats for 2015/06/22 - 2015/07/12 (since 3.2) These lists are automatically generated, and may be incomplete or contain duplicates. We closed 1 issue and merged 3 pull requests. -The full list can be seen `on GitHub `_ +The full list can be seen `on GitHub `__ The following 5 authors contributed 9 commits. @@ -31,7 +31,7 @@ GitHub stats for 2015/04/03 - 2015/06/21 (since 3.1) These lists are automatically generated, and may be incomplete or contain duplicates. We closed 7 issues and merged 30 pull requests. -The full list can be seen `on GitHub `_ +The full list can be seen `on GitHub `__ The following 15 authors contributed 74 commits. diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index c13142a93f7..e68fa3f06d0 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -20,6 +20,7 @@ development work they do here in a user friendly format. .. toctree:: :maxdepth: 1 + version5 development version4 github-stats-4 From a730594edb8ff398fcedfdc3dfd16d797279d729 Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 14:30:45 +0200 Subject: [PATCH 0411/4859] Add autogen and html_noapi to docs make.cmd --- docs/make.cmd | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/make.cmd b/docs/make.cmd index aa10980c690..08a2d788382 100644 --- a/docs/make.cmd +++ b/docs/make.cmd @@ -7,13 +7,14 @@ SET SPHINXOPTS= SET SPHINXBUILD=sphinx-build SET PAPER= SET SRCDIR=source +SET PYTHON=python IF "%PAPER%" == "" SET PAPER=a4 SET ALLSPHINXOPTS=-d build\doctrees -D latex_paper_size=%PAPER% %SPHINXOPTS% %SRCDIR% FOR %%X IN (%SPHINXBUILD%.exe) DO SET P=%%~$PATH:X -FOR %%L IN (html pickle htmlhelp latex changes linkcheck) DO ( +FOR %%L IN (html html_noapi pickle htmlhelp latex changes linkcheck) DO ( IF "%1" == "%%L" ( IF "%P%" == "" ( ECHO. @@ -22,7 +23,14 @@ FOR %%L IN (html pickle htmlhelp latex changes linkcheck) DO ( ) MD build\doctrees 2>NUL MD build\%1 || GOTO DIR_EXIST - %SPHINXBUILD% -b %1 %ALLSPHINXOPTS% build\%1 + %PYTHON% autogen_config.py && echo "Created docs for line & cell magics" + %PYTHON% autogen_magics.py && echo "Created docs for config options" + IF NOT "%1" == "html_noapi" ( + %PYTHON% autogen_api.py && echo "Build API docs finished." + %SPHINXBUILD% -b %1 %ALLSPHINXOPTS% build\%1 + ) ELSE ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% build\%1 + ) IF NOT ERRORLEVEL 0 GOTO ERROR ECHO. ECHO Build finished. Results are in build\%1. @@ -52,13 +60,14 @@ IF "%1" == "clean" ( ECHO. ECHO Please use "make [target]" where [target] is one of: ECHO. -ECHO html to make standalone HTML files -ECHO jsapi to make standalone HTML files for the Javascript API -ECHO pickle to make pickle files (usable by e.g. sphinx-web) -ECHO htmlhelp to make HTML files and a HTML help project -ECHO latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter -ECHO changes to make an overview over all changed/added/deprecated items -ECHO linkcheck to check all external links for integrity +ECHO html to make standalone HTML files +ECHO html_noapi same as above, without the time consuming API docs +ECHO jsapi to make standalone HTML files for the Javascript API +ECHO pickle to make pickle files (usable by e.g. sphinx-web) +ECHO htmlhelp to make HTML files and a HTML help project +ECHO latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter +ECHO changes to make an overview over all changed/added/deprecated items +ECHO linkcheck to check all external links for integrity GOTO END :DIR_EXIST From a2d38c250acb76904ab5ddaabfa0b13a3f3c73bc Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 16:24:52 +0200 Subject: [PATCH 0412/4859] Fix undefined labels in docs #2 --- docs/source/interactive/python-ipython-diff.rst | 2 +- docs/source/overview.rst | 2 +- docs/source/whatsnew/version0.12.rst | 7 +++---- docs/source/whatsnew/version1.0.rst | 4 ---- docs/source/whatsnew/version2.0.rst | 4 ++-- docs/source/whatsnew/version3.rst | 2 +- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/source/interactive/python-ipython-diff.rst b/docs/source/interactive/python-ipython-diff.rst index 8bf67c49a84..9ae08f5bcda 100644 --- a/docs/source/interactive/python-ipython-diff.rst +++ b/docs/source/interactive/python-ipython-diff.rst @@ -179,7 +179,7 @@ The later form of expansion supports arbitrary python expression: The bang can also be present in the right hand side of an assignment, just after the equal sign, or separated from it by a white space. In which case the standard output of the command after the bang ``!`` will be split out into lines -in a list-like object (:ref:`IPython Slist`) and assign to the left hand side. +in a list-like object and assign to the left hand side. This allow you for example to put the list of files of the current working directory in a variable: diff --git a/docs/source/overview.rst b/docs/source/overview.rst index a81604d23cf..f6ebd3d143e 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -20,7 +20,7 @@ has three main components: * An enhanced interactive Python shell. * A decoupled :ref:`two-process communication model `, which allows for multiple clients to connect to a computation kernel, most notably - the web-based :ref:`notebook ` + the web-based notebook. * An architecture for interactive parallel computing. All of IPython is open source (released under the revised BSD license). diff --git a/docs/source/whatsnew/version0.12.rst b/docs/source/whatsnew/version0.12.rst index d5c9090a082..1d8a2dba028 100644 --- a/docs/source/whatsnew/version0.12.rst +++ b/docs/source/whatsnew/version0.12.rst @@ -97,8 +97,7 @@ for floating matplotlib windows or:: for plotting support with automatically inlined figures. Note that it is now possible also to activate pylab support at runtime via ``%pylab``, so you do not need to make this decision when starting the server. - -See :ref:`the Notebook docs ` for technical details. + .. _two_process_console: @@ -173,8 +172,8 @@ Other important new features ---------------------------- * **SSH Tunnels**: In 0.11, the :mod:`IPython.parallel` Client could tunnel its - connections to the Controller via ssh. Now, the QtConsole :ref:`supports - ` ssh tunneling, as do parallel engines. + connections to the Controller via ssh. Now, the QtConsole supports ssh tunneling, + as do parallel engines. * **relaxed command-line parsing**: 0.11 was released with overly-strict command-line parsing, preventing the ability to specify arguments with spaces, diff --git a/docs/source/whatsnew/version1.0.rst b/docs/source/whatsnew/version1.0.rst index 35e186e802c..3e8afdb1dfc 100644 --- a/docs/source/whatsnew/version1.0.rst +++ b/docs/source/whatsnew/version1.0.rst @@ -164,10 +164,6 @@ To use nbconvert to convert various file formats:: See ``ipython nbconvert --help`` for more information. nbconvert depends on `pandoc`_ for many of the translations to and from various formats. -.. seealso:: - - :ref:`nbconvert` - .. _pandoc: http://johnmacfarlane.net/pandoc/ Notebook diff --git a/docs/source/whatsnew/version2.0.rst b/docs/source/whatsnew/version2.0.rst index 83f02871b2b..e379308fd53 100644 --- a/docs/source/whatsnew/version2.0.rst +++ b/docs/source/whatsnew/version2.0.rst @@ -149,11 +149,11 @@ which can be started from the Help menu. Security ******** -2.0 introduces a :ref:`security model ` for notebooks, +2.0 introduces a security model for notebooks, to prevent untrusted code from executing on users' behalf when notebooks open. A quick summary of the model: -- Trust is determined by :ref:`signing notebooks`. +- Trust is determined by signing notebooks. - Untrusted HTML output is sanitized. - Untrusted Javascript is never executed. - HTML and Javascript in Markdown are never trusted. diff --git a/docs/source/whatsnew/version3.rst b/docs/source/whatsnew/version3.rst index 3372aaaa957..8bc6869541e 100644 --- a/docs/source/whatsnew/version3.rst +++ b/docs/source/whatsnew/version3.rst @@ -278,7 +278,7 @@ Backwards incompatible changes Adapters are included, so IPython frontends can still talk to kernels that implement protocol version 4. -* The :ref:`notebook format ` has been updated from version 3 to version 4. +* The notebook format has been updated from version 3 to version 4. Read-only support for v4 notebooks has been backported to IPython 2.4. Notable changes: From b399422796c9bc9193d7a2f8e30777cb2ae8841b Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 16:36:35 +0200 Subject: [PATCH 0413/4859] Skip pt_inputhooks --- docs/autogen_api.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/autogen_api.py b/docs/autogen_api.py index 75b6a26b5e3..504ab0f3e5c 100755 --- a/docs/autogen_api.py +++ b/docs/autogen_api.py @@ -30,6 +30,7 @@ r'\.sphinxext', # Shims r'\.kernel', + r'\.terminal\.pt_inputhooks', ] # The inputhook* modules often cause problems on import, such as trying to @@ -37,8 +38,6 @@ docwriter.module_skip_patterns += [ r'\.lib\.inputhook.+', r'\.ipdoctest', r'\.testing\.plugin', - # Deprecated: - r'\.core\.magics\.deprecated', # Backwards compat import for lib.lexers r'\.nbconvert\.utils\.lexers', # We document this manually. From 32cc988e81bbbecf09f7e7a801e92c6cfc281e75 Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 17:10:39 +0200 Subject: [PATCH 0414/4859] Remove generation of unnecessary generated.rst file --- docs/autogen_config.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/autogen_config.py b/docs/autogen_config.py index 2514c513bfd..a562ab4fcc5 100755 --- a/docs/autogen_config.py +++ b/docs/autogen_config.py @@ -7,7 +7,6 @@ here = abspath(dirname(__file__)) options = join(here, 'source', 'config', 'options') -generated = join(options, 'generated.rst') def write_doc(name, title, app, preamble=None): filename = '%s.rst' % name @@ -18,18 +17,12 @@ def write_doc(name, title, app, preamble=None): if preamble is not None: f.write(preamble + '\n\n') f.write(app.document_config_options()) - with open(generated, 'a') as f: - f.write(filename + '\n') if __name__ == '__main__': - # create empty file - with open(generated, 'w'): - pass write_doc('terminal', 'Terminal IPython options', TerminalIPythonApp()) write_doc('kernel', 'IPython kernel options', IPKernelApp(), preamble=("These options can be used in :file:`ipython_kernel_config.py`. " "The kernel also respects any options in `ipython_config.py`"), ) - From fc6d290de2af9aa17a52bc3136120d31a9cf920e Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 18:06:02 +0200 Subject: [PATCH 0415/4859] Fix argument type in docsting --- IPython/lib/latextools.py | 2 +- IPython/utils/tokenutil.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/lib/latextools.py b/IPython/lib/latextools.py index c0d646ba3aa..c3230dd489e 100644 --- a/IPython/lib/latextools.py +++ b/IPython/lib/latextools.py @@ -64,7 +64,7 @@ def latex_to_png(s, encode=False, backend=None, wrap=False): Parameters ---------- - s : text + s : str The raw string containing valid inline LaTeX. encode : bool, optional Should the PNG data base64 encoded to make it JSON'able. diff --git a/IPython/utils/tokenutil.py b/IPython/utils/tokenutil.py index ab42d795ccc..f52d3b76583 100644 --- a/IPython/utils/tokenutil.py +++ b/IPython/utils/tokenutil.py @@ -31,7 +31,7 @@ def line_at_cursor(cell, cursor_pos=0): Parameters ---------- - cell: text + cell: str multiline block of text cursor_pos: integer the cursor position From 63aaecb5af7881f1696ab1b39658a006a7a87f02 Mon Sep 17 00:00:00 2001 From: klonuo Date: Tue, 7 Jun 2016 18:38:15 +0200 Subject: [PATCH 0416/4859] Swap echo messages --- docs/make.cmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/make.cmd b/docs/make.cmd index 08a2d788382..e2347617f07 100644 --- a/docs/make.cmd +++ b/docs/make.cmd @@ -23,10 +23,10 @@ FOR %%L IN (html html_noapi pickle htmlhelp latex changes linkcheck) DO ( ) MD build\doctrees 2>NUL MD build\%1 || GOTO DIR_EXIST - %PYTHON% autogen_config.py && echo "Created docs for line & cell magics" - %PYTHON% autogen_magics.py && echo "Created docs for config options" + %PYTHON% autogen_config.py && ECHO Created docs for config options + %PYTHON% autogen_magics.py && ECHO Created docs for line ^& cell magics IF NOT "%1" == "html_noapi" ( - %PYTHON% autogen_api.py && echo "Build API docs finished." + %PYTHON% autogen_api.py && ECHO Build API docs finished %SPHINXBUILD% -b %1 %ALLSPHINXOPTS% build\%1 ) ELSE ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% build\%1 From 62ba7e4b9d642054591e61309ae99ef206c1f3aa Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 12:18:44 -0700 Subject: [PATCH 0417/4859] Some docs --- IPython/core/interactiveshell.py | 2 ++ IPython/core/oinspect.py | 15 +++++------ docs/source/whatsnew/version5.rst | 43 +++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index aca1a549ac4..9f1d782e0ad 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1550,11 +1550,13 @@ def _inspect(self, meth, oname, namespaces=None, **kw): """ info = self._object_find(oname, namespaces) docformat = sphinxify if self.sphinxify_docstring else None + print("using docformat", docformat, self.sphinxify_docstring, sphinxify) if info.found: pmethod = getattr(self.inspector, meth) # TODO: only apply format_screen to the plain/text repr of the mime # bundle. formatter = format_screen if info.ismagic else docformat + print("usingformatter", formatter) if meth == 'pdoc': pmethod(info.obj, oname, formatter) elif meth == 'pinfo': diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 88093af0c6f..d4c56e57264 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -44,6 +44,13 @@ from IPython.utils.signatures import signature from IPython.utils.colorable import Colorable +from pygments import highlight +from pygments.lexers import PythonLexer +from pygments.formatters import HtmlFormatter + +def pylight(code): + return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True)) + # builtin docstrings to ignore _func_call_docstring = types.FunctionType.__call__.__doc__ _object_init_docstring = object.__init__.__doc__ @@ -365,14 +372,6 @@ def find_source_lines(obj): return lineno -from pygments import highlight -from pygments.lexers import PythonLexer -from pygments.formatters import HtmlFormatter - -def pylight(code): - return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True)) - - class Inspector(Colorable): def __init__(self, color_table=InspectColors, diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index fe83f2707d0..2a6382ea4a1 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -41,3 +41,46 @@ IPython itself. the `PromptManager` class have been removed, and the prompt machinery simplified. See `TerminalINteractiveShell.prompts` configurable for how to setup your prompts. + + +Provisional Changes +------------------- + +Provisional changes are in experimental functionality that may, or may not make +it to future version of IPython, and which API may change without warnings. +Activating these feature and using these API is at your own risk, and may have +security implication for your system, especially if used with the Jupyter notebook, + +When running via the Jupyter notebook interfaces, or other compatible client, +you can enable rich documentation experimental functionality: + +When the ``docrepr`` package is installed setting the boolean flag +``InteractiveShell.sphinxify_docstring`` to ``True``, will process the various +object through sphinx before displaying them (see the ``docrepr`` package +documentation for more information. + +You need to also enable the IPython pager display rich HTML representation +using the ``InteractiveShell.enable_html_pager`` boolean configuration option. +As usual you can set these configuration options globally in your configuration +files, alternatively you can turn them on dynamically using the following +snippet: + +.. code-block:: python + + ip = get_ipython() + ip.sphinxify_docstring = True + ip.enable_html_pager = True + +You can test the effect of various combinations of the above configuration in +the Jupyter notebook, with things example like : + +.. code-block:: python + + import numpy as np + np.histogram? + +This is part of an effort to make Documentation in Python richer and provide in +the long term if possible dynamic examples that can contain math, images, +widgets... As stated above this is nightly experimental feature with a lot of +(fun) problem to solve. We would be happy to get your feedback and expertise on +it. From 4989935f46d0825ec09680849009de28ac924740 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 13:10:20 -0700 Subject: [PATCH 0418/4859] Remove forgotten print statements --- IPython/core/interactiveshell.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 9f1d782e0ad..aca1a549ac4 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1550,13 +1550,11 @@ def _inspect(self, meth, oname, namespaces=None, **kw): """ info = self._object_find(oname, namespaces) docformat = sphinxify if self.sphinxify_docstring else None - print("using docformat", docformat, self.sphinxify_docstring, sphinxify) if info.found: pmethod = getattr(self.inspector, meth) # TODO: only apply format_screen to the plain/text repr of the mime # bundle. formatter = format_screen if info.ismagic else docformat - print("usingformatter", formatter) if meth == 'pdoc': pmethod(info.obj, oname, formatter) elif meth == 'pinfo': From 7874c2c8e865e1eb6857081f58858577e3702ac6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 13:23:47 -0700 Subject: [PATCH 0419/4859] Add provisional warnings. --- IPython/core/interactiveshell.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index aca1a549ac4..f800cc91242 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -95,6 +95,13 @@ def sphinxify(doc): except ImportError: sphinxify = None + +class ProvisionalWarning(DeprecationWarning): + """ + Warning class for unstable features + """ + pass + #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -212,6 +219,7 @@ class InteractiveShell(SingletonConfigurable): Autoindent IPython code entered interactively. """ ).tag(config=True) + automagic = Bool(True, help= """ Enable magic commands to be called without the leading %. @@ -277,16 +285,29 @@ class InteractiveShell(SingletonConfigurable): display_formatter = Instance(DisplayFormatter, allow_none=True) displayhook_class = Type(DisplayHook) display_pub_class = Type(DisplayPublisher) + sphinxify_docstring = Bool(False, help= """ Enables rich html representation of docstrings. (This requires the docrepr module). """).tag(config=True) + + @observe("sphinxify_docstring") + def _sphinxify_docstring_changed(self, change): + if change['new'] is True: + warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning) + enable_html_pager = Bool(False, help= """ (Provisional API) enables html representation in mime bundles sent to pagers. """).tag(config=True) + + @observe("enable_html_pager") + def _enable_html_pager_changed(self, change): + if change['new'] is True: + warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning) + data_pub_class = None exit_now = Bool(False) From 03e6b0c099d27d6ab139a593d0ab101a9227374b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 13:29:37 -0700 Subject: [PATCH 0420/4859] Fail on bad use of traitlets. --- IPython/testing/iptest.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 1a9dd72d6e0..7bfa6496ae0 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -47,6 +47,7 @@ warnings.filterwarnings('ignore', message='.*Matplotlib is building the font cache.*', category=UserWarning, module='.*') if sys.version_info > (3,0): warnings.filterwarnings('error', message='.*', category=ResourceWarning, module='.*') +warnings.filterwarnings('error', message=".*{'config': True}.*", category=DeprecationWarning, module='IPy.*') warnings.filterwarnings('default', message='.*', category=Warning, module='IPy.*') if version_info < (6,): From 78b1453c926791fa227080266600381ce5ab1fa3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 13:30:02 -0700 Subject: [PATCH 0421/4859] Fix traitlets API usage, to match 4.2. --- IPython/terminal/ptshell.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 0f8bcf54555..177a3d0b822 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -11,7 +11,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 +from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone @@ -125,10 +125,11 @@ def _highlighting_style_changed(self, change): help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ).tag(config=True) - prompts_class = Type(Prompts, config=True, help='Class used to generate Prompt token for prompt_toolkit') + prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True) prompts = Instance(Prompts) + @default('prompts') def _prompts_default(self): return self.prompts_class(self) @@ -136,6 +137,7 @@ def _prompts_default(self): def _(self, change): self._update_layout() + @default('displayhook_class') def _displayhook_class_default(self): return RichPromptDisplayHook From 4da4b40e380d0f62f2ef46731932ff901fb812d5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 15:41:03 -0700 Subject: [PATCH 0422/4859] Restore previous key bindings. Esc dismiss the completer on next loop tick, or next keypress (technical limitation) then clear the prompt. ControlC dismiss the completer without clearing the buffer first. Closes #9564 Closes #9554 Bump #9556 To feature request. --- IPython/terminal/ptshell.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 0f8bcf54555..10851097b7c 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -199,9 +199,17 @@ def _(event): else: b.insert_text('\n' + (' ' * (indent or 0))) + # We have to set eager to True for Escape this will lead to a delay to + # dismiss the completer or clear the buffer until next loop, or next input character. + # CtrlC will act immediately. + @kbmanager.registry.add_binding(Keys.Escape, filter=HasFocus(DEFAULT_BUFFER), eager=True) @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) def _reset_buffer(event): - event.current_buffer.reset() + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + else: + b.reset() @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) def _reset_search_buffer(event): From 97bd1ea3260774ffe438a5f850c7873e903e6e3f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 16:04:21 -0700 Subject: [PATCH 0423/4859] release 5.0.0b2 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 378ad55a95c..bd4becf5044 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'b1' +_version_extra = 'b2' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 73e6bc54a18209d133dfccf2c695b1dfe7c40622 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 7 Jun 2016 16:07:33 -0700 Subject: [PATCH 0424/4859] Back to dev --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index bd4becf5044..05b578cf73d 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'b2' +# _version_extra = 'b2' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From a29ac5524df06305614bee0350d4f57575a3d51c Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 8 Jun 2016 11:47:08 +0200 Subject: [PATCH 0425/4859] add colon to header block in oinspect output rather than outside, so the colon's style matches the word --- IPython/core/oinspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index d4c56e57264..4a3b4d31aef 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -607,7 +607,7 @@ def append_field(bundle, title, key, formatter=None): field = info[key] if field is not None: formatted_field = self._mime_format(field, formatter) - bundle['text/plain'] += self.__head(title) + ':\n' + formatted_field['text/plain'] + '\n' + bundle['text/plain'] += self.__head(title + ':') + '\n' + formatted_field['text/plain'] + '\n' bundle['text/html'] += '

' + title + '

\n' + formatted_field['text/html'] + '\n' def code_formatter(text): From be7114821f3aece0b24962c86638e715fea6fc04 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 8 Jun 2016 11:53:04 +0200 Subject: [PATCH 0426/4859] InteractiveShell.object_inspect_text must return text That's the whole point of it. Adds object_inspect_mime for returning the mimebundle of formatted outputs, which `_get_info` now returns. --- IPython/core/interactiveshell.py | 8 ++++++++ IPython/core/tests/test_interactiveshell.py | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index aca1a549ac4..4a55669bf0f 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1579,6 +1579,14 @@ def object_inspect(self, oname, detail_level=0): def object_inspect_text(self, oname, detail_level=0): """Get object info as formatted text""" + return self.object_inspect_mime(oname, detail_level)['text/plain'] + + def object_inspect_mime(self, oname, detail_level=0): + """Get object info as a mimebundle of formatted representations. + + A mimebundle is a dictionary, keyed by mime-type. + It must always have the key `'text/plain'`. + """ with self.builtin_trap: info = self._object_find(oname) if info.found: diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py index 3a38c84f2b5..db22c158b66 100644 --- a/IPython/core/tests/test_interactiveshell.py +++ b/IPython/core/tests/test_interactiveshell.py @@ -514,6 +514,12 @@ def test_get_exception_only(self): else: self.assertEqual(msg, 'IPython.core.tests.test_interactiveshell.DerivedInterrupt: foo\n') + def test_inspect_text(self): + ip.run_cell('a = 5') + text = ip.object_inspect_text('a') + self.assertIsInstance(text, unicode_type) + + class TestSafeExecfileNonAsciiPath(unittest.TestCase): @onlyif_unicode_paths From 4556af2f1433824b0519c7f31cc62ff1781d51cd Mon Sep 17 00:00:00 2001 From: Udi Oron Date: Wed, 8 Jun 2016 13:03:04 +0300 Subject: [PATCH 0427/4859] fix typo --- docs/source/whatsnew/version5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 2a6382ea4a1..4e7b59561a7 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -7,7 +7,7 @@ IPython 5.0 Released June, 2016 -IPython 5.0 now uses `promt-toolkit` for the command line interface, thus +IPython 5.0 now uses `prompt-toolkit` for the command line interface, thus allowing real multi-line editing and syntactic coloration as you type. From 6a99f90f441a267dc74d8bf1496e1d89119d49b9 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 8 Jun 2016 10:06:38 -0700 Subject: [PATCH 0428/4859] use idiomatic Python --- IPython/core/interactiveshell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index f800cc91242..b5b68c27916 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -294,7 +294,7 @@ class InteractiveShell(SingletonConfigurable): @observe("sphinxify_docstring") def _sphinxify_docstring_changed(self, change): - if change['new'] is True: + if change['new']: warn("`sphinxify_docstring` is provisional since IPython 5.0 and might change in future versions." , ProvisionalWarning) enable_html_pager = Bool(False, help= @@ -305,7 +305,7 @@ def _sphinxify_docstring_changed(self, change): @observe("enable_html_pager") def _enable_html_pager_changed(self, change): - if change['new'] is True: + if change['new']: warn("`enable_html_pager` is provisional since IPython 5.0 and might change in future versions.", ProvisionalWarning) data_pub_class = None From b0f81c6a2fbe111a96e297d1d1c03894d9acbce6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 8 Jun 2016 11:39:53 -0700 Subject: [PATCH 0429/4859] Fix crash dusing completion on PTK 1.0.0 Closes #9579 Closes #9578 --- IPython/terminal/ptshell.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 0f8bcf54555..24aad2e1884 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -183,8 +183,9 @@ def _(event): d = b.document if b.complete_state: - cs = b.complete_state - b.apply_completion(cs.current_completion) + cc = b.complete_state.current_completion + if cc: + b.apply_completion(cc) return if not (d.on_last_line or d.cursor_position_row >= d.line_count From 9be1a3b3c8a47455a48c75e95da3b7b7603ab68d Mon Sep 17 00:00:00 2001 From: Jonathan Slenders Date: Wed, 8 Jun 2016 21:18:23 +0200 Subject: [PATCH 0430/4859] Use correct Pygments lexers for different %%magics. --- IPython/terminal/ptutils.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 312ba1268d6..092373e4f61 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -7,7 +7,8 @@ from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer -from pygments.lexers import Python3Lexer, BashLexer, PythonLexer +import pygments.lexers as pygments_lexers + class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" @@ -56,11 +57,32 @@ class IPythonPTLexer(Lexer): Wrapper around PythonLexer and BashLexer. """ def __init__(self): - self.python_lexer = PygmentsLexer(Python3Lexer if PY3 else PythonLexer) - self.shell_lexer = PygmentsLexer(BashLexer) + l = pygments_lexers + self.python_lexer = PygmentsLexer(l.Python3Lexer if PY3 else l.PythonLexer) + self.shell_lexer = PygmentsLexer(l.BashLexer) + + self.magic_lexers = { + 'HTML': PygmentsLexer(l.HtmlLexer), + 'html': PygmentsLexer(l.HtmlLexer), + 'javascript': PygmentsLexer(l.JavascriptLexer), + 'js': PygmentsLexer(l.JavascriptLexer), + 'perl': PygmentsLexer(l.PerlLexer), + 'ruby': PygmentsLexer(l.RubyLexer), + 'latex': PygmentsLexer(l.TexLexer), + } def lex_document(self, cli, document): - if document.text.startswith('!'): - return self.shell_lexer.lex_document(cli, document) - else: - return self.python_lexer.lex_document(cli, document) + text = document.text.lstrip() + + lexer = self.python_lexer + + if text.startswith('!') or text.startswith('%%bash'): + lexer = self.shell_lexer + + elif text.startswith('%%'): + for magic, l in self.magic_lexers.items(): + if text.startswith('%%' + magic): + lexer = l + break + + return lexer.lex_document(cli, document) From b6b21215ac6848fb69b6fd223a4d49cada5c2394 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 8 Jun 2016 12:24:00 -0700 Subject: [PATCH 0431/4859] Use CtrlG instead of Escape as per request. --- IPython/terminal/ptshell.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 10851097b7c..4c5f7a913ce 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -14,7 +14,7 @@ from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone +from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone, HasCompletions from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface @@ -199,10 +199,17 @@ def _(event): else: b.insert_text('\n' + (' ' * (indent or 0))) - # We have to set eager to True for Escape this will lead to a delay to - # dismiss the completer or clear the buffer until next loop, or next input character. - # CtrlC will act immediately. - @kbmanager.registry.add_binding(Keys.Escape, filter=HasFocus(DEFAULT_BUFFER), eager=True) + @kbmanager.registry.add_binding(Keys.ControlG, filter=( + HasFocus(DEFAULT_BUFFER) & HasCompletions() + )) + def _dismiss_completion(event): + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + + + + @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) def _reset_buffer(event): b = event.current_buffer From cb6a75d855c203e0c17b25ef8136de0b1d6a817c Mon Sep 17 00:00:00 2001 From: klonuo Date: Thu, 9 Jun 2016 15:09:54 +0200 Subject: [PATCH 0432/4859] Refactor autogen config --- docs/Makefile | 5 ++--- docs/autogen_config.py | 8 ++++++-- docs/source/config/options/index.rst | 5 +---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 6beba8a33cf..b804b515337 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -41,8 +41,7 @@ clean_api: clean: clean_api -rm -rf build/* dist/* - -cd $(SRCDIR)/config/options; test -f generated && cat generated | xargs rm -f - -rm -rf $(SRCDIR)/config/options/generated + -rm -f $(SRCDIR)/config/options/config-generated.txt -rm -f $(SRCDIR)/interactive/magics-generated.txt pdf: latex @@ -75,7 +74,7 @@ source/interactive/magics-generated.txt: autogen_magics.py $(PYTHON) autogen_magics.py @echo "Created docs for line & cell magics" -autoconfig: source/config/options/generated +autoconfig: source/config/options/config-generated.txt source/config/options/generated: $(PYTHON) autogen_config.py diff --git a/docs/autogen_config.py b/docs/autogen_config.py index a562ab4fcc5..f2f6f66667d 100755 --- a/docs/autogen_config.py +++ b/docs/autogen_config.py @@ -7,10 +7,11 @@ here = abspath(dirname(__file__)) options = join(here, 'source', 'config', 'options') +generated = join(options, 'config-generated.txt') + def write_doc(name, title, app, preamble=None): - filename = '%s.rst' % name - with open(join(options, filename), 'w') as f: + with open(generated, 'a') as f: f.write(title + '\n') f.write(('=' * len(title)) + '\n') f.write('\n') @@ -20,6 +21,9 @@ def write_doc(name, title, app, preamble=None): if __name__ == '__main__': + # create empty file + with open(generated, 'w'): + pass write_doc('terminal', 'Terminal IPython options', TerminalIPythonApp()) write_doc('kernel', 'IPython kernel options', IPKernelApp(), diff --git a/docs/source/config/options/index.rst b/docs/source/config/options/index.rst index a0f38e2a231..70907995c94 100644 --- a/docs/source/config/options/index.rst +++ b/docs/source/config/options/index.rst @@ -6,7 +6,4 @@ Any of the options listed here can be set in config files, at the command line, or from inside IPython. See :ref:`setting_config` for details. -.. toctree:: - - terminal - kernel +.. include:: config-generated.txt From 747b00318f04506de5134988d2c9b000fd2a661b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 10:07:57 -0700 Subject: [PATCH 0433/4859] "a few whats new" --- docs/source/whatsnew/version5.rst | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 2a6382ea4a1..52b43d1075c 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -84,3 +84,25 @@ the long term if possible dynamic examples that can contain math, images, widgets... As stated above this is nightly experimental feature with a lot of (fun) problem to solve. We would be happy to get your feedback and expertise on it. + + +Known Issues: +------------- + + - ```` Key does not dismiss the completer and does not clear the current + buffer. This is an on purpose modification due to current technical + limitation. Cf :ghpull:`9572`. Escape the control character which is used + for other shortcut, and there is no practical way to distinguish. Use Ctr-G + or Ctrl-C as an alternative. + + - Cannot use ``Shift-Enter`` and ``Ctrl-Enter`` to submit code in terminal. cf + :gh:`9587` and :gh:`9401`. In terminal there is no practical way to + distinguish these key sequences from a normal new line return. + + - Dialog completion pop up even with a single completion. Cf :gh:`9540`. This + would automatically be resolved with the next minor revision of + ``prompt_toolkit`` + + - ``PageUp`` and ``pageDown`` do not move through completion menu. + + From 5f2390588213c6def555804695d122aa0268c121 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 10:30:57 -0700 Subject: [PATCH 0434/4859] Restore vi-insert mode `CtrlP` and `CtrlN` to readline behavior. Vi key binding for readline are slightly different than the Vi Editor. CtrlP and CtrlN in insert mode do recall previous or next history line instead of calling the completer. By default Prompt toolkit (1.0.0 at least) implement the Vi-editor key bindings. Though muscle memory is hard and our vi-mode users[1] have a hard time adapting. This though overwrite the PTK default and mimic the readline behavior. Completer can still be invoked with ``, and then CtrlP, CtrlN will select previous / next. closes #9584 Special commit acknowledgement. [1] I'm inclined not to put a `s` here, as only Matthew Brett complains and it's his usual behavior. But I don't want to ignore Paul Ivanov either, and so technically two is sufficient to make our Vi users plural. --- IPython/terminal/ptshell.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index f2cf23c4559..d472a29437f 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -202,6 +202,24 @@ def _(event): else: b.insert_text('\n' + (' ' * (indent or 0))) + @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) + def _previous_history_or_previous_completion(event): + """ + Control-P in vi edit mode on readline is history next, unlike default prompt toolkit. + + If completer is open this still select previous completion. + """ + event.current_buffer.auto_up() + + @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) + def _next_history_or_next_completion(event): + """ + Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit. + + If completer is open this still select next completion. + """ + event.current_buffer.auto_down() + @kbmanager.registry.add_binding(Keys.ControlG, filter=( HasFocus(DEFAULT_BUFFER) & HasCompletions() )) @@ -210,9 +228,6 @@ def _dismiss_completion(event): if b.complete_state: b.cancel_completion() - - - @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) def _reset_buffer(event): b = event.current_buffer From bab9c8efd6c316d18a1245779b5628aa52e46ead Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 14:43:14 -0700 Subject: [PATCH 0435/4859] List a few know issues in changelog. --- docs/source/whatsnew/version5.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index a44d2a66531..50cf5384dbb 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -96,13 +96,19 @@ Known Issues: or Ctrl-C as an alternative. - Cannot use ``Shift-Enter`` and ``Ctrl-Enter`` to submit code in terminal. cf - :gh:`9587` and :gh:`9401`. In terminal there is no practical way to + :ghissue:`9587` and :ghissue:`9401`. In terminal there is no practical way to distinguish these key sequences from a normal new line return. - - Dialog completion pop up even with a single completion. Cf :gh:`9540`. This + - Dialog completion pop up even with a single completion. Cf :ghissue:`9540`. This would automatically be resolved with the next minor revision of ``prompt_toolkit`` - ``PageUp`` and ``pageDown`` do not move through completion menu. + - Custom prompt cannot make use of custom invisible escape sequences. This + will be automatically resolved with next version of Prompt Toolkit + + - Color styles might not adapt to terminal emulator themes. This will need new + version of Pygments to be released, and can be mitigated with custom themes. + From 7f5f1ce798670efd23ced7c5650afa84d07efd90 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 14:48:27 -0700 Subject: [PATCH 0436/4859] release 5.0.0b3 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 05b578cf73d..a85fe24c5f3 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'b2' +_version_extra = 'b3' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From b80aa920178589e1f03c80328f2bda674b35f6d1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 14:52:40 -0700 Subject: [PATCH 0437/4859] back to .dev --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index a85fe24c5f3..8272c2efc48 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'b3' +# _version_extra = 'b3' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From e6a041f3851513f1c8a993f2318d05205fa19e44 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 9 Jun 2016 17:16:35 -0700 Subject: [PATCH 0438/4859] Fix case where completer menu get stuck if nothing is focused. --- IPython/terminal/ptshell.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index d472a29437f..4616988ad26 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -188,6 +188,8 @@ def _(event): cc = b.complete_state.current_completion if cc: b.apply_completion(cc) + else: + b.cancel_completion() return if not (d.on_last_line or d.cursor_position_row >= d.line_count From 1440e81e369bfd3910e25f9a4a69e62578ba4333 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 9 Jun 2016 20:13:13 -0500 Subject: [PATCH 0439/4859] BUG: extra blank line on dedenting keywords --- IPython/core/inputsplitter.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index 1b4d55b1eff..b6964649337 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -626,12 +626,15 @@ def push(self, lines): # We must ensure all input is pure unicode lines = cast_unicode(lines, self.encoding) - # ''.splitlines() --> [], but we need to push the empty line to transformers lines_list = lines.splitlines() if not lines_list: lines_list = [''] + # interpet trailing newline as a blank line + if lines.endswith('\n'): + lines_list += [''] + # Store raw source before applying any transformations to it. Note # that this must be done *after* the reset() call that would otherwise # flush the buffer. From 98b23995b0964ecbd071f88c710ead40b051e945 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 9 Jun 2016 20:31:36 -0500 Subject: [PATCH 0440/4859] handle from ptshell side --- IPython/core/inputsplitter.py | 4 ---- IPython/terminal/ptshell.py | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/IPython/core/inputsplitter.py b/IPython/core/inputsplitter.py index b6964649337..ac14747d69c 100644 --- a/IPython/core/inputsplitter.py +++ b/IPython/core/inputsplitter.py @@ -631,10 +631,6 @@ def push(self, lines): if not lines_list: lines_list = [''] - # interpet trailing newline as a blank line - if lines.endswith('\n'): - lines_list += [''] - # Store raw source before applying any transformations to it. Note # that this must be done *after* the reset() call that would otherwise # flush the buffer. diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index d472a29437f..dee66b27b2f 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -195,7 +195,7 @@ def _(event): b.newline() return - status, indent = self.input_splitter.check_complete(d.text) + status, indent = self.input_splitter.check_complete(d.text + '\n') if (status != 'incomplete') and b.accept_action.is_returnable: b.accept_action.validate_and_handle(event.cli, b) From b46f60a6ebfec7dd1fb0b5a594c96f2aea205657 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 10 Jun 2016 14:34:41 +0200 Subject: [PATCH 0441/4859] terminal IPython display formatter is plain-text-only this was lost in the ptshell transition --- IPython/terminal/ptshell.py | 5 +++++ IPython/terminal/tests/test_interactivshell.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 4616988ad26..15c6647af64 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -162,6 +162,11 @@ def init_term_title(self, change=None): else: toggle_set_term_title(False) + def init_display_formatter(self): + super(TerminalInteractiveShell, self).init_display_formatter() + # terminal only supports plain text + self.display_formatter.active_types = ['text/plain'] + def init_prompt_toolkit_cli(self): self._app = None if self.simple_prompt: diff --git a/IPython/terminal/tests/test_interactivshell.py b/IPython/terminal/tests/test_interactivshell.py index 6eebf79ceea..9e76d5f0d56 100644 --- a/IPython/terminal/tests/test_interactivshell.py +++ b/IPython/terminal/tests/test_interactivshell.py @@ -95,6 +95,11 @@ def test_inputtransformer_syntaxerror(self): ip.input_splitter.python_line_transforms.remove(transformer) ip.input_transformer_manager.python_line_transforms.remove(transformer) + def test_plain_text_only(self): + ip = get_ipython() + formatter = ip.display_formatter + assert formatter.active_types == ['text/plain'] + class SyntaxErrorTransformer(InputTransformer): def push(self, line): From 51210a7eebac6ea92dfca3a73134e255009548b4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Sun, 12 Jun 2016 10:25:54 -0700 Subject: [PATCH 0442/4859] Fix double formatting. closes #9607 --- IPython/core/oinspect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 4a3b4d31aef..7da59a28093 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -831,7 +831,7 @@ def _info(self, obj, oname='', info=None, detail_level=0): init_def = None if init_def: - out['init_definition'] = self.format(init_def) + out['init_definition'] = init_def # get the __init__ docstring try: From 589822493192889f8d6902f3461ae63e0040ff5f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 14 Jun 2016 16:21:40 +0100 Subject: [PATCH 0443/4859] Ctrl-V paste on Windows Allow users to paste in Windows with Ctrl-V, avoiding some issues with native paste in cmd, as discussed in gh-9600. I'm only enabling this in Windows, because native bracketed paste should work well in Unix terminals. And it's disabled if you use vi editing mode, in case it conflicts with other shortcuts. There probably aren't many Windows users who configure vi mode, in any case. --- IPython/terminal/ptshell.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c20ecd3536c..109ede9693e 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -14,7 +14,9 @@ from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from prompt_toolkit.filters import HasFocus, HasSelection, Condition, ViInsertMode, EmacsInsertMode, IsDone, HasCompletions +from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, + ViInsertMode, EmacsInsertMode, IsDone, HasCompletions) +from prompt_toolkit.filters.cli import ViMode from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface @@ -271,6 +273,23 @@ def cursor_in_leading_ws(cli): def _indent_buffer(event): event.current_buffer.insert_text(' ' * 4) + if sys.platform == 'win32': + from IPython.lib.clipboard import (ClipboardEmpty, + win32_clipboard_get, tkinter_clipboard_get) + @kbmanager.registry.add_binding(Keys.ControlV, + filter=(HasFocus(DEFAULT_BUFFER) & ~ViMode())) + def _paste(event): + try: + text = win32_clipboard_get() + except TryNext: + try: + text = tkinter_clipboard_get() + except (TryNext, ClipboardEmpty): + return + except ClipboardEmpty: + return + event.current_buffer.insert_text(text) + # Pre-populate history from IPython's history database history = InMemoryHistory() last_cell = u"" From c6b6dd132dd6cdf304792a309cb7ece809d3e158 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 14 Jun 2016 14:38:47 -0700 Subject: [PATCH 0444/4859] Fix test failing because of extra newline. --- IPython/core/tests/test_oinspect.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index caa4c0186da..3c00efbed99 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -283,7 +283,7 @@ def test_info(): nt.assert_equal(i['source'], None) nt.assert_true(i['isclass']) _self_py2 = '' if py3compat.PY3 else 'self, ' - nt.assert_equal(i['init_definition'], "Call(%sx, y=1)\n" % _self_py2) + nt.assert_equal(i['init_definition'], "Call(%sx, y=1)" % _self_py2) nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) i = inspector.info(Call, detail_level=1) @@ -310,12 +310,12 @@ def test_info(): def test_class_signature(): info = inspector.info(HasSignature, 'HasSignature') - nt.assert_equal(info['init_definition'], "HasSignature(test)\n") + nt.assert_equal(info['init_definition'], "HasSignature(test)") nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__) def test_info_awkward(): # Just test that this doesn't throw an error. - i = inspector.info(Awkward()) + inspector.info(Awkward()) def test_bool_raise(): inspector.info(NoBoolCall()) From f7eb09d9b857de0bcfa3bd2fd9d9662d912aebee Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 14 Jun 2016 15:37:20 -0700 Subject: [PATCH 0445/4859] 'restore formatting' --- IPython/core/oinspect.py | 74 +++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 28 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 7da59a28093..0c6ca69b5a8 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -593,13 +593,29 @@ def _mime_format(self, text, formatter=None): else: return dict(defaults, **formatted) + + def format_mime(self, bundle): + + text_plain = bundle['text/plain'] + + text = '' + heads, bodies = list(zip(*text_plain)) + _len = max(len(h) for h in heads) + + for head, body in zip(heads, bodies): + delim = '\n' if '\n' in body else ' ' + text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n' + + bundle['text/plain'] = text + return bundle + def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0): """Retrieve an info dict and format it.""" info = self._info(obj, oname=oname, info=info, detail_level=detail_level) - mime = { - 'text/plain': '', + _mime = { + 'text/plain': [], 'text/html': '', } @@ -607,7 +623,7 @@ def append_field(bundle, title, key, formatter=None): field = info[key] if field is not None: formatted_field = self._mime_format(field, formatter) - bundle['text/plain'] += self.__head(title + ':') + '\n' + formatted_field['text/plain'] + '\n' + bundle['text/plain'].append((title, formatted_field['text/plain'])) bundle['text/html'] += '

' + title + '

\n' + formatted_field['text/html'] + '\n' def code_formatter(text): @@ -617,59 +633,61 @@ def code_formatter(text): } if info['isalias']: - append_field(mime, 'Repr', 'string_form') + append_field(_mime, 'Repr', 'string_form') elif info['ismagic']: if detail_level > 0: - append_field(mime, 'Source', 'source', code_formatter) + append_field(_mime, 'Source', 'source', code_formatter) else: - append_field(mime, 'Docstring', 'docstring', formatter) - append_field(mime, 'File', 'file') + append_field(_mime, 'Docstring', 'docstring', formatter) + append_field(_mime, 'File', 'file') elif info['isclass'] or is_simple_callable(obj): # Functions, methods, classes - append_field(mime, 'Signature', 'definition', code_formatter) - append_field(mime, 'Init signature', 'init_definition', code_formatter) + append_field(_mime, 'Signature', 'definition', code_formatter) + append_field(_mime, 'Init signature', 'init_definition', code_formatter) if detail_level > 0: - append_field(mime, 'Source', 'source', code_formatter) + append_field(_mime, 'Source', 'source', code_formatter) else: - append_field(mime, 'Docstring', 'docstring', formatter) - append_field(mime, 'Init docstring', 'init_docstring', formatter) + append_field(_mime, 'Docstring', 'docstring', formatter) + append_field(_mime, 'Init docstring', 'init_docstring', formatter) - append_field(mime, 'File', 'file') - append_field(mime, 'Type', 'type_name') + append_field(_mime, 'File', 'file') + append_field(_mime, 'Type', 'type_name') else: # General Python objects - append_field(mime, 'Type', 'type_name') + append_field(_mime, 'Type', 'type_name') # Base class for old-style instances if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']: - append_field(mime, 'Base Class', 'base_class') + append_field(_mime, 'Base Class', 'base_class') - append_field(mime, 'String form', 'string_form') + append_field(_mime, 'String form', 'string_form') # Namespace if info['namespace'] != 'Interactive': - append_field(mime, 'Namespace', 'namespace') + 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, 'Length', 'length') + append_field(_mime, 'File', 'file'), + append_field(_mime, 'Signature', 'definition', code_formatter) # Source or docstring, depending on detail level and whether # source found. if detail_level > 0: - append_field(mime, 'Source', 'source', code_formatter) + append_field(_mime, 'Source', 'source', code_formatter) else: - append_field(mime, 'Docstring', 'docstring', formatter) + append_field(_mime, 'Docstring', 'docstring', formatter) + + 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) + - 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 mime + return self.format_mime(_mime) def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True): """Show detailed information about an object. From d50b7c0ba4fd72f668ba1d8cc8328d0efce88991 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 15 Jun 2016 12:55:11 +0200 Subject: [PATCH 0446/4859] get signature from init if top-level signature fails this shouldn't be necessary on most classes (arguably ever), but it appears to be for builtins (int, list). --- IPython/core/oinspect.py | 13 ++++++++++--- IPython/core/tests/test_oinspect.py | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 0c6ca69b5a8..47c2a9e4498 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -848,20 +848,27 @@ def _info(self, obj, oname='', info=None, detail_level=0): except AttributeError: init_def = None - if init_def: - out['init_definition'] = init_def - # get the __init__ docstring try: obj_init = obj.__init__ except AttributeError: init_ds = None else: + if init_def is None: + # Get signature from init if top-level sig failed. + # Can happen for built-in types (list, etc.). + try: + init_def = self._getdef(obj_init, oname) + except AttributeError: + pass init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None + if init_def: + out['init_definition'] = init_def + if init_ds: out['init_docstring'] = init_ds diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index 3c00efbed99..eb753f1f758 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -419,15 +419,34 @@ def test_pdef(): def foo(): pass inspector.pdef(foo, 'foo') + def test_pinfo_nonascii(): # See gh-1177 from . import nonascii2 ip.user_ns['nonascii2'] = nonascii2 ip._inspect('pinfo', 'nonascii2', detail_level=1) + def test_pinfo_magic(): with AssertPrints('Docstring:'): ip._inspect('pinfo', 'lsmagic', detail_level=0) with AssertPrints('Source:'): ip._inspect('pinfo', 'lsmagic', detail_level=1) + + +def test_init_colors(): + # ensure colors are not present in signature info + info = inspector.info(HasSignature) + init_def = info['init_definition'] + nt.assert_not_in('[0m', init_def) + + +def test_builtin_init(): + info = inspector.info(list) + init_def = info['init_definition'] + # Python < 3.4 can't get init definition from builtins, + # but still exercise the inspection in case of error-raising bugs. + if sys.version_info >= (3,4): + nt.assert_is_not_none(init_def) + From b3314be794c59c77da38017980d13e8fb456974d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 15 Jun 2016 17:55:45 +0100 Subject: [PATCH 0447/4859] Replace tab with 4*space when inserting pasted text --- IPython/terminal/ptshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index 109ede9693e..27f5ddcf88b 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -288,7 +288,7 @@ def _paste(event): return except ClipboardEmpty: return - event.current_buffer.insert_text(text) + event.current_buffer.insert_text(text.replace('\t', ' ' * 4)) # Pre-populate history from IPython's history database history = InMemoryHistory() From 6651c22cf224081120b7cbc43661713e133502a5 Mon Sep 17 00:00:00 2001 From: klonuo Date: Wed, 15 Jun 2016 19:23:15 +0200 Subject: [PATCH 0448/4859] Integrate windows unicode console --- IPython/terminal/ptshell.py | 3 +++ setup.py | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py index c20ecd3536c..8c41af7a2d1 100644 --- a/IPython/terminal/ptshell.py +++ b/IPython/terminal/ptshell.py @@ -368,7 +368,10 @@ def init_io(self): if sys.platform not in {'win32', 'cli'}: return + import win_unicode_console import colorama + + win_unicode_console.enable() colorama.init() # For some reason we make these wrappers around stdout/stderr. diff --git a/setup.py b/setup.py index c80bfa92390..09f15404ea3 100755 --- a/setup.py +++ b/setup.py @@ -209,7 +209,7 @@ 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'], + ':sys_platform == "win32"': ['colorama', 'win_unicode_console'], 'test:python_version == "2.7"': ['mock'], }) # FIXME: re-specify above platform dependencies for pip < 6 From b24b774f48906c35aa27e5e15e1dd310d6933694 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 15 Jun 2016 11:08:53 -0700 Subject: [PATCH 0449/4859] Hide the global `quit` from ipdb smart command. --- IPython/core/debugger.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 115e0aacdcf..bc3ba778986 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -259,7 +259,15 @@ def parseline(self, line): # "Smart command mode" from pdb++: don't execute commands if a variable # with the same name exists. cmd, arg, newline = super(Pdb, self).parseline(line) - if cmd in self.curframe.f_globals or cmd in self.curframe.f_locals: + # Fix for #9611: Do not trigger smart command if the command is `exit` + # or `quit` and it would resolve to their *global* value (the + # `ExitAutocall` object). Just checking that it is not present in the + # locals dict is not enough as locals and globals match at the + # toplevel. + if ((cmd in self.curframe.f_locals or cmd in self.curframe.f_globals) + and not (cmd in ["exit", "quit"] + and (self.curframe.f_locals is self.curframe.f_globals + or cmd not in self.curframe.f_locals))): return super(Pdb, self).parseline("!" + line) return super(Pdb, self).parseline(line) From fe24e6698904c6f3b069513d1d5659f971a6860e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 14:05:20 -0700 Subject: [PATCH 0450/4859] Pin prompt_toolkit to >=1.0.1 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index c80bfa92390..78313ed1e38 100755 --- a/setup.py +++ b/setup.py @@ -196,7 +196,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets>=4.2', - 'prompt_toolkit>=1.0.0,<2.0.0', + 'prompt_toolkit>=1.0.1,<2.0.0', 'pygments', ] From 9c1bc3e879133f8153f46e161e71f88d1b5d4bdb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 14:13:59 -0700 Subject: [PATCH 0451/4859] Remove non-issues now that ptk 1.0.1 is out. --- docs/source/whatsnew/version5.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 50cf5384dbb..4c604840826 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -99,15 +99,8 @@ Known Issues: :ghissue:`9587` and :ghissue:`9401`. In terminal there is no practical way to distinguish these key sequences from a normal new line return. - - Dialog completion pop up even with a single completion. Cf :ghissue:`9540`. This - would automatically be resolved with the next minor revision of - ``prompt_toolkit`` - - ``PageUp`` and ``pageDown`` do not move through completion menu. - - Custom prompt cannot make use of custom invisible escape sequences. This - will be automatically resolved with next version of Prompt Toolkit - - Color styles might not adapt to terminal emulator themes. This will need new version of Pygments to be released, and can be mitigated with custom themes. From 2436f9bd9d44d2b772aca672249013a04eda11db Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 8 Jun 2016 11:13:25 +0200 Subject: [PATCH 0452/4859] undeprecate terminal.interactiveshell move terminal.ptshell to terminal.interactiveshell, since it is the new implementation of the class. The deprecation was there while the readline implementation remained, but there is no need for it now that there is just one implementation of TerminalInteractiveShell. --- IPython/core/interactiveshell.py | 10 +- IPython/terminal/embed.py | 5 +- IPython/terminal/interactiveshell.py | 578 ++++++++++++++++++++++++++- IPython/terminal/ipapp.py | 2 +- IPython/terminal/ptshell.py | 569 -------------------------- 5 files changed, 571 insertions(+), 593 deletions(-) delete mode 100644 IPython/terminal/ptshell.py diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index b5e52ceb643..3157d7c8c79 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -365,22 +365,22 @@ def _exiter_default(self): # deprecated prompt traits: prompt_in1 = Unicode('In [\\#]: ', - help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." + help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompt_in2 = Unicode(' .\\D.: ', - help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." + help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompt_out = Unicode('Out[\\#]: ', - help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." + help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly." ).tag(config=True) prompts_pad_left = Bool(True, - help="Deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly." + help="Deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly." ).tag(config=True) @observe('prompt_in1', 'prompt_in2', 'prompt_out', 'prompt_pad_left') def _prompt_trait_changed(self, change): name = change['name'] - warn("InteractiveShell.{name} is deprecated since IPython 4.0 and ignored since 5.0, set IPython.terminal.ptshell.TerminalInteractiveShell.prompts object directly.".format( + warn("InteractiveShell.{name} is deprecated since IPython 4.0 and ignored since 5.0, set TerminalInteractiveShell.prompts object directly.".format( name=name) ) # protect against weird cases where self.config may not exist: diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 9ada31cf18b..275cacea8d2 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -13,9 +13,8 @@ from IPython.core import ultratb, compilerop from IPython.core.magic import Magics, magics_class, line_magic -from IPython.core.interactiveshell import DummyMod -from IPython.core.interactiveshell import InteractiveShell -from IPython.terminal.ptshell import TerminalInteractiveShell +from IPython.core.interactiveshell import DummyMod, InteractiveShell +from IPython.terminal.interactiveshell import TerminalInteractiveShell from IPython.terminal.ipapp import load_default_config from traitlets import Bool, CBool, Unicode diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 5c89ca0c64b..85c3a899d4d 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -1,21 +1,569 @@ -# -*- coding: utf-8 -*- -"""DEPRECATED: old import location of TerminalInteractiveShell""" - -# Copyright (c) IPython Development Team. -# Distributed under the terms of the Modified BSD License. +"""IPython terminal interface using prompt_toolkit in place of readline""" +from __future__ import print_function +import os +import sys +import signal from warnings import warn -from IPython.utils.decorators import undoc -from .ptshell import TerminalInteractiveShell as PromptToolkitShell +from IPython.core.error import TryNext +from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC +from IPython.utils.py3compat import PY3, cast_unicode_py2, input +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 + +from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode +from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, + ViInsertMode, EmacsInsertMode, IsDone, HasCompletions) +from prompt_toolkit.filters.cli import ViMode +from prompt_toolkit.history import InMemoryHistory +from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout +from prompt_toolkit.interface import CommandLineInterface +from prompt_toolkit.key_binding.manager import KeyBindingManager +from prompt_toolkit.keys import Keys +from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor +from prompt_toolkit.styles import PygmentsStyle, DynamicStyle + +from pygments.styles import get_style_by_name, get_all_styles +from pygments.token import Token + +from .debugger import TerminalPdb, Pdb +from .magics import TerminalMagics +from .pt_inputhooks import get_inputhook_func +from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook +from .ptutils import IPythonPTCompleter, IPythonPTLexer + + +def get_default_editor(): + try: + ed = os.environ['EDITOR'] + if not PY3: + ed = ed.decode() + return ed + except KeyError: + pass + except UnicodeError: + warn("$EDITOR environment variable is not pure ASCII. Using platform " + "default editor.") + + if os.name == 'posix': + return 'vi' # the only one guaranteed to be there! + else: + return 'notepad' # same in Windows! + + +if sys.stdin and sys.stdout and sys.stderr: + _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty()) +else: + _is_tty = False + + +_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) + +class TerminalInteractiveShell(InteractiveShell): + colors_force = True + + space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' + 'to reserve for the completion menu' + ).tag(config=True) + + def _space_for_menu_changed(self, old, new): + self._update_layout() + + pt_cli = None + debugger_history = None + + simple_prompt = Bool(_use_simple_prompt, + help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. + + Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: + IPython own testing machinery, and emacs inferior-shell integration through elpy. + + This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` + environment variable is set, or the current terminal is not a tty. + + """ + ).tag(config=True) + + @property + def debugger_cls(self): + return Pdb if self.simple_prompt else TerminalPdb + + autoedit_syntax = Bool(False, + help="auto editing of files with syntax errors.", + ).tag(config=True) + + + confirm_exit = Bool(True, + help=""" + Set to confirm when you try to exit IPython with an EOF (Control-D + in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', + you can force a direct exit without any confirmation.""", + ).tag(config=True) + + editing_mode = Unicode('emacs', + help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", + ).tag(config=True) + + mouse_support = Bool(False, + help="Enable mouse support in the prompt" + ).tag(config=True) + + highlighting_style = Unicode('default', + help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) + ).tag(config=True) + + + @observe('highlighting_style') + def _highlighting_style_changed(self, change): + self._style = self._make_style_from_name(self.highlighting_style) + + highlighting_style_overrides = Dict( + help="Override highlighting format for specific tokens" + ).tag(config=True) + + editor = Unicode(get_default_editor(), + help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." + ).tag(config=True) + + prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True) + + prompts = Instance(Prompts) + + @default('prompts') + def _prompts_default(self): + return self.prompts_class(self) + + @observe('prompts') + def _(self, change): + self._update_layout() + + @default('displayhook_class') + def _displayhook_class_default(self): + return RichPromptDisplayHook + + term_title = Bool(True, + help="Automatically set the terminal title" + ).tag(config=True) + + display_completions_in_columns = Bool(False, + help="Display a multi column completion menu.", + ).tag(config=True) + + highlight_matching_brackets = Bool(True, + help="Highlight matching brackets .", + ).tag(config=True) + + @observe('term_title') + def init_term_title(self, change=None): + # Enable or disable the terminal title. + if self.term_title: + toggle_set_term_title(True) + set_term_title('IPython: ' + abbrev_cwd()) + else: + toggle_set_term_title(False) + + def init_display_formatter(self): + super(TerminalInteractiveShell, self).init_display_formatter() + # terminal only supports plain text + self.display_formatter.active_types = ['text/plain'] + + def init_prompt_toolkit_cli(self): + self._app = None + if self.simple_prompt: + # Fall back to plain non-interactive output for tests. + # This is very limited, and only accepts a single line. + def prompt(): + return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) + self.prompt_for_code = prompt + return + + kbmanager = KeyBindingManager.for_prompt() + insert_mode = ViInsertMode() | EmacsInsertMode() + # Ctrl+J == Enter, seemingly + @kbmanager.registry.add_binding(Keys.ControlJ, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + )) + def _(event): + b = event.current_buffer + d = b.document + + if b.complete_state: + cc = b.complete_state.current_completion + if cc: + b.apply_completion(cc) + else: + b.cancel_completion() + return + + if not (d.on_last_line or d.cursor_position_row >= d.line_count + - d.empty_line_count_at_the_end()): + b.newline() + return + + status, indent = self.input_splitter.check_complete(d.text + '\n') + + if (status != 'incomplete') and b.accept_action.is_returnable: + b.accept_action.validate_and_handle(event.cli, b) + else: + b.insert_text('\n' + (' ' * (indent or 0))) + + @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) + def _previous_history_or_previous_completion(event): + """ + Control-P in vi edit mode on readline is history next, unlike default prompt toolkit. + + If completer is open this still select previous completion. + """ + event.current_buffer.auto_up() + + @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) + def _next_history_or_next_completion(event): + """ + Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit. + + If completer is open this still select next completion. + """ + event.current_buffer.auto_down() + + @kbmanager.registry.add_binding(Keys.ControlG, filter=( + HasFocus(DEFAULT_BUFFER) & HasCompletions() + )) + def _dismiss_completion(event): + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + + @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) + def _reset_buffer(event): + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + else: + b.reset() + + @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) + def _reset_search_buffer(event): + if event.current_buffer.document.text: + event.current_buffer.reset() + else: + event.cli.push_focus(DEFAULT_BUFFER) + + supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) + + @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) + def _suspend_to_bg(event): + event.cli.suspend_to_background() + + @Condition + def cursor_in_leading_ws(cli): + before = cli.application.buffer.document.current_line_before_cursor + return (not before) or before.isspace() + + # Ctrl+I == Tab + @kbmanager.registry.add_binding(Keys.ControlI, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + & cursor_in_leading_ws + )) + def _indent_buffer(event): + event.current_buffer.insert_text(' ' * 4) + + if sys.platform == 'win32': + from IPython.lib.clipboard import (ClipboardEmpty, + win32_clipboard_get, tkinter_clipboard_get) + @kbmanager.registry.add_binding(Keys.ControlV, + filter=(HasFocus(DEFAULT_BUFFER) & ~ViMode())) + def _paste(event): + try: + text = win32_clipboard_get() + except TryNext: + try: + text = tkinter_clipboard_get() + except (TryNext, ClipboardEmpty): + return + except ClipboardEmpty: + return + event.current_buffer.insert_text(text.replace('\t', ' ' * 4)) + + # Pre-populate history from IPython's history database + history = InMemoryHistory() + last_cell = u"" + for __, ___, cell in self.history_manager.get_tail(self.history_load_length, + include_latest=True): + # Ignore blank lines and consecutive duplicates + cell = cell.rstrip() + if cell and (cell != last_cell): + history.append(cell) + + self._style = self._make_style_from_name(self.highlighting_style) + style = DynamicStyle(lambda: self._style) + + editing_mode = getattr(EditingMode, self.editing_mode.upper()) + + self._app = create_prompt_application( + editing_mode=editing_mode, + key_bindings_registry=kbmanager.registry, + history=history, + completer=IPythonPTCompleter(self.Completer), + enable_history_search=True, + style=style, + mouse_support=self.mouse_support, + **self._layout_options() + ) + self._eventloop = create_eventloop(self.inputhook) + self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop) + + def _make_style_from_name(self, name): + """ + Small wrapper that make an IPython compatible style from a style name + + We need that to add style for prompt ... etc. + """ + style_cls = get_style_by_name(name) + style_overrides = { + Token.Prompt: '#009900', + Token.PromptNum: '#00ff00 bold', + Token.OutPrompt: '#990000', + Token.OutPromptNum: '#ff0000 bold', + } + if name == 'default': + style_cls = get_style_by_name('default') + # The default theme needs to be visible on both a dark background + # and a light background, because we can't tell what the terminal + # looks like. These tweaks to the default theme help with that. + style_overrides.update({ + Token.Number: '#007700', + Token.Operator: 'noinherit', + Token.String: '#BB6622', + Token.Name.Function: '#2080D0', + Token.Name.Class: 'bold #2080D0', + Token.Name.Namespace: 'bold #2080D0', + }) + style_overrides.update(self.highlighting_style_overrides) + style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, + style_dict=style_overrides) + + return style + + def _layout_options(self): + """ + Return the current layout option for the current Terminal InteractiveShell + """ + return { + 'lexer':IPythonPTLexer(), + 'reserve_space_for_menu':self.space_for_menu, + 'get_prompt_tokens':self.prompts.in_prompt_tokens, + 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, + 'multiline':True, + 'display_completions_in_columns': self.display_completions_in_columns, + + # Highlight matching brackets, but only when this setting is + # enabled, and only when the DEFAULT_BUFFER has the focus. + 'extra_input_processors': [ConditionalProcessor( + processor=HighlightMatchingBracketProcessor(chars='[](){}'), + filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & + Condition(lambda cli: self.highlight_matching_brackets))], + } + + def _update_layout(self): + """ + Ask for a re computation of the application layout, if for example , + some configuration options have changed. + """ + if getattr(self, '._app', None): + self._app.layout = create_prompt_layout(**self._layout_options()) + + def prompt_for_code(self): + document = self.pt_cli.run( + pre_run=self.pre_prompt, reset_current_buffer=True) + return document.text + + def init_io(self): + if sys.platform not in {'win32', 'cli'}: + return + + import win_unicode_console + import colorama + + win_unicode_console.enable() + colorama.init() + + # For some reason we make these wrappers around stdout/stderr. + # For now, we need to reset them so all output gets coloured. + # https://github.com/ipython/ipython/issues/8669 + from IPython.utils import io + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) + + def init_magics(self): + super(TerminalInteractiveShell, self).init_magics() + self.register_magics(TerminalMagics) + + def init_alias(self): + # The parent class defines aliases that can be safely used with any + # frontend. + super(TerminalInteractiveShell, self).init_alias() + + # Now define aliases that only make sense on the terminal, because they + # need direct access to the console in a way that we can't emulate in + # GUI or web frontend + if os.name == 'posix': + for cmd in ['clear', 'more', 'less', 'man']: + self.alias_manager.soft_define_alias(cmd, cmd) -warn("Since IPython 5.0 `IPython.terminal.interactiveshell` is deprecated in favor of `IPython.terminal.ptshell`.", - DeprecationWarning) -@undoc -class TerminalInteractiveShell(PromptToolkitShell): def __init__(self, *args, **kwargs): - warn("Since IPython 5.0 this is a deprecated alias for IPython.terminal.ptshell.TerminalInteractiveShell. " - "The terminal interface of this class now uses prompt_toolkit instead of readline.", - DeprecationWarning, stacklevel=2) - PromptToolkitShell.__init__(self, *args, **kwargs) + super(TerminalInteractiveShell, self).__init__(*args, **kwargs) + self.init_prompt_toolkit_cli() + self.init_term_title() + self.keep_running = True + + self.debugger_history = InMemoryHistory() + + def ask_exit(self): + self.keep_running = False + + rl_next_input = None + + def pre_prompt(self): + if self.rl_next_input: + self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input) + self.rl_next_input = None + + def interact(self): + while self.keep_running: + print(self.separate_in, end='') + + try: + code = self.prompt_for_code() + except EOFError: + if (not self.confirm_exit) \ + or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): + self.ask_exit() + + else: + if code: + self.run_cell(code, store_history=True) + if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: + self.edit_syntax_error() + + def mainloop(self): + # An extra layer of protection in case someone mashing Ctrl-C breaks + # out of our internal code. + while True: + try: + self.interact() + break + except KeyboardInterrupt: + print("\nKeyboardInterrupt escaped interact()\n") + + if hasattr(self, '_eventloop'): + self._eventloop.close() + + _inputhook = None + def inputhook(self, context): + if self._inputhook is not None: + self._inputhook(context) + + def enable_gui(self, gui=None): + if gui: + self._inputhook = get_inputhook_func(gui) + else: + self._inputhook = None + + # Methods to support auto-editing of SyntaxErrors: + + def edit_syntax_error(self): + """The bottom half of the syntax error handler called in the main loop. + + Loop until syntax error is fixed or user cancels. + """ + + while self.SyntaxTB.last_syntax_error: + # copy and clear last_syntax_error + err = self.SyntaxTB.clear_err_state() + if not self._should_recompile(err): + return + try: + # may set last_syntax_error again if a SyntaxError is raised + self.safe_execfile(err.filename, self.user_ns) + except: + self.showtraceback() + else: + try: + with open(err.filename) as f: + # This should be inside a display_trap block and I + # think it is. + sys.displayhook(f.read()) + except: + self.showtraceback() + + def _should_recompile(self, e): + """Utility routine for edit_syntax_error""" + + if e.filename in ('', '', '', + '', '', + None): + return False + try: + if (self.autoedit_syntax and + not self.ask_yes_no( + 'Return to editor to correct syntax error? ' + '[Y/n] ', 'y')): + return False + except EOFError: + return False + + def int0(x): + try: + return int(x) + except TypeError: + return 0 + + # always pass integer line and offset values to editor hook + try: + self.hooks.fix_error_editor(e.filename, + int0(e.lineno), int0(e.offset), + e.msg) + except TryNext: + warn('Could not open editor') + return False + return True + + # Run !system commands directly, not through pipes, so terminal programs + # work correctly. + system = InteractiveShell.system_raw + + def auto_rewrite_input(self, cmd): + """Overridden from the parent class to use fancy rewriting prompt""" + if not self.show_rewritten_input: + return + + tokens = self.prompts.rewrite_prompt_tokens() + if self.pt_cli: + self.pt_cli.print_tokens(tokens) + print(cmd) + else: + prompt = ''.join(s for t, s in tokens) + print(prompt, cmd, sep='') + + _prompts_before = None + def switch_doctest_mode(self, mode): + """Switch prompts to classic for %doctest_mode""" + if mode: + self._prompts_before = self.prompts + self.prompts = ClassicPrompts(self) + elif self._prompts_before: + self.prompts = self._prompts_before + self._prompts_before = None + + +InteractiveShellABC.register(TerminalInteractiveShell) + +if __name__ == '__main__': + TerminalInteractiveShell.instance().interact() diff --git a/IPython/terminal/ipapp.py b/IPython/terminal/ipapp.py index 1d89a18f65b..8add4612638 100755 --- a/IPython/terminal/ipapp.py +++ b/IPython/terminal/ipapp.py @@ -32,7 +32,7 @@ InteractiveShellApp, shell_flags, shell_aliases ) from IPython.extensions.storemagic import StoreMagics -from .ptshell import TerminalInteractiveShell +from .interactiveshell import TerminalInteractiveShell from IPython.paths import get_ipython_dir from traitlets import ( Bool, List, Dict, default, observe, diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py deleted file mode 100644 index 85c3a899d4d..00000000000 --- a/IPython/terminal/ptshell.py +++ /dev/null @@ -1,569 +0,0 @@ -"""IPython terminal interface using prompt_toolkit in place of readline""" -from __future__ import print_function - -import os -import sys -import signal -from warnings import warn - -from IPython.core.error import TryNext -from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC -from IPython.utils.py3compat import PY3, cast_unicode_py2, input -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 - -from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, - ViInsertMode, EmacsInsertMode, IsDone, HasCompletions) -from prompt_toolkit.filters.cli import ViMode -from prompt_toolkit.history import InMemoryHistory -from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout -from prompt_toolkit.interface import CommandLineInterface -from prompt_toolkit.key_binding.manager import KeyBindingManager -from prompt_toolkit.keys import Keys -from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor -from prompt_toolkit.styles import PygmentsStyle, DynamicStyle - -from pygments.styles import get_style_by_name, get_all_styles -from pygments.token import Token - -from .debugger import TerminalPdb, Pdb -from .magics import TerminalMagics -from .pt_inputhooks import get_inputhook_func -from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook -from .ptutils import IPythonPTCompleter, IPythonPTLexer - - -def get_default_editor(): - try: - ed = os.environ['EDITOR'] - if not PY3: - ed = ed.decode() - return ed - except KeyError: - pass - except UnicodeError: - warn("$EDITOR environment variable is not pure ASCII. Using platform " - "default editor.") - - if os.name == 'posix': - return 'vi' # the only one guaranteed to be there! - else: - return 'notepad' # same in Windows! - - -if sys.stdin and sys.stdout and sys.stderr: - _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty()) -else: - _is_tty = False - - -_use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) - -class TerminalInteractiveShell(InteractiveShell): - colors_force = True - - space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' - 'to reserve for the completion menu' - ).tag(config=True) - - def _space_for_menu_changed(self, old, new): - self._update_layout() - - pt_cli = None - debugger_history = None - - simple_prompt = Bool(_use_simple_prompt, - help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. - - Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: - IPython own testing machinery, and emacs inferior-shell integration through elpy. - - This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` - environment variable is set, or the current terminal is not a tty. - - """ - ).tag(config=True) - - @property - def debugger_cls(self): - return Pdb if self.simple_prompt else TerminalPdb - - autoedit_syntax = Bool(False, - help="auto editing of files with syntax errors.", - ).tag(config=True) - - - confirm_exit = Bool(True, - help=""" - Set to confirm when you try to exit IPython with an EOF (Control-D - in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', - you can force a direct exit without any confirmation.""", - ).tag(config=True) - - editing_mode = Unicode('emacs', - help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", - ).tag(config=True) - - mouse_support = Bool(False, - help="Enable mouse support in the prompt" - ).tag(config=True) - - highlighting_style = Unicode('default', - help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) - ).tag(config=True) - - - @observe('highlighting_style') - def _highlighting_style_changed(self, change): - self._style = self._make_style_from_name(self.highlighting_style) - - highlighting_style_overrides = Dict( - help="Override highlighting format for specific tokens" - ).tag(config=True) - - editor = Unicode(get_default_editor(), - help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." - ).tag(config=True) - - prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True) - - prompts = Instance(Prompts) - - @default('prompts') - def _prompts_default(self): - return self.prompts_class(self) - - @observe('prompts') - def _(self, change): - self._update_layout() - - @default('displayhook_class') - def _displayhook_class_default(self): - return RichPromptDisplayHook - - term_title = Bool(True, - help="Automatically set the terminal title" - ).tag(config=True) - - display_completions_in_columns = Bool(False, - help="Display a multi column completion menu.", - ).tag(config=True) - - highlight_matching_brackets = Bool(True, - help="Highlight matching brackets .", - ).tag(config=True) - - @observe('term_title') - def init_term_title(self, change=None): - # Enable or disable the terminal title. - if self.term_title: - toggle_set_term_title(True) - set_term_title('IPython: ' + abbrev_cwd()) - else: - toggle_set_term_title(False) - - def init_display_formatter(self): - super(TerminalInteractiveShell, self).init_display_formatter() - # terminal only supports plain text - self.display_formatter.active_types = ['text/plain'] - - def init_prompt_toolkit_cli(self): - self._app = None - if self.simple_prompt: - # Fall back to plain non-interactive output for tests. - # This is very limited, and only accepts a single line. - def prompt(): - return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) - self.prompt_for_code = prompt - return - - kbmanager = KeyBindingManager.for_prompt() - insert_mode = ViInsertMode() | EmacsInsertMode() - # Ctrl+J == Enter, seemingly - @kbmanager.registry.add_binding(Keys.ControlJ, - filter=(HasFocus(DEFAULT_BUFFER) - & ~HasSelection() - & insert_mode - )) - def _(event): - b = event.current_buffer - d = b.document - - if b.complete_state: - cc = b.complete_state.current_completion - if cc: - b.apply_completion(cc) - else: - b.cancel_completion() - return - - if not (d.on_last_line or d.cursor_position_row >= d.line_count - - d.empty_line_count_at_the_end()): - b.newline() - return - - status, indent = self.input_splitter.check_complete(d.text + '\n') - - if (status != 'incomplete') and b.accept_action.is_returnable: - b.accept_action.validate_and_handle(event.cli, b) - else: - b.insert_text('\n' + (' ' * (indent or 0))) - - @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) - def _previous_history_or_previous_completion(event): - """ - Control-P in vi edit mode on readline is history next, unlike default prompt toolkit. - - If completer is open this still select previous completion. - """ - event.current_buffer.auto_up() - - @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) - def _next_history_or_next_completion(event): - """ - Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit. - - If completer is open this still select next completion. - """ - event.current_buffer.auto_down() - - @kbmanager.registry.add_binding(Keys.ControlG, filter=( - HasFocus(DEFAULT_BUFFER) & HasCompletions() - )) - def _dismiss_completion(event): - b = event.current_buffer - if b.complete_state: - b.cancel_completion() - - @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) - def _reset_buffer(event): - b = event.current_buffer - if b.complete_state: - b.cancel_completion() - else: - b.reset() - - @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) - def _reset_search_buffer(event): - if event.current_buffer.document.text: - event.current_buffer.reset() - else: - event.cli.push_focus(DEFAULT_BUFFER) - - supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) - - @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) - def _suspend_to_bg(event): - event.cli.suspend_to_background() - - @Condition - def cursor_in_leading_ws(cli): - before = cli.application.buffer.document.current_line_before_cursor - return (not before) or before.isspace() - - # Ctrl+I == Tab - @kbmanager.registry.add_binding(Keys.ControlI, - filter=(HasFocus(DEFAULT_BUFFER) - & ~HasSelection() - & insert_mode - & cursor_in_leading_ws - )) - def _indent_buffer(event): - event.current_buffer.insert_text(' ' * 4) - - if sys.platform == 'win32': - from IPython.lib.clipboard import (ClipboardEmpty, - win32_clipboard_get, tkinter_clipboard_get) - @kbmanager.registry.add_binding(Keys.ControlV, - filter=(HasFocus(DEFAULT_BUFFER) & ~ViMode())) - def _paste(event): - try: - text = win32_clipboard_get() - except TryNext: - try: - text = tkinter_clipboard_get() - except (TryNext, ClipboardEmpty): - return - except ClipboardEmpty: - return - event.current_buffer.insert_text(text.replace('\t', ' ' * 4)) - - # Pre-populate history from IPython's history database - history = InMemoryHistory() - last_cell = u"" - for __, ___, cell in self.history_manager.get_tail(self.history_load_length, - include_latest=True): - # Ignore blank lines and consecutive duplicates - cell = cell.rstrip() - if cell and (cell != last_cell): - history.append(cell) - - self._style = self._make_style_from_name(self.highlighting_style) - style = DynamicStyle(lambda: self._style) - - editing_mode = getattr(EditingMode, self.editing_mode.upper()) - - self._app = create_prompt_application( - editing_mode=editing_mode, - key_bindings_registry=kbmanager.registry, - history=history, - completer=IPythonPTCompleter(self.Completer), - enable_history_search=True, - style=style, - mouse_support=self.mouse_support, - **self._layout_options() - ) - self._eventloop = create_eventloop(self.inputhook) - self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop) - - def _make_style_from_name(self, name): - """ - Small wrapper that make an IPython compatible style from a style name - - We need that to add style for prompt ... etc. - """ - style_cls = get_style_by_name(name) - style_overrides = { - Token.Prompt: '#009900', - Token.PromptNum: '#00ff00 bold', - Token.OutPrompt: '#990000', - Token.OutPromptNum: '#ff0000 bold', - } - if name == 'default': - style_cls = get_style_by_name('default') - # The default theme needs to be visible on both a dark background - # and a light background, because we can't tell what the terminal - # looks like. These tweaks to the default theme help with that. - style_overrides.update({ - Token.Number: '#007700', - Token.Operator: 'noinherit', - Token.String: '#BB6622', - Token.Name.Function: '#2080D0', - Token.Name.Class: 'bold #2080D0', - Token.Name.Namespace: 'bold #2080D0', - }) - style_overrides.update(self.highlighting_style_overrides) - style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, - style_dict=style_overrides) - - return style - - def _layout_options(self): - """ - Return the current layout option for the current Terminal InteractiveShell - """ - return { - 'lexer':IPythonPTLexer(), - 'reserve_space_for_menu':self.space_for_menu, - 'get_prompt_tokens':self.prompts.in_prompt_tokens, - 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, - 'multiline':True, - 'display_completions_in_columns': self.display_completions_in_columns, - - # Highlight matching brackets, but only when this setting is - # enabled, and only when the DEFAULT_BUFFER has the focus. - 'extra_input_processors': [ConditionalProcessor( - processor=HighlightMatchingBracketProcessor(chars='[](){}'), - filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & - Condition(lambda cli: self.highlight_matching_brackets))], - } - - def _update_layout(self): - """ - Ask for a re computation of the application layout, if for example , - some configuration options have changed. - """ - if getattr(self, '._app', None): - self._app.layout = create_prompt_layout(**self._layout_options()) - - def prompt_for_code(self): - document = self.pt_cli.run( - pre_run=self.pre_prompt, reset_current_buffer=True) - return document.text - - def init_io(self): - if sys.platform not in {'win32', 'cli'}: - return - - import win_unicode_console - import colorama - - win_unicode_console.enable() - colorama.init() - - # For some reason we make these wrappers around stdout/stderr. - # For now, we need to reset them so all output gets coloured. - # https://github.com/ipython/ipython/issues/8669 - from IPython.utils import io - io.stdout = io.IOStream(sys.stdout) - io.stderr = io.IOStream(sys.stderr) - - def init_magics(self): - super(TerminalInteractiveShell, self).init_magics() - self.register_magics(TerminalMagics) - - def init_alias(self): - # The parent class defines aliases that can be safely used with any - # frontend. - super(TerminalInteractiveShell, self).init_alias() - - # Now define aliases that only make sense on the terminal, because they - # need direct access to the console in a way that we can't emulate in - # GUI or web frontend - if os.name == 'posix': - for cmd in ['clear', 'more', 'less', 'man']: - self.alias_manager.soft_define_alias(cmd, cmd) - - - def __init__(self, *args, **kwargs): - super(TerminalInteractiveShell, self).__init__(*args, **kwargs) - self.init_prompt_toolkit_cli() - self.init_term_title() - self.keep_running = True - - self.debugger_history = InMemoryHistory() - - def ask_exit(self): - self.keep_running = False - - rl_next_input = None - - def pre_prompt(self): - if self.rl_next_input: - self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input) - self.rl_next_input = None - - def interact(self): - while self.keep_running: - print(self.separate_in, end='') - - try: - code = self.prompt_for_code() - except EOFError: - if (not self.confirm_exit) \ - or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): - self.ask_exit() - - else: - if code: - self.run_cell(code, store_history=True) - if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: - self.edit_syntax_error() - - def mainloop(self): - # An extra layer of protection in case someone mashing Ctrl-C breaks - # out of our internal code. - while True: - try: - self.interact() - break - except KeyboardInterrupt: - print("\nKeyboardInterrupt escaped interact()\n") - - if hasattr(self, '_eventloop'): - self._eventloop.close() - - _inputhook = None - def inputhook(self, context): - if self._inputhook is not None: - self._inputhook(context) - - def enable_gui(self, gui=None): - if gui: - self._inputhook = get_inputhook_func(gui) - else: - self._inputhook = None - - # Methods to support auto-editing of SyntaxErrors: - - def edit_syntax_error(self): - """The bottom half of the syntax error handler called in the main loop. - - Loop until syntax error is fixed or user cancels. - """ - - while self.SyntaxTB.last_syntax_error: - # copy and clear last_syntax_error - err = self.SyntaxTB.clear_err_state() - if not self._should_recompile(err): - return - try: - # may set last_syntax_error again if a SyntaxError is raised - self.safe_execfile(err.filename, self.user_ns) - except: - self.showtraceback() - else: - try: - with open(err.filename) as f: - # This should be inside a display_trap block and I - # think it is. - sys.displayhook(f.read()) - except: - self.showtraceback() - - def _should_recompile(self, e): - """Utility routine for edit_syntax_error""" - - if e.filename in ('', '', '', - '', '', - None): - return False - try: - if (self.autoedit_syntax and - not self.ask_yes_no( - 'Return to editor to correct syntax error? ' - '[Y/n] ', 'y')): - return False - except EOFError: - return False - - def int0(x): - try: - return int(x) - except TypeError: - return 0 - - # always pass integer line and offset values to editor hook - try: - self.hooks.fix_error_editor(e.filename, - int0(e.lineno), int0(e.offset), - e.msg) - except TryNext: - warn('Could not open editor') - return False - return True - - # Run !system commands directly, not through pipes, so terminal programs - # work correctly. - system = InteractiveShell.system_raw - - def auto_rewrite_input(self, cmd): - """Overridden from the parent class to use fancy rewriting prompt""" - if not self.show_rewritten_input: - return - - tokens = self.prompts.rewrite_prompt_tokens() - if self.pt_cli: - self.pt_cli.print_tokens(tokens) - print(cmd) - else: - prompt = ''.join(s for t, s in tokens) - print(prompt, cmd, sep='') - - _prompts_before = None - def switch_doctest_mode(self, mode): - """Switch prompts to classic for %doctest_mode""" - if mode: - self._prompts_before = self.prompts - self.prompts = ClassicPrompts(self) - elif self._prompts_before: - self.prompts = self._prompts_before - self._prompts_before = None - - -InteractiveShellABC.register(TerminalInteractiveShell) - -if __name__ == '__main__': - TerminalInteractiveShell.instance().interact() From a3332387eea89daaecd9400c5555657132a2cd9c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 14:27:47 -0700 Subject: [PATCH 0453/4859] Add a warning things have been moved back. --- IPython/terminal/ptshell.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 IPython/terminal/ptshell.py diff --git a/IPython/terminal/ptshell.py b/IPython/terminal/ptshell.py new file mode 100644 index 00000000000..666d3c5b514 --- /dev/null +++ b/IPython/terminal/ptshell.py @@ -0,0 +1,8 @@ +raise DeprecationWarning("""DEPRECATED: + +After Popular request and decision from the BDFL: +`IPython.terminal.ptshell` has been moved back to `IPython.terminal.interactiveshell` +during the beta cycle (after IPython 5.0.beta3) Sorry about that. + +This file will be removed in 5.0 rc or final. +""") From b67f2e8aac8f4124e514bd3021b7ed9c0932554e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 14:41:26 -0700 Subject: [PATCH 0454/4859] Add extra documentation in the changelog. --- docs/source/whatsnew/version5.rst | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 50cf5384dbb..afbee655f78 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -34,12 +34,26 @@ that same event. Integration with pydb has been removed since pydb development has been stopped since 2012, and pydb is not installable from PyPI -IPython 5.0 now uses prompt_toolkit, so any setting that affects ``readline`` will -have no effect, and has likely been replaced by a configuration option on -IPython itself. -the `PromptManager` class have been removed, and the prompt machinery simplified. -See `TerminalINteractiveShell.prompts` configurable for how to setup your prompts. + +Replacement of readline and TerminalInteractiveShell +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +IPython 5.0 now uses ``prompt_toolkit``. The +``IPtyhon.terminal.interactiveshell.TerminalInteractiveShell`` now uses +``prompt_toolkit``. It is an almost complete rewrite, so many settings have +thus changed or disappeared. The class keep the same name to avoid breaking +user configuration for the options which names is unchanged. + + +A particular side effect of not using `readline` anymore is that `.inputrc` +settings are note effective anymore. Options having similar effects have likely +been replaced by a configuration option on IPython itself (e.g: vi input mode). + +The `PromptManager` class have been removed, and the prompt machinery simplified. +See `TerminalInteractiveShell.prompts` configurable for how to setup your prompts. + + From 56be45c4ea6e72baa7f37a502a36aa48231e4da3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 14:48:00 -0700 Subject: [PATCH 0455/4859] Extra information on changelog. --- docs/source/whatsnew/version5.rst | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index afbee655f78..ac084a5f923 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -36,8 +36,8 @@ since 2012, and pydb is not installable from PyPI -Replacement of readline and TerminalInteractiveShell -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Replacement of readline in TerminalInteractiveShell and PDB +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IPython 5.0 now uses ``prompt_toolkit``. The ``IPtyhon.terminal.interactiveshell.TerminalInteractiveShell`` now uses @@ -45,14 +45,23 @@ IPython 5.0 now uses ``prompt_toolkit``. The thus changed or disappeared. The class keep the same name to avoid breaking user configuration for the options which names is unchanged. - -A particular side effect of not using `readline` anymore is that `.inputrc` -settings are note effective anymore. Options having similar effects have likely -been replaced by a configuration option on IPython itself (e.g: vi input mode). +The usage of ``prompt_toolkit`` is accompanied by a complete removal of all +code, using ``readline``. A particular effect of not using `readline` anymore +is that `.inputrc` settings are note effective anymore. Options having similar +effects have likely been replaced by a configuration option on IPython itself +(e.g: vi input mode). The `PromptManager` class have been removed, and the prompt machinery simplified. See `TerminalInteractiveShell.prompts` configurable for how to setup your prompts. +.. note:: + + During developement and beta cycle, ``TerminalInteractiveShell`` was + temporarly moved to ``IPtyhon.terminal.ptshell``. + + +Most of the above remarks also affect `IPython.core.debugger.Pdb`, the `%debug` +and `%pdb` magic which do not use readline anymore either. From 0668587b74996a0c1bb043687902c5d0738e177a Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 15:47:30 -0700 Subject: [PATCH 0456/4859] Extend the completion layout to use a third readlinelike option. The `display_completions_in_columns` thus becomes deprecated, and the Boolean is replaced by an Enum: `column`, `multicolumn`, `readlinelike` which give us more freedom to implement extra-layout later. --- IPython/terminal/interactiveshell.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 85c3a899d4d..a8d496d8750 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -11,7 +11,7 @@ from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 +from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, @@ -24,6 +24,7 @@ from prompt_toolkit.keys import Keys from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor from prompt_toolkit.styles import PygmentsStyle, DynamicStyle +from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline from pygments.styles import get_style_by_name, get_all_styles from pygments.token import Token @@ -147,10 +148,17 @@ def _displayhook_class_default(self): help="Automatically set the terminal title" ).tag(config=True) - display_completions_in_columns = Bool(False, - help="Display a multi column completion menu.", + display_completions_in_columns = Bool(None, + help="Display a multi column completion menu.", allow_none=True ).tag(config=True) + @observe('display_completions_in_columns') + def _display_completions_in_columns_changed(self, new): + raise DeprecationWarning("The `display_completions_in_columns` Boolean has been replaced by the enum `display_completions`" + "with the following acceptable value: 'column', 'multicolumn','readlinelike'. ") + + display_completions = Enum(('column', 'multicolumn','readlinelike'), default_value='multicolumn').tag(config=True) + highlight_matching_brackets = Bool(True, help="Highlight matching brackets .", ).tag(config=True) @@ -273,6 +281,18 @@ def cursor_in_leading_ws(cli): def _indent_buffer(event): event.current_buffer.insert_text(' ' * 4) + + if self.display_completions == 'readlinelike': + @kbmanager.registry.add_binding(Keys.ControlI, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + & ~cursor_in_leading_ws + )) + def _disaply_compl(ev): + display_completions_like_readline(ev) + + if sys.platform == 'win32': from IPython.lib.clipboard import (ClipboardEmpty, win32_clipboard_get, tkinter_clipboard_get) @@ -360,7 +380,7 @@ def _layout_options(self): 'get_prompt_tokens':self.prompts.in_prompt_tokens, 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, 'multiline':True, - 'display_completions_in_columns': self.display_completions_in_columns, + 'display_completions_in_columns': (self.display_completions == 'multicolumn'), # Highlight matching brackets, but only when this setting is # enabled, and only when the DEFAULT_BUFFER has the focus. From fc9fa9dc7b381a61aa20146f114a088dc142d674 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 15 Jun 2016 16:26:01 -0700 Subject: [PATCH 0457/4859] Update release instructions. Closes #9535 --- docs/source/coredev/release_process.rst | 45 ++++++++++++++----------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 4bba61b74a9..d595f0caff0 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -76,18 +76,8 @@ of any file that could be problematic. previous build attempts. - -4. Run the `tools/build_release` script ---------------------------------------- - -Running `tools/build_release` does all the file checking and building that -the real release script will do. This makes test installations, checks that -the build procedure runs OK, and tests other steps in the release process. - -We encourage creating a test build of the docs as well. - -5. Create and push the new tag ------------------------------- +4. Update the release version number +------------------------------------ Edit `IPython/core/release.py` to have the current version. @@ -98,9 +88,24 @@ Make sure the version number matches pep440, in particular, `rc` and `beta` are not separated by `.` or the `sdist` and `bdist` will appear as different releases. For example, a valid version number for a release candidate (rc) release is: ``1.3rc1``. Notice that there is no separator between the '3' and -the 'r'. +the 'r'. Check the environment variable `$VERSION` as well. +5. Run the `tools/build_release` script +--------------------------------------- + +Running `tools/build_release` does all the file checking and building that +the real release script will do. This makes test installations, checks that +the build procedure runs OK, and tests other steps in the release process. + +The `build_release` script will in particular verify that the version number +match PEP 440, in order to avoid surprise at the time of build upload. + +We encourage creating a test build of the docs as well. + +6. Create and push the new tag +------------------------------ + Commit the changes to release.py:: git commit -am "release $VERSION" @@ -116,7 +121,7 @@ Update release.py back to `x.y-dev` or `x.y-maint`, and push:: git commit -am "back to development" git push origin $BRANCH -6. Get a fresh clone +7. Get a fresh clone -------------------- Get a fresh clone of the tag for building the release:: @@ -124,7 +129,7 @@ Get a fresh clone of the tag for building the release:: cd /tmp git clone --depth 1 https://github.com/ipython/ipython.git -b "$VERSION" -7. Run the release script +8. Run the release script ------------------------- Run the `release` script, this step requires having a current wheel, Python >=3.4 and Python 2.7.:: @@ -147,7 +152,7 @@ dist/*`) manually to actually upload on PyPI. Unlike setuptools, twine is able to upload packages over SSL. -8. Draft a short release announcement +9. Draft a short release announcement ------------------------------------- The announcement should include: @@ -158,8 +163,8 @@ The announcement should include: Post the announcement to the mailing list and or blog, and link from Twitter. -9. Update milestones on GitHub ------------------------------- +10. Update milestones on GitHub +------------------------------- These steps will bring milestones up to date: @@ -167,7 +172,7 @@ These steps will bring milestones up to date: - open a new milestone for the next release (x, y+1), if the milestone doesn't exist already -10. Update the IPython website +11. Update the IPython website ------------------------------ The IPython website should document the new release: @@ -176,7 +181,7 @@ The IPython website should document the new release: - update current version and download links - update links on the documentation page (especially if a major release) -11. Celebrate! +12. Celebrate! -------------- Celebrate the release and please thank the contributors for their work. Great From 0b33ac681ee28f5d48cdd3d548567dbe88fbf621 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 16 Jun 2016 09:22:47 -0700 Subject: [PATCH 0458/4859] Remove readline mention, fit IPython typo. --- IPython/terminal/interactiveshell.py | 2 +- docs/source/whatsnew/version5.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index a8d496d8750..4a1dcb03d6d 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -1,4 +1,4 @@ -"""IPython terminal interface using prompt_toolkit in place of readline""" +"""IPython terminal interface using prompt_toolkit""" from __future__ import print_function import os diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index ac084a5f923..14f3faf6201 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -40,7 +40,7 @@ Replacement of readline in TerminalInteractiveShell and PDB ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ IPython 5.0 now uses ``prompt_toolkit``. The -``IPtyhon.terminal.interactiveshell.TerminalInteractiveShell`` now uses +``IPython.terminal.interactiveshell.TerminalInteractiveShell`` now uses ``prompt_toolkit``. It is an almost complete rewrite, so many settings have thus changed or disappeared. The class keep the same name to avoid breaking user configuration for the options which names is unchanged. From 3bf3dfdddf4343fcdc1ead5a1a2627774088c722 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 16 Jun 2016 09:20:42 -0700 Subject: [PATCH 0459/4859] Clarify intent of option removal post Beta. --- IPython/terminal/interactiveshell.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 4a1dcb03d6d..34191a7cd6b 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -148,8 +148,9 @@ def _displayhook_class_default(self): help="Automatically set the terminal title" ).tag(config=True) + # Leaving that for beta/rc tester, shoudl remove for 5.0.0 final. display_completions_in_columns = Bool(None, - help="Display a multi column completion menu.", allow_none=True + help="DEPRECATED", allow_none=True ).tag(config=True) @observe('display_completions_in_columns') From 1b487f7af0d2da10a1fca1d0425c86b32b077a9c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 16 Jun 2016 15:25:59 -0700 Subject: [PATCH 0460/4859] Release 5.0.0b4 What's new since b3: Small delay since last beta release, sorry about that, a few reasons though: - We / I slowed down a bit on the beta release pace, there was a few bugs/issues/User interface annoyance that needed a new version of prompt_toolkit to be released, there was no reasons to make extra-beta without this new version released. - We backed-down on some changes on which we had a few disagrements (more below). - I got sick, and had to catch up with backlog. Anyway, Jonathan release prompt_toolkit 1.0.1 and 1.0.2, so even if you don't try this new beta, upgrading prompt_toolkit will fix some of your issues. == Move back `TerminalInteractiveShell` to it's old place. This is a bigger breaking change since 5.0b3, the `TerminalInteractiveshell` moved back from `IPython.terminal.ptshell` to `IPython.terminal.interactiveshell`, if you've updated your project recently to adapt to this change we're sorry, but despite the fact that the version pre 5.0 and post 5.0 are relatively different the cost of conditional import for project depending on us appeared to be too high. So it's now easier to migrate from 4.0 to 5.0 as the class have the same name, and same location == Option name and default changed. `TerminalInteractiveShell.display_completions_in_column` is now gone. It was not present on 4.x so no API breakage there, and is now replaced by `TerminalInteractiveShell.display_completions` and is a enum that gained a 3rd mode for the completer: `readlinelike` for those of you that regret readline. This give us more flexibility for further options. Would appreciate testing of this new layout from vi user. The two other mode now being `column` and `multicolumn`. By popular request, `multicolumn` is not the default value for the previous option. == bug fixed: - quit/exit broken in ipdb - Copy/Past broken on windowm - Unicode broken on windows - function signature garbled when using `object?` - issue with paging text with `?` - completer could get stuck. See the complete git log for more informations. --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 8272c2efc48..2db15aff3c4 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'b3' +_version_extra = 'b4' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From d87397a56c5e3b3fcb898b9171b16ff79a814cd2 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 16 Jun 2016 15:33:10 -0700 Subject: [PATCH 0461/4859] back to dev --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 2db15aff3c4..f2486977c89 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'b4' +# _version_extra = 'b4' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 365c8ac6da9630c8ad0a306a989bc9ce2d0923d3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 16 Jun 2016 16:07:41 -0700 Subject: [PATCH 0462/4859] Fix interact() and mainloop() for backward compat. --- IPython/terminal/interactiveshell.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 4a1dcb03d6d..5e33966403f 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -35,6 +35,8 @@ from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer +DISPLAY_BANNER_DEPRECATED = object() + def get_default_editor(): try: @@ -455,7 +457,11 @@ def pre_prompt(self): self.pt_cli.application.buffer.text = cast_unicode_py2(self.rl_next_input) self.rl_next_input = None - def interact(self): + def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED): + + if display_banner is not DISPLAY_BANNER_DEPRECATED: + warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) + while self.keep_running: print(self.separate_in, end='') @@ -472,9 +478,11 @@ def interact(self): if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: self.edit_syntax_error() - def mainloop(self): + def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED): # An extra layer of protection in case someone mashing Ctrl-C breaks # out of our internal code. + if display_banner is not DISPLAY_BANNER_DEPRECATED: + warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) while True: try: self.interact() From c90b7b281e4c361083071f612c702af32e1852b8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 17 Jun 2016 12:32:33 +0100 Subject: [PATCH 0463/4859] Fix Makefile for generating config docs --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index b804b515337..5f05864680e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -76,7 +76,7 @@ source/interactive/magics-generated.txt: autogen_magics.py autoconfig: source/config/options/config-generated.txt -source/config/options/generated: +source/config/options/config-generated.txt: $(PYTHON) autogen_config.py @echo "Created docs for config options" From 581727bb5329f227cd6750a47bae92eedc1b0c00 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 17 Jun 2016 10:01:36 -0700 Subject: [PATCH 0464/4859] Fix quoting tests on Windows. Quoting should be done with double quotes, not single quotes. --- IPython/core/tests/test_completer.py | 60 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index da7b538b00c..8211dd0b9cc 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -37,37 +37,37 @@ def greedy_completion(): def test_protect_filename(): if sys.platform == 'win32': - pairs = [ ('abc','abc'), - (' abc',"' abc'"), - ('a bc',"'a bc'"), - ('a bc',"'a bc'"), - (' bc',"' bc'"), - ] + pairs = [('abc','abc'), + (' abc','" abc"'), + ('a bc','"a bc"'), + ('a bc','"a bc"'), + (' bc','" bc"'), + ] else: - pairs = [ ('abc','abc'), - (' abc',r'\ abc'), - ('a bc',r'a\ bc'), - ('a bc',r'a\ \ bc'), - (' bc',r'\ \ bc'), - # On posix, we also protect parens and other special characters - ('a(bc',r'a\(bc'), - ('a)bc',r'a\)bc'), - ('a( )bc',r'a\(\ \)bc'), - ('a[1]bc', r'a\[1\]bc'), - ('a{1}bc', r'a\{1\}bc'), - ('a#bc', r'a\#bc'), - ('a?bc', r'a\?bc'), - ('a=bc', r'a\=bc'), - ('a\\bc', r'a\\bc'), - ('a|bc', r'a\|bc'), - ('a;bc', r'a\;bc'), - ('a:bc', r'a\:bc'), - ("a'bc", r"a\'bc"), - ('a*bc', r'a\*bc'), - ('a"bc', r'a\"bc'), - ('a^bc', r'a\^bc'), - ('a&bc', r'a\&bc'), - ] + pairs = [('abc','abc'), + (' abc',r'\ abc'), + ('a bc',r'a\ bc'), + ('a bc',r'a\ \ bc'), + (' bc',r'\ \ bc'), + # On posix, we also protect parens and other special characters. + ('a(bc',r'a\(bc'), + ('a)bc',r'a\)bc'), + ('a( )bc',r'a\(\ \)bc'), + ('a[1]bc', r'a\[1\]bc'), + ('a{1}bc', r'a\{1\}bc'), + ('a#bc', r'a\#bc'), + ('a?bc', r'a\?bc'), + ('a=bc', r'a\=bc'), + ('a\\bc', r'a\\bc'), + ('a|bc', r'a\|bc'), + ('a;bc', r'a\;bc'), + ('a:bc', r'a\:bc'), + ("a'bc", r"a\'bc"), + ('a*bc', r'a\*bc'), + ('a"bc', r'a\"bc'), + ('a^bc', r'a\^bc'), + ('a&bc', r'a\&bc'), + ] # run the actual tests for s1, s2 in pairs: s1p = completer.protect_filename(s1) From 2277b4aee6f35bcca599e5e5c9888555e0c16cd1 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 17 Jun 2016 15:13:08 -0700 Subject: [PATCH 0465/4859] Add test that quit and exit work in debugger. Closes #9625 Testing is difficult to do without doctests, and yielding 2 test functions does not seem to work as the docstring seem to not be found and the test does reliably pass even when it should not. --- IPython/core/tests/test_debugger.py | 49 ++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index 75b3d41e77c..5db9a7ce086 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -69,7 +69,7 @@ def test_longer_repr(): nt.assert_equal(trepr(a), a_trunc) # The creation of our tracer modifies the repr module's repr function # in-place, since that global is used directly by the stdlib's pdb module. - t = debugger.Tracer() + debugger.Tracer() nt.assert_equal(trepr(a), ar) def test_ipdb_magics(): @@ -184,3 +184,50 @@ def test_ipdb_magics2(): >>> sys.settrace(old_trace) ''' + +def can_quit(): + '''Test that quit work in ipydb + + >>> old_trace = sys.gettrace() + + >>> def bar(): + ... pass + + >>> with PdbTestInput([ + ... 'quit', + ... ]): + ... debugger.Pdb().runcall(bar) + > (2)bar() + 1 def bar(): + ----> 2 pass + + ipdb> quit + + Restore previous trace function, e.g. for coverage.py + + >>> sys.settrace(old_trace) + ''' + + +def can_exit(): + '''Test that quit work in ipydb + + >>> old_trace = sys.gettrace() + + >>> def bar(): + ... pass + + >>> with PdbTestInput([ + ... 'exit', + ... ]): + ... debugger.Pdb().runcall(bar) + > (2)bar() + 1 def bar(): + ----> 2 pass + + ipdb> exit + + Restore previous trace function, e.g. for coverage.py + + >>> sys.settrace(old_trace) + ''' From d1ba39add809f1ebde839e8678912371ce68295b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 21 Jun 2016 13:27:14 -0700 Subject: [PATCH 0466/4859] Reformat newlines in Tooltips. Closes #9640 --- IPython/core/oinspect.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 47c2a9e4498..971e4dac3a6 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -603,6 +603,7 @@ def format_mime(self, bundle): _len = max(len(h) for h in heads) for head, body in zip(heads, bodies): + body = body.strip('\n') delim = '\n' if '\n' in body else ' ' text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n' From aa6cf81c86f166e640438b86c8bff1574f1f6e70 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 21 Jun 2016 13:37:14 -0700 Subject: [PATCH 0467/4859] Bump minimal PTK to 1.0.3 Closes #9630 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 44975df60fb..4a81a4f3b58 100755 --- a/setup.py +++ b/setup.py @@ -196,7 +196,7 @@ def run(self): 'pickleshare', 'simplegeneric>0.8', 'traitlets>=4.2', - 'prompt_toolkit>=1.0.1,<2.0.0', + 'prompt_toolkit>=1.0.3,<2.0.0', 'pygments', ] From 4042f2a040d7d5e242ab552946f9a41d9e6aa5f4 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 21 Jun 2016 13:57:32 -0700 Subject: [PATCH 0468/4859] Use SIMPLE_PROMPT while testing. Closes #9618 --- IPython/testing/globalipapp.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/testing/globalipapp.py b/IPython/testing/globalipapp.py index 635921a2843..7e6582449a0 100644 --- a/IPython/testing/globalipapp.py +++ b/IPython/testing/globalipapp.py @@ -97,6 +97,7 @@ def start_ipython(): # Create custom argv and namespaces for our IPython to be test-friendly config = tools.default_config() + config.TerminalInteractiveShell.simple_prompt = True # Create and initialize our test-friendly IPython instance. shell = TerminalInteractiveShell.instance(config=config, From b7d03ed6b16013973b82c4725c79c30ac0a84903 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 21 Jun 2016 14:10:43 -0700 Subject: [PATCH 0469/4859] Remove the "autoedit_syntax" feature. IPython used to (a long time ago, in a galaxy far far away) have the ability to automatically open an editor in case a wild syntax error appears. The configuration option to enable that was not working for a few years, and apparently we by mistake re enabled it, to discover that the feature is actually broken. So this plainly remove the code to support this feature, at the exception of the `fix_error_editor` hook. Indeed it is public API, so for now as it seem to be used only for this feature, we'll just raise a UserWarning (there is roughly 0 chance of this being tested as it's used mostly interactively, so DeprecationWarnings would be unseen). We'll remove later if no complaints Closes #9603 --- IPython/core/hooks.py | 16 ++++++- IPython/terminal/interactiveshell.py | 66 ---------------------------- docs/source/whatsnew/version5.rst | 30 ++++++++++++- 3 files changed, 42 insertions(+), 70 deletions(-) diff --git a/IPython/core/hooks.py b/IPython/core/hooks.py index 79503de20da..b0d0e6c22bf 100644 --- a/IPython/core/hooks.py +++ b/IPython/core/hooks.py @@ -37,6 +37,7 @@ def load_ipython_extension(ip): import os import subprocess +import warnings import sys from IPython.core.error import TryNext @@ -83,13 +84,24 @@ def editor(self, filename, linenum=None, wait=True): import tempfile def fix_error_editor(self,filename,linenum,column,msg): - """Open the editor at the given filename, linenumber, column and + """DEPRECATED + + Open the editor at the given filename, linenumber, column and show an error message. This is used for correcting syntax errors. The current implementation only has special support for the VIM editor, and falls back on the 'editor' hook if VIM is not used. - Call ip.set_hook('fix_error_editor',youfunc) to use your own function, + Call ip.set_hook('fix_error_editor',yourfunc) to use your own function, """ + + warnings.warn(""" +`fix_error_editor` is pending deprecation as of IPython 5.0 and will be removed +in future versions. It appears to be used only for automatically fixing syntax +error that has been broken for a few years and has thus been removed. If you +happend to use this function and still need it please make your voice heard on +the mailing list ipython-dev@scipy.org , or on the GitHub Issue tracker: +https://github.com/ipython/ipython/issues/9649 """, UserWarning) + def vim_quickfix_file(): t = tempfile.NamedTemporaryFile() t.write('%s:%d:%d:%s\n' % (filename,linenum,column,msg)) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index b4b3f178340..233cb1fd180 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -93,11 +93,6 @@ def _space_for_menu_changed(self, old, new): def debugger_cls(self): return Pdb if self.simple_prompt else TerminalPdb - autoedit_syntax = Bool(False, - help="auto editing of files with syntax errors.", - ).tag(config=True) - - confirm_exit = Bool(True, help=""" Set to confirm when you try to exit IPython with an EOF (Control-D @@ -476,8 +471,6 @@ def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED): else: if code: self.run_cell(code, store_history=True) - if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: - self.edit_syntax_error() def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED): # An extra layer of protection in case someone mashing Ctrl-C breaks @@ -505,65 +498,6 @@ def enable_gui(self, gui=None): else: self._inputhook = None - # Methods to support auto-editing of SyntaxErrors: - - def edit_syntax_error(self): - """The bottom half of the syntax error handler called in the main loop. - - Loop until syntax error is fixed or user cancels. - """ - - while self.SyntaxTB.last_syntax_error: - # copy and clear last_syntax_error - err = self.SyntaxTB.clear_err_state() - if not self._should_recompile(err): - return - try: - # may set last_syntax_error again if a SyntaxError is raised - self.safe_execfile(err.filename, self.user_ns) - except: - self.showtraceback() - else: - try: - with open(err.filename) as f: - # This should be inside a display_trap block and I - # think it is. - sys.displayhook(f.read()) - except: - self.showtraceback() - - def _should_recompile(self, e): - """Utility routine for edit_syntax_error""" - - if e.filename in ('', '', '', - '', '', - None): - return False - try: - if (self.autoedit_syntax and - not self.ask_yes_no( - 'Return to editor to correct syntax error? ' - '[Y/n] ', 'y')): - return False - except EOFError: - return False - - def int0(x): - try: - return int(x) - except TypeError: - return 0 - - # always pass integer line and offset values to editor hook - try: - self.hooks.fix_error_editor(e.filename, - int0(e.lineno), int0(e.offset), - e.msg) - except TryNext: - warn('Could not open editor') - return False - return True - # Run !system commands directly, not through pipes, so terminal programs # work correctly. system = InteractiveShell.system_raw diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 5680ee52c94..9052e9ccfc7 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -64,8 +64,6 @@ Most of the above remarks also affect `IPython.core.debugger.Pdb`, the `%debug` and `%pdb` magic which do not use readline anymore either. - - Provisional Changes ------------------- @@ -109,6 +107,34 @@ widgets... As stated above this is nightly experimental feature with a lot of it. +Removed Feature +--------------- + + - ``TerminalInteractiveShell.autoedit_syntax`` Has been broken for many years now +apparently. It has been removed. + + +Deprecated Features +------------------- + +Some deprecated feature, don't forget to enable `DeprecationWarning` as error +of you are using IPython in Continuous Integration setup or in your testing in general: + +.. code:: + :python: + + import warnings + warnings.filterwarnings('error', '.*', DeprecationWarning, module='yourmodule.*') + + + - `hooks.fix_error_editor` seem to be unused and is pending deprecation. + - `IPython/core/excolors.py:ExceptionColors` is deprecated. + - `IPython.core.InteractiveShell:write()` is deprecated, use `sys.stdout` instead. + - `IPython.core.InteractiveShell:write_err()` is deprecated, use `sys.stderr` instead. + - The `formatter` keyword argument to `Inspector.info` in `IPython.core.oinspec` has now no effects. + - The `global_ns` keyword argument of IPython Embed was deprecated, and will now have no effect. Use `module` keyword argument instead. + + Known Issues: ------------- From ad10d99e200e57c0276cd274b2a3cec654530ad7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 23 Jun 2016 11:48:12 -0700 Subject: [PATCH 0470/4859] Restore the ability to use %colors to switch terminal theme. And restore previous coloring of prompts on classical color themes. Unlike 4.x this will **not** change with your terminal background. If the hightligh_style of TerminalInteractiveSHell is set to `legacy` then it uses the value of TermianlInteractiveShell.colors to select the theme: monokai for darkbg/linux (by decision of BDFL), and old prompt values. default for lightbg Closes #9648 --- IPython/core/magics/basic.py | 2 + IPython/terminal/interactiveshell.py | 81 ++++++++++++++++++++-------- docs/source/config/details.rst | 59 +++++++++++++++++--- docs/source/whatsnew/version5.rst | 11 +++- 4 files changed, 124 insertions(+), 29 deletions(-) diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index b9da12db5d4..1108ffbe1c1 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -358,6 +358,8 @@ def color_switch_err(name): # Set exception colors try: shell.InteractiveTB.set_colors(scheme = new_scheme) + shell.colors = new_scheme + shell.refresh_style() shell.SyntaxTB.set_colors(scheme = new_scheme) except: color_switch_err('exception') diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 233cb1fd180..86326a95b88 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -38,6 +38,28 @@ DISPLAY_BANNER_DEPRECATED = object() +from pygments.style import Style + +class _NoStyle(Style): pass + + + +_style_overrides_light_bg = { + Token.Prompt: '#0000ff', + Token.PromptNum: '#0000ee bold', + Token.OutPrompt: '#cc0000', + Token.OutPromptNum: '#bb0000 bold', +} + +_style_overrides_linux = { + Token.Prompt: '#00cc00', + Token.PromptNum: '#00bb00 bold', + Token.OutPrompt: '#cc0000', + Token.OutPromptNum: '#bb0000 bold', +} + + + def get_default_editor(): try: ed = os.environ['EDITOR'] @@ -108,15 +130,20 @@ def debugger_cls(self): help="Enable mouse support in the prompt" ).tag(config=True) - highlighting_style = Unicode('default', + highlighting_style = Unicode('legacy', help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) ).tag(config=True) @observe('highlighting_style') + @observe('colors') def _highlighting_style_changed(self, change): + self.refresh_style() + + def refresh_style(self): self._style = self._make_style_from_name(self.highlighting_style) + highlighting_style_overrides = Dict( help="Override highlighting format for specific tokens" ).tag(config=True) @@ -342,26 +369,38 @@ def _make_style_from_name(self, name): We need that to add style for prompt ... etc. """ - style_cls = get_style_by_name(name) - style_overrides = { - Token.Prompt: '#009900', - Token.PromptNum: '#00ff00 bold', - Token.OutPrompt: '#990000', - Token.OutPromptNum: '#ff0000 bold', - } - if name == 'default': - style_cls = get_style_by_name('default') - # The default theme needs to be visible on both a dark background - # and a light background, because we can't tell what the terminal - # looks like. These tweaks to the default theme help with that. - style_overrides.update({ - Token.Number: '#007700', - Token.Operator: 'noinherit', - Token.String: '#BB6622', - Token.Name.Function: '#2080D0', - Token.Name.Class: 'bold #2080D0', - Token.Name.Namespace: 'bold #2080D0', - }) + if name == 'legacy': + legacy = self.colors.lower() + if legacy == 'linux': + style_cls = get_style_by_name('monokai') + style_overrides = _style_overrides_linux + elif legacy == 'lightbg': + style_overrides = _style_overrides_light_bg + style_cls = get_style_by_name('default') + # The default theme needs to be visible on both a dark background + # and a light background, because we can't tell what the terminal + # looks like. These tweaks to the default theme help with that. + style_overrides.update({ + Token.Number: '#007700', + Token.Operator: 'noinherit', + Token.String: '#BB6622', + Token.Name.Function: '#2080D0', + Token.Name.Class: 'bold #2080D0', + Token.Name.Namespace: 'bold #2080D0', + }) + elif legacy =='nocolor': + style_cls=_NoStyle + style_overrides = {} + else : + raise ValueError('Got unknown colors: ', legacy) + else : + style_cls = get_style_by_name(name) + style_overrides = { + Token.Prompt: '#009900', + Token.PromptNum: '#00ff00 bold', + Token.OutPrompt: '#990000', + Token.OutPromptNum: '#ff0000 bold', + } style_overrides.update(self.highlighting_style_overrides) style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, style_dict=style_overrides) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 3f7414b65fa..ba99e2ff9db 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -21,15 +21,12 @@ The following terminals seem to handle the color sequences fine: * CDE terminal (tested under Solaris). This one boldfaces light colors. * (X)Emacs buffers. See the :ref:`emacs` section for more details on using IPython with (X)Emacs. - * A Windows (XP/2k) command prompt with pyreadline_. * A Windows (XP/2k) CygWin shell. Although some users have reported problems; it is not clear whether there is an issue for everyone or only under specific configurations. If you have full color support under cygwin, please post to the IPython mailing list so this issue can be resolved for all users. -.. _pyreadline: https://code.launchpad.net/pyreadline - These have shown problems: * Windows command prompt in WinXP/2k logged into a Linux machine via @@ -38,9 +35,56 @@ These have shown problems: extensions. Once Gary's readline library is installed, the normal WinXP/2k command prompt works perfectly. -IPython uses colors for two main groups of things: prompts and -tracebacks which are directly printed to the terminal, and the object -introspection system which passes large sets of data through a pager. +IPython uses colors for various groups of things that may be +controlled by different configuration options: prompts, tracebacks, as +you type in the terminal and the object introspection system which +passes large sets of data through a pager. There are various way to +change the colors. + +We can distinguish the coloration into 2 main categories: + +- The one that affect only the terminal client. +- The ones that also affect client connected through the Jupyter + protocol. + +Traceback, debugger, and pager are highlighted kernel-side so fall +into the second category, for historical reasons they are often +governed by a ``colors`` attribute or configuration option that can +take one of 3 case insensitive values: ``NoColors``, ``Linux`` and +``LightBG``. + +Colors that affect only the terminal client are governed mainly by +``TerminalInteractiveShell.highlight_style`` taking the name of a +``Pygments`` style. + +As of IPython 5.0 the color configuration works as follows: + + - by default, ``TerminalInteractiveShell.highlight_style`` is set to + ``legacy`` which **try to** emulate the colors of IPython pre 5.0, + and respect the ``.color`` configuration option. + The emulation is approximative as the current version of Pygments + (2.1) does only support extended ANSI escape sequence, hence the + theme cannot adapt to your terminal custom mapping if you have + one. + + The last extra difference being that the "as you type" coloration + is present using the theme "default" if `color` is `LightBG`, and + using the theme "monokai" if `Linux`. + + - if ``TerminalInteractiveShell.highlight_style`` is set to any other + themes, this theme is used for "as you type" highlighting. The + prompt highlighting is then governed by + ``--TerminalInteractiveShell.highlighting_style_overrides`` + +As a summary, by default IPython 5.0 should mostly behave unchanged +from IPython 4.x and before. Use +``TerminalInteractiveShell.highlight_style`` and +``--TerminalInteractiveShell.highlighting_style_overrides`` for extra +flexibility. + +With default configuration `--colors=[nocolors|linux|ightbg]` as well +as the `%colors` magic should behave identically as before. + Colors in the pager ------------------- @@ -54,6 +98,9 @@ To configure your default pager to allow these: properly interpret control sequences, which is how color information is given to your terminal. + + + .. _editors: Editor configuration diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 9052e9ccfc7..808a0854509 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -8,7 +8,7 @@ IPython 5.0 Released June, 2016 IPython 5.0 now uses `prompt-toolkit` for the command line interface, thus -allowing real multi-line editing and syntactic coloration as you type. +allowing real multi-line editing and syntactic coloration as you type. When using IPython as a subprocess, like for emacs inferior-shell, IPython can @@ -20,7 +20,7 @@ Backwards incompatible changes ------------------------------ -The `install_ext magic` function which was deprecated since 4.0 have now been deleted. +The `install_ext magic` function which was deprecated since 4.0 have now been deleted. You can still distribute and install extension as packages on PyPI. Update IPython event triggering to ensure callback registration and @@ -63,6 +63,13 @@ See `TerminalInteractiveShell.prompts` configurable for how to setup your prompt Most of the above remarks also affect `IPython.core.debugger.Pdb`, the `%debug` and `%pdb` magic which do not use readline anymore either. +The color handling has been slightly changed and is now exposed +through, in particular the colors of prompts and as you type +highlighting can be affected by : +``TerminalInteractiveShell.highlight_style``. With default +configuration the ``--colors`` flag and ``%colors`` magic behavior +should be mostly unchanged. See the `colors `_ section of +our documentation Provisional Changes ------------------- From 840c49b53c48cff5108e18557fc39dbe63c1cbcf Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 24 Jun 2016 11:26:25 -0700 Subject: [PATCH 0471/4859] Have -> Has typo --- docs/source/whatsnew/version5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 808a0854509..225395974ae 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -20,7 +20,7 @@ Backwards incompatible changes ------------------------------ -The `install_ext magic` function which was deprecated since 4.0 have now been deleted. +The `install_ext magic` function which was deprecated since 4.0 has now been deleted. You can still distribute and install extension as packages on PyPI. Update IPython event triggering to ensure callback registration and From e36267046e6a380861a055dde4c93feafc2d2362 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 21 Jun 2016 13:27:14 -0700 Subject: [PATCH 0472/4859] Reformat newlines in Tooltips. Closes #9640 --- IPython/core/oinspect.py | 1 + 1 file changed, 1 insertion(+) diff --git a/IPython/core/oinspect.py b/IPython/core/oinspect.py index 47c2a9e4498..971e4dac3a6 100644 --- a/IPython/core/oinspect.py +++ b/IPython/core/oinspect.py @@ -603,6 +603,7 @@ def format_mime(self, bundle): _len = max(len(h) for h in heads) for head, body in zip(heads, bodies): + body = body.strip('\n') delim = '\n' if '\n' in body else ' ' text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n' From fdc923a43a2983a9e38ce0e62dfa536919023d46 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 24 Jun 2016 11:33:05 -0700 Subject: [PATCH 0473/4859] Edit version doc --- docs/source/whatsnew/version5.rst | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 225395974ae..643a2299058 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -7,13 +7,13 @@ IPython 5.0 Released June, 2016 -IPython 5.0 now uses `prompt-toolkit` for the command line interface, thus +IPython 5.0 now uses ``prompt-toolkit`` for the command line interface, thus allowing real multi-line editing and syntactic coloration as you type. When using IPython as a subprocess, like for emacs inferior-shell, IPython can -be started with --simple-prompt flag, which will bypass the prompt_toolkit -input layer. In this mode completion, prompt color and many other features are +be started with a ``--simple-prompt`` flag, which will bypass the prompt_toolkit +input layer. In this mode, prompt color and many other features are disabled. Backwards incompatible changes @@ -21,10 +21,10 @@ Backwards incompatible changes The `install_ext magic` function which was deprecated since 4.0 has now been deleted. -You can still distribute and install extension as packages on PyPI. +You can still distribute and install extensions as packages on PyPI. Update IPython event triggering to ensure callback registration and -unregistration only affects the set of callbacks the *next* time that event is +unregistration will only affect the set of callbacks the *next* time that event is triggered. See :ghissue:`9447` and :ghpull:`9453`. This is a change to the existing semantics, wherein one callback registering a @@ -32,7 +32,7 @@ second callback when triggered for an event would previously be invoked for that same event. Integration with pydb has been removed since pydb development has been stopped -since 2012, and pydb is not installable from PyPI +since 2012, and pydb is not installable from PyPI. @@ -43,7 +43,7 @@ IPython 5.0 now uses ``prompt_toolkit``. The ``IPython.terminal.interactiveshell.TerminalInteractiveShell`` now uses ``prompt_toolkit``. It is an almost complete rewrite, so many settings have thus changed or disappeared. The class keep the same name to avoid breaking -user configuration for the options which names is unchanged. +user configuration for the options with names that are unchanged. The usage of ``prompt_toolkit`` is accompanied by a complete removal of all code, using ``readline``. A particular effect of not using `readline` anymore @@ -56,15 +56,15 @@ See `TerminalInteractiveShell.prompts` configurable for how to setup your prompt .. note:: - During developement and beta cycle, ``TerminalInteractiveShell`` was - temporarly moved to ``IPtyhon.terminal.ptshell``. + During development and beta cycle, ``TerminalInteractiveShell`` was + temporarly moved to ``IPython.terminal.ptshell``. Most of the above remarks also affect `IPython.core.debugger.Pdb`, the `%debug` and `%pdb` magic which do not use readline anymore either. -The color handling has been slightly changed and is now exposed -through, in particular the colors of prompts and as you type +The color handling has been slightly changed and is now exposed, +in particular the colors of prompts and as you type highlighting can be affected by : ``TerminalInteractiveShell.highlight_style``. With default configuration the ``--colors`` flag and ``%colors`` magic behavior @@ -74,9 +74,9 @@ our documentation Provisional Changes ------------------- -Provisional changes are in experimental functionality that may, or may not make -it to future version of IPython, and which API may change without warnings. -Activating these feature and using these API is at your own risk, and may have +Provisional changes are experimental functionality that may, or may not, make +it into a future version of IPython, and which API may change without warnings. +Activating these features and using these API are at your own risk, and may have security implication for your system, especially if used with the Jupyter notebook, When running via the Jupyter notebook interfaces, or other compatible client, From 4d160dbfc239d1a5f1e55c1649e51ebc66731ec7 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Fri, 24 Jun 2016 11:43:19 -0700 Subject: [PATCH 0474/4859] Edit doc on color details. --- docs/source/config/details.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index ba99e2ff9db..250f1aa6a38 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -36,34 +36,34 @@ These have shown problems: WinXP/2k command prompt works perfectly. IPython uses colors for various groups of things that may be -controlled by different configuration options: prompts, tracebacks, as -you type in the terminal and the object introspection system which +controlled by different configuration options: prompts, tracebacks, "as +you type" in the terminal, and the object introspection system which passes large sets of data through a pager. There are various way to change the colors. We can distinguish the coloration into 2 main categories: -- The one that affect only the terminal client. -- The ones that also affect client connected through the Jupyter +- The one that affects only the terminal client. +- The ones that also affect clients connected through the Jupyter protocol. -Traceback, debugger, and pager are highlighted kernel-side so fall -into the second category, for historical reasons they are often +Traceback, debugger, and pager are highlighted kernel-side so they fall +into the second category. For historical reasons they are often governed by a ``colors`` attribute or configuration option that can take one of 3 case insensitive values: ``NoColors``, ``Linux`` and ``LightBG``. -Colors that affect only the terminal client are governed mainly by +Colors that affect only the terminal client are governed mainly by ``TerminalInteractiveShell.highlight_style`` taking the name of a ``Pygments`` style. As of IPython 5.0 the color configuration works as follows: - by default, ``TerminalInteractiveShell.highlight_style`` is set to - ``legacy`` which **try to** emulate the colors of IPython pre 5.0, + ``legacy`` which **trys to** emulate the colors of IPython pre 5.0 and respect the ``.color`` configuration option. - The emulation is approximative as the current version of Pygments - (2.1) does only support extended ANSI escape sequence, hence the + The emulation is an approximation of the current version of Pygments + (2.1) and only supports extended ANSI escape sequence, hence the theme cannot adapt to your terminal custom mapping if you have one. From f8cc22a2667435df0e7b0db096b062b4d102d3eb Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 24 Jun 2016 23:25:15 +0200 Subject: [PATCH 0475/4859] Don't rely upon traitlets copying self.config when saving CLI config to reload later for highest priority. traitlets 4.1-4.2.1 don't copy self.config in update_config (rightly so), so when saving CLI config for later re-loading, make sure it's a copy so it doesn't get changed by further loading. --- IPython/core/application.py | 5 ++++- IPython/core/tests/test_application.py | 24 ++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/IPython/core/application.py b/IPython/core/application.py index 038891e8423..18016279552 100644 --- a/IPython/core/application.py +++ b/IPython/core/application.py @@ -13,6 +13,7 @@ # Distributed under the terms of the Modified BSD License. import atexit +from copy import deepcopy import glob import logging import os @@ -447,7 +448,9 @@ def initialize(self, argv=None): if self.subapp is not None: # stop here if subapp is taking over return - cl_config = self.config + # save a copy of CLI config to re-load after config files + # so that it has highest priority + cl_config = deepcopy(self.config) self.init_profile_dir() self.init_config_files() self.load_config_file() diff --git a/IPython/core/tests/test_application.py b/IPython/core/tests/test_application.py index 8ef97f3ea97..fb7724f0db7 100644 --- a/IPython/core/tests/test_application.py +++ b/IPython/core/tests/test_application.py @@ -4,9 +4,15 @@ import os import tempfile +import nose.tools as nt + +from traitlets import Unicode + from IPython.core.application import BaseIPythonApplication from IPython.testing import decorators as dec from IPython.utils import py3compat +from IPython.utils.tempdir import TemporaryDirectory + @dec.onlyif_unicode_paths def test_unicode_cwd(): @@ -48,3 +54,21 @@ def test_unicode_ipdir(): os.environ["IPYTHONDIR"] = old_ipdir1 if old_ipdir2: os.environ["IPYTHONDIR"] = old_ipdir2 + +def test_cli_priority(): + with TemporaryDirectory() as td: + + class TestApp(BaseIPythonApplication): + test = Unicode().tag(config=True) + + # Create the config file, so it tries to load it. + with open(os.path.join(td, 'ipython_config.py'), "w") as f: + f.write("c.TestApp.test = 'config file'") + + app = TestApp() + app.initialize(['--profile-dir', td]) + nt.assert_equal(app.test, 'config file') + app = TestApp() + app.initialize(['--profile-dir', td, '--TestApp.test=cli']) + nt.assert_equal(app.test, 'cli') + From d7fe797d612ebde3ef511efb5ecfec8d73713e21 Mon Sep 17 00:00:00 2001 From: Adam Greenhall Date: Fri, 24 Jun 2016 16:38:57 -0700 Subject: [PATCH 0476/4859] colors in interactive shell --- IPython/terminal/embed.py | 1 - 1 file changed, 1 deletion(-) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 275cacea8d2..a49122d2ad4 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -295,7 +295,6 @@ def embed(**kwargs): if config is None: config = load_default_config() config.InteractiveShellEmbed = config.TerminalInteractiveShell - config.InteractiveShellEmbed.colors='nocolor' kwargs['config'] = config #save ps1/ps2 if defined ps1 = None From 5b905f8fef97d150c837c638376abe9a855bc003 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 24 Jun 2016 16:45:55 -0700 Subject: [PATCH 0477/4859] Documentation overhaul. Remove many unnecessary section or inaccurate, build locally using RTD theme to simplify testing locally. Decrease the depth of some section. And do not duplicate table of content which anyway is always on the sidebar. --- docs/source/_static/default.css | 534 ------------------------ docs/source/_templates/layout.html | 23 - docs/source/conf.py | 6 +- docs/source/coredev/release_process.rst | 6 +- docs/source/index.rst | 75 +++- docs/source/install/index.rst | 50 ++- docs/source/install/install.rst | 131 ++---- docs/source/overview.rst | 35 +- docs/source/whatsnew/index.rst | 2 +- 9 files changed, 193 insertions(+), 669 deletions(-) delete mode 100644 docs/source/_static/default.css delete mode 100644 docs/source/_templates/layout.html diff --git a/docs/source/_static/default.css b/docs/source/_static/default.css deleted file mode 100644 index 7938313e0e8..00000000000 --- a/docs/source/_static/default.css +++ /dev/null @@ -1,534 +0,0 @@ -/** - * Alternate Sphinx design - * Originally created by Armin Ronacher for Werkzeug, adapted by Georg Brandl. - */ - -body { - font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; - font-size: 14px; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - /*background-color: #AFC1C4; */ - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -a { - color: #CA7900; - text-decoration: none; -} - -a:hover { - color: #2491CF; -} - -pre { - font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.015em; - padding: 0.5em; - border: 1px solid #ccc; - background-color: #f8f8f8; -} - -td.linenos pre { - padding: 0.5em 0; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} - -hr { - border: 1px solid #abc; - margin: 2em; -} - -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; - border: 0; -} - -tt.descclassname { - background-color: transparent; - border: 0; -} - -tt.xref { - background-color: transparent; - font-weight: bold; - border: 0; -} - -a tt { - background-color: transparent; - font-weight: bold; - border: 0; - color: #CA7900; -} - -a tt:hover { - color: #2491CF; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -.refcount { - color: #060; -} - -dt { - font-weight: bold; - padding-left: 0.5em; -} - -dt:target, -.highlight { - background-color: #fbe54e; -} - -dl.class, dl.function { - border-top: 2px solid #888; -} - -dl.method, dl.attribute { - border-top: 1px solid #aaa; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -pre { - line-height: 120%; -} - -pre a { - color: inherit; - text-decoration: underline; -} - -.first { - margin-top: 0 !important; -} - -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; -} - -/* -div.documentwrapper { - width: 100%; -} -*/ - -div.clearer { - clear: both; -} - -div.related h3 { - display: none; -} - -div.related ul { - background-image: url(navigation.png); - height: 2em; - list-style: none; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 0; - padding-left: 10px; -} - -div.related ul li { - margin: 0; - padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { - margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; -} - -div.related ul li a:hover { - color: #3CA8E7; -} - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; -} - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.body a { - text-decoration: underline; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - text-align: left; -/* margin-left: -100%; */ -} - -div.sphinxsidebar h4, div.sphinxsidebar h3 { - margin: 1em 0 0.5em 0; - font-size: 0.9em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - list-style: none; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - list-style: square; - margin-left: 20px; -} - -p { - margin: 0.8em 0 0.5em 0; -} - -p.rubric { - font-weight: bold; -} - -h1 { - margin: 0; - padding: 0.7em 0 0.3em 0; - font-size: 1.5em; - color: #11557C; -} - -h2 { - margin: 1.3em 0 0.2em 0; - font-size: 1.35em; - padding: 0; -} - -h3 { - margin: 1em 0 0.2em 0; - font-size: 1.2em; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { - display: inline; -} - -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -div.pagination { - margin-top: 2em; - padding-top: 0.5em; - border-top: 1px solid black; - text-align: center; -} - -div.sphinxsidebar ul.toc { - margin: 1em 0 1em 0; - padding: 0 0 0 0.5em; - list-style: none; -} - -div.sphinxsidebar ul.toc li { - margin: 0.5em 0 0.5em 0; - font-size: 0.9em; - line-height: 130%; -} - -div.sphinxsidebar ul.toc li p { - margin: 0; - padding: 0; -} - -div.sphinxsidebar ul.toc ul { - margin: 0.2em 0 0.2em 0; - padding: 0 0 0 1.8em; -} - -div.sphinxsidebar ul.toc ul li { - padding: 0; -} - -div.admonition, div.warning { - font-size: 0.9em; - margin: 1em 0 0 0; - border: 1px solid #86989B; - background-color: #f7f7f7; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border-bottom: 1px solid #86989B; - font-weight: bold; - background-color: #AFC1C4; -} - -div.warning { - border: 1px solid #940000; -} - -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; -} - -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; -} - -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; -} - - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -a.headerlink:hover { - background-color: #ccc; - color: white!important; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -img.inheritance { - border: 0px -} - -form.pfform { - margin: 10px 0 20px 0; -} - -table.contentstable { - width: 90%; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -.search input[name=q] { - max-width: 100%; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} -div.figure { - text-align: center; -} - -div.versionchanged { - margin-left: 30px; - margin-right: 30px; -} - -span.versionmodified { - font-style: italic; -} - -pre { - white-space: pre-wrap; -} diff --git a/docs/source/_templates/layout.html b/docs/source/_templates/layout.html deleted file mode 100644 index 965c354f287..00000000000 --- a/docs/source/_templates/layout.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "!layout.html" %} - - -{% block rootrellink %} -
  • home
  • -
  • search
  • -
  • documentation »
  • -{% endblock %} - - -{% block relbar1 %} - -
    -IPython Documentation -
    -{{ super() }} -{% endblock %} - -{# put the sidebar before the body #} -{% block sidebar1 %}{{ sidebar() }}{% endblock %} -{% block sidebar2 %}{% endblock %} - diff --git a/docs/source/conf.py b/docs/source/conf.py index 6b7a5fb5a1e..91be39fe2de 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -34,6 +34,10 @@ '__file__': fpath, '__name__': '__main__', }) +else: + import sphinx_rtd_theme + html_theme = "sphinx_rtd_theme" + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it @@ -148,7 +152,7 @@ # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. -html_style = 'default.css' +# html_style = 'default.css' html_favicon = 'favicon.ico' # The name for this set of Sphinx documents. If None, it defaults to diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index d595f0caff0..94255d6f015 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -91,6 +91,9 @@ release is: ``1.3rc1``. Notice that there is no separator between the '3' and the 'r'. Check the environment variable `$VERSION` as well. +Comment remove the `developpement` entry in `whatsnew/index.rst`. TODO, figure +out how to make that automatic. + 5. Run the `tools/build_release` script --------------------------------------- @@ -116,7 +119,8 @@ Create and push the tag:: git tag -am "release $VERSION" "$VERSION" git push origin --tags -Update release.py back to `x.y-dev` or `x.y-maint`, and push:: +Update release.py back to `x.y-dev` or `x.y-maint`, and re-add the +`developpement` entry in `docs/source/whatsnew/index.rst` and push:: git commit -am "back to development" git push origin $BRANCH diff --git a/docs/source/index.rst b/docs/source/index.rst index 7b4625eeccf..fd308e1d361 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,3 +1,5 @@ +.. _introduction: + ===================== IPython Documentation ===================== @@ -7,14 +9,81 @@ IPython Documentation :Release: |release| :Date: |today| -Welcome to the official IPython documentation. +Welcome to the official IPython documentation + +IPython provides a rich toolkit to help you make the most out of using Python +interactively. Its main components are: + +* A powerful interactive Python shell +* A `Jupyter `_ kernel to work with Python code in Jupyter + notebooks and other interactive frontends. + +The enhanced interactive Python shells and kernel have the following main +features: + +* Comprehensive object introspection. + +* Input history, persistent across sessions. + +* Caching of output results during a session with automatically generated + references. + +* Extensible tab completion, with support by default for completion of python + variables and keywords, filenames and function keywords. + +* Extensible system of 'magic' commands for controlling the environment and + performing many tasks related either to IPython or the operating system. + +* A rich configuration system with easy switching between different setups + (simpler than changing $PYTHONSTARTUP environment variables every time). + +* Session logging and reloading. + +* Extensible syntax processing for special purpose situations. + +* Access to the system shell with user-extensible alias system. + +* Easily embeddable in other Python programs and GUIs. + +* Integrated access to the pdb debugger and the Python profiler. + + +The Command line interface inherit all the above functionality and posses + +* real multiline editting. + +* syntax highlighting as you type + +* intgration with command line editor for a better workflow. + +The kernel also have its share of feature, when used with a compatible frontend +it allows for: + +* rich display system for object allowing to display Html, Images, Latex,Sounds + Video. + +* interactive widgets with the use of the ``ipywigets`` package. + + +This documentation will walk through most of the features of the IPython +command line and kernel, as well as describe the internals mechanisms in order +to improve your Python workflow. + +You can always find the table of content for this documentation in the left +sidebar, allowing you to come back on previous section if needed, or skip ahead. + + +The latest development version is always available from IPython's `GitHub +repository `_. + + -Contents -======== .. toctree:: :maxdepth: 1 + :hidden: + self overview whatsnew/index install/index diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst index 2d84cfb69be..d50aaad7309 100644 --- a/docs/source/install/index.rst +++ b/docs/source/install/index.rst @@ -5,8 +5,56 @@ Installation ============ .. toctree:: - :maxdepth: 2 + :maxdepth: 3 + :hidden: + install kernel_install + + +This sections will guide you into `installing IPython itself `_, and +installing `kernels for jupyter `_ if you are working with +multiple version of Python, or multiple environments. + +To know more, head to the next section. + + +Quick install reminder +~~~~~~~~~~~~~~~~~~~~~~ + +Here is a quick reminder of the various commands needed if you are already +familiar with IPython and are just searching to refresh your memory: + +Install IPython: + +.. code-block:: bash + + $ pip install ipython + + +Install and register an IPython kernel with Jupyter: + + +.. code-block:: bash + + $ python -m pip install ipykernel + + $ python -m ipykernel install [--user] [--name ] [--display-name <"User Friendly Name">] + +for more help see + +.. code-block:: bash + + $ python -m ipykernel install --help + + + +.. seealso:: + + `Installing Jupyter `__ + The Notebook, nbconvert, and many other former pieces of IPython are now + part of Project Jupyter. + + diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index c2895f61ced..4e73713d328 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -1,34 +1,28 @@ -IPython requires Python 2.7 or ≥ 3.3. +Installing IPython +================== -.. seealso:: - `Installing Jupyter `__ - The Notebook, nbconvert, and many other former pieces of IPython are now - part of Project Jupyter. +IPython requires Python 2.7 or ≥ 3.3. -Quickstart -========== +Quick Install +------------- -If you have :mod:`pip`, -the quickest way to get up and running with IPython is: +With ``pip`` already installed : .. code-block:: bash $ pip install ipython -To use IPython with notebooks or the Qt console, you should also install -``jupyter``. +This should install IPython as well as all the other dependency required. -To run IPython's test suite, use the :command:`iptest` command: - -.. code-block:: bash +If you try to use IPython with notebooks or the Qt console, you should also install +``jupyter``. - $ iptest Overview -======== +-------- This document describes in detail the steps required to install IPython. For a few quick ways to get started with package managers or full Python distributions, @@ -36,10 +30,10 @@ see `the install page `_ of the IPython website Please let us know if you have problems installing IPython or any of its dependencies. -IPython and most dependencies can be installed via :command:`pip`. +IPython and most dependencies should be installed via :command:`pip`. In many scenarios, this is the simplest method of installing Python packages. More information about :mod:`pip` can be found on -`its PyPI page `__. +`its PyPI page `__. More general information about installing Python packages can be found in @@ -47,21 +41,20 @@ More general information about installing Python packages can be found in Installing IPython itself -========================= +~~~~~~~~~~~~~~~~~~~~~~~~~ -Given a properly built Python, the basic interactive IPython shell will work -with no external dependencies. However, some Python distributions -(particularly on Windows and OS X), don't come with a working :mod:`readline` -module. The IPython shell will work without :mod:`readline`, but will lack -many features that users depend on, such as tab completion and command line -editing. If you install IPython with :mod:`pip`, -then the appropriate :mod:`readline` for your platform will be installed. -See below for details of how to make sure you have a working :mod:`readline`. +IPython requires several dependencies to work correctly, it is not recommended +to install IPython and all it's dependencies manually as this can be quite long and trouble some. +You should likely use the python package manager ``pip`` Installation using pip ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ + +Make sure you have the latest version of :mod:`pip` ( the Python package +manager) installed. If you do not, head to `Pip documentation +`_ and install it first. -If you have :mod:`pip`, the easiest way of getting IPython is: +The quickest way to get up and running with IPython is to install it with pip: .. code-block:: bash @@ -71,7 +64,7 @@ That's it. Installation from source ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ If you don't want to use :command:`pip`, or don't have it installed, grab the latest stable tarball of IPython `from PyPI @@ -83,12 +76,22 @@ grab the latest stable tarball of IPython `from PyPI $ cd ipython $ pip install . +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. + 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`. +permissions, you may need to run the last command with :command:`sudo`. You can +also install in user specific location by using the ``--user`` flag in conjunction with pip + +To can run IPython's test suite, use the :command:`iptest` command from outside of the IPython source tree: + +.. code-block:: bash + + $ iptest Installing the development version ----------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is also possible to install the development version of IPython from our `Git `_ source code repository. To do this you will @@ -100,15 +103,15 @@ need to have Git installed on your system. Then do: $ cd ipython $ pip install . -Some users want to be able to follow the development branch as it changes. If -you have :mod:`pip`, you can replace the last step by: +Some users want to be able to follow the development branch as it changes. +With :mod:`pip` installed, you can replace the last step by: .. code-block:: bash $ pip install -e . This creates links in the right places and installs the command line script to -the appropriate places. +the appropriate location. Then, if you want to update your IPython at any time, do: @@ -119,62 +122,10 @@ Then, if you want to update your IPython at any time, do: .. _dependencies: Dependencies -============ +~~~~~~~~~~~~ IPython relies on a number of other Python packages. Installing using a package manager like pip or conda will ensure the necessary packages are installed. If you install manually, it's up to you to make sure dependencies are installed. -They're not listed here, because they may change from release to release, so a -static list will inevitably get out of date. - -It also has one key non-Python dependency which you may need to install separately. - -readline --------- - -IPython's terminal interface relies on readline to provide features like tab -completion and history navigation. If you only want to use IPython as a kernel -for Jupyter notebooks and other frontends, you don't need readline. - - -**On Windows**, to get full console functionality, *PyReadline* is required. -PyReadline is a separate, Windows only implementation of readline that uses -native Windows calls through :mod:`ctypes`. The easiest way of installing -PyReadline is you use the binary installer available `here -`__. - -**On OS X**, if you are using the built-in Python shipped by Apple, you will be -missing a proper readline implementation as Apple ships instead a library called -``libedit`` that provides only some of readline's functionality. While you may -find libedit sufficient, we have occasional reports of bugs with it and several -developers who use OS X as their main environment consider libedit unacceptable -for productive, regular use with IPython. - -Therefore, IPython on OS X depends on the :mod:`gnureadline` module. -We will *not* consider completion/history problems to be bugs for IPython if you -are using libedit. - -To get a working :mod:`readline` module on OS X, do (with :mod:`pip` -installed): - -.. code-block:: bash - - $ pip install gnureadline - -.. note:: - - Other Python distributions on OS X (such as Anaconda, fink, MacPorts) - already have proper readline so you likely don't have to do this step. - -When IPython is installed with :mod:`pip`, -the correct readline should be installed if you specify the `terminal` -optional dependencies: - -.. code-block:: bash - - $ pip install "ipython[terminal]" - -**On Linux**, readline is normally installed by default. If not, install it -from your system package manager. If you are compiling your own Python, make -sure you install the readline development headers first. - +They're not listed here, because they may change from release to release, and +depending on platform so a static list will inevitably get out of date. diff --git a/docs/source/overview.rst b/docs/source/overview.rst index f6ebd3d143e..0419b6c84d5 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -1,9 +1,6 @@ .. _overview: -============ -Introduction -============ - +======== Overview ======== @@ -18,10 +15,13 @@ interactive and exploratory computing. To support this goal, IPython has three main components: * An enhanced interactive Python shell. + * A decoupled :ref:`two-process communication model `, which allows for multiple clients to connect to a computation kernel, most notably - the web-based notebook. -* An architecture for interactive parallel computing. + the web-based notebook provided with `Jupyter `_. + +* An architecture for interactive parallel computing now part of the + `ipyparallel` package. All of IPython is open source (released under the revised BSD license). @@ -69,8 +69,7 @@ Main features of the interactive shell * Completion in the local namespace, by typing :kbd:`TAB` at the prompt. This works for keywords, modules, methods, variables and files in the - current directory. This is supported via the readline library, and - full access to configuring readline's behavior is provided. + current directory. This is supported via the ``prompt_toolkit`` library. Custom completers can be implemented easily for different purposes (system commands, magic arguments etc.) @@ -79,7 +78,7 @@ Main features of the interactive shell history and caching of all input and output. * User-extensible 'magic' commands. A set of commands prefixed with - :samp:`%` is available for controlling IPython itself and provides + :samp:`%` or :samp:`%%` is available for controlling IPython itself and provides directory control, namespace information and many aliases to common system shell commands. @@ -102,8 +101,8 @@ Main features of the interactive shell allows you to save arbitrary Python variables. These get restored when you run the :samp:`%store -r` command. -* Automatic indentation (optional) of code as you type (through the - readline library). +* Automatic indentation and highlighting of code as you type (through the + `prompt_toolkit` library). * Macro system for quickly re-executing multiple lines of previous input with a single name via the :samp:`%macro` command. Macros can be @@ -204,10 +203,11 @@ This decoupling allows us to have several clients connected to the same kernel, and even allows clients and kernels to live on different machines. With the exclusion of the traditional single process terminal-based IPython (what you start if you run ``ipython`` without any subcommands), all -other IPython machinery uses this two-process model. This includes ``ipython -console``, ``ipython qtconsole``, and ``ipython notebook``. +other IPython machinery uses this two-process model. Most of this is now part +of the `Jupyter` project, whis includes ``jupyter console``, ``jupyter +qtconsole``, and ``jupyter notebook``. -As an example, this means that when you start ``ipython qtconsole``, you're +As an example, this means that when you start ``jupyter qtconsole``, you're really starting two processes, a kernel and a Qt-based client can send commands to and receive results from that kernel. If there is already a kernel running that you want to connect to, you can pass the ``--existing`` flag @@ -217,7 +217,7 @@ running, use the ``%connect_info`` magic to get the unique connection file, which will be something like ``--existing kernel-19732.json`` but with different numbers which correspond to the Process ID of the kernel. -You can read more about using `ipython qtconsole +You can read more about using `jupyter qtconsole `_, and `ipython notebook `_. There is also a :ref:`message spec ` which documents the protocol for @@ -232,6 +232,11 @@ and clients. Interactive parallel computing ============================== +.. note:: + + This functionality is optional and now part of the `ipyparallel + `_ project. + Increasingly, parallel computer hardware, such as multicore CPUs, clusters and supercomputers, is becoming ubiquitous. Over the last several years, we have developed an architecture within IPython that allows such hardware to be used diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index e68fa3f06d0..2ce01e81b8a 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -20,8 +20,8 @@ development work they do here in a user friendly format. .. toctree:: :maxdepth: 1 - version5 development + version5 version4 github-stats-4 version3 From 46995271c20ee698f836458eb7a225639cfa2f9f Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 24 Jun 2016 17:10:06 -0700 Subject: [PATCH 0478/4859] Some rst and configuration fixes. --- docs/source/conf.py | 13 +++++++-- docs/source/whatsnew/version5.rst | 47 ++++++++++++++++--------------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 91be39fe2de..262ef2e303f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -83,9 +83,18 @@ # The suffix of source filenames. source_suffix = '.rst' -if iprelease['_version_extra'] == 'dev': +def is_stable(extra): + for ext in {'dev', 'b', 'rc'}: + if ext in extra: + return False + return True + +if is_stable(iprelease['_version_extra']): + tags.add('ipystable') +else: + tags.add('ipydev') rst_prolog = """ - .. note:: + .. warning:: This documentation is for a development version of IPython. There may be significant differences from the latest stable release. diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 808a0854509..fc2d1aaccff 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -99,14 +99,16 @@ snippet: ip.sphinxify_docstring = True ip.enable_html_pager = True + You can test the effect of various combinations of the above configuration in the Jupyter notebook, with things example like : -.. code-block:: python +.. code-block:: ipython import numpy as np np.histogram? + This is part of an effort to make Documentation in Python richer and provide in the long term if possible dynamic examples that can contain math, images, widgets... As stated above this is nightly experimental feature with a lot of @@ -117,47 +119,46 @@ it. Removed Feature --------------- - - ``TerminalInteractiveShell.autoedit_syntax`` Has been broken for many years now -apparently. It has been removed. +- ``TerminalInteractiveShell.autoedit_syntax`` Has been broken for many years now + apparently. It has been removed. Deprecated Features ------------------- -Some deprecated feature, don't forget to enable `DeprecationWarning` as error +Some deprecated feature, don't forget to enable ``DeprecationWarning`` as error of you are using IPython in Continuous Integration setup or in your testing in general: -.. code:: - :python: +.. code-block:: python import warnings warnings.filterwarnings('error', '.*', DeprecationWarning, module='yourmodule.*') - - `hooks.fix_error_editor` seem to be unused and is pending deprecation. - - `IPython/core/excolors.py:ExceptionColors` is deprecated. - - `IPython.core.InteractiveShell:write()` is deprecated, use `sys.stdout` instead. - - `IPython.core.InteractiveShell:write_err()` is deprecated, use `sys.stderr` instead. - - The `formatter` keyword argument to `Inspector.info` in `IPython.core.oinspec` has now no effects. - - The `global_ns` keyword argument of IPython Embed was deprecated, and will now have no effect. Use `module` keyword argument instead. +- ``hooks.fix_error_editor`` seem to be unused and is pending deprecation. +- `IPython/core/excolors.py:ExceptionColors` is deprecated. +- `IPython.core.InteractiveShell:write()` is deprecated, use `sys.stdout` instead. +- `IPython.core.InteractiveShell:write_err()` is deprecated, use `sys.stderr` instead. +- The `formatter` keyword argument to `Inspector.info` in `IPython.core.oinspec` has now no effects. +- The `global_ns` keyword argument of IPython Embed was deprecated, and will now have no effect. Use `module` keyword argument instead. Known Issues: ------------- - - ```` Key does not dismiss the completer and does not clear the current - buffer. This is an on purpose modification due to current technical - limitation. Cf :ghpull:`9572`. Escape the control character which is used - for other shortcut, and there is no practical way to distinguish. Use Ctr-G - or Ctrl-C as an alternative. +- ```` Key does not dismiss the completer and does not clear the current + buffer. This is an on purpose modification due to current technical + limitation. Cf :ghpull:`9572`. Escape the control character which is used + for other shortcut, and there is no practical way to distinguish. Use Ctr-G + or Ctrl-C as an alternative. - - Cannot use ``Shift-Enter`` and ``Ctrl-Enter`` to submit code in terminal. cf - :ghissue:`9587` and :ghissue:`9401`. In terminal there is no practical way to - distinguish these key sequences from a normal new line return. +- Cannot use ``Shift-Enter`` and ``Ctrl-Enter`` to submit code in terminal. cf + :ghissue:`9587` and :ghissue:`9401`. In terminal there is no practical way to + distinguish these key sequences from a normal new line return. - - ``PageUp`` and ``pageDown`` do not move through completion menu. +- ``PageUp`` and ``pageDown`` do not move through completion menu. - - Color styles might not adapt to terminal emulator themes. This will need new - version of Pygments to be released, and can be mitigated with custom themes. +- Color styles might not adapt to terminal emulator themes. This will need new + version of Pygments to be released, and can be mitigated with custom themes. From c64b5204c31c4d74599415e2ca533f87a3fea570 Mon Sep 17 00:00:00 2001 From: klonuo Date: Sat, 25 Jun 2016 10:14:47 +0200 Subject: [PATCH 0479/4859] Added keyboard shortcuts docs --- docs/Makefile | 11 +++- docs/autogen_shortcuts.py | 83 ++++++++++++++++++++++++++ docs/make.cmd | 1 + docs/source/conf.py | 0 docs/source/config/index.rst | 1 + docs/source/config/shortcuts/index.rst | 25 ++++++++ 6 files changed, 118 insertions(+), 3 deletions(-) create mode 100755 docs/autogen_shortcuts.py mode change 100644 => 100755 docs/source/conf.py create mode 100755 docs/source/config/shortcuts/index.rst diff --git a/docs/Makefile b/docs/Makefile index b804b515337..20ddd10bd14 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -42,6 +42,7 @@ clean_api: clean: clean_api -rm -rf build/* dist/* -rm -f $(SRCDIR)/config/options/config-generated.txt + -rm -f $(SRCDIR)/config/shortcuts/*.csv -rm -f $(SRCDIR)/interactive/magics-generated.txt pdf: latex @@ -59,8 +60,8 @@ dist: html cp -al build/html . @echo "Build finished. Final docs are in html/" -html: api autoconfig automagic -html_noapi: clean_api autoconfig automagic +html: api autoconfig automagic autogen_shortcuts +html_noapi: clean_api autoconfig automagic autogen_shortcuts html html_noapi: mkdir -p build/html build/doctrees @@ -76,7 +77,7 @@ source/interactive/magics-generated.txt: autogen_magics.py autoconfig: source/config/options/config-generated.txt -source/config/options/generated: +source/config/options/config-generated.txt: $(PYTHON) autogen_config.py @echo "Created docs for config options" @@ -86,6 +87,10 @@ source/api/generated/gen.txt: $(PYTHON) autogen_api.py @echo "Build API docs finished." +autogen_shortcuts: + $(PYTHON) autogen_shortcuts.py + @echo "Created docs for shortcuts" + pickle: mkdir -p build/pickle build/doctrees $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle diff --git a/docs/autogen_shortcuts.py b/docs/autogen_shortcuts.py new file mode 100755 index 00000000000..96e9815f531 --- /dev/null +++ b/docs/autogen_shortcuts.py @@ -0,0 +1,83 @@ +from os.path import abspath, dirname, join + +from IPython.terminal.interactiveshell import KeyBindingManager + + +def name(c): + s = c.__class__.__name__ + return log_filters[s] if s in log_filters.keys() else s + + +def sentencize(s): + """Extract first sentence + """ + s = s.replace('\n', ' ').strip().split('.') + s = s[0] if len(s) else s + try: + return " ".join(s.split()) + except AttributeError: + return s + + +def most_common(lst, n=3): + """Most common elements occurring more then `n` times + """ + from collections import Counter + + c = Counter(lst) + return [k for (k, v) in c.items() if k and v > n] + + +def multi_filter_str(flt): + """Yield readable conditional filter + """ + assert hasattr(flt, 'filters'), 'Conditional filter required' + + yield name(flt) + for subfilter in flt.filters: + yield name(subfilter) + if hasattr(subfilter, 'filter'): + yield name(subfilter.filter) + + +log_filters = dict(_AndList='(And)', _OrList='(Or)', _Invert='(Inv)') + +kbm = KeyBindingManager.for_prompt() +ipy_bindings = kbm.registry.key_bindings + +dummy_docs = [] # ignore bindings without proper documentation + +common_docs = most_common([kb.handler.__doc__ for kb in ipy_bindings]) +if common_docs: + dummy_docs.extend(common_docs) + +dummy_docs = list(set(dummy_docs)) + +single_filter = dict() +multi_filter = dict() +for kb in ipy_bindings: + doc = kb.handler.__doc__ + if not doc or doc in dummy_docs: + continue + + shortcut = ' '.join([k if isinstance(k, str) else k.name for k in kb.keys]) + shortcut += shortcut.endswith('\\') and '\\' or '' + if hasattr(kb.filter, 'filters'): + flt = ' '.join(multi_filter_str(kb.filter)) + multi_filter[(shortcut, flt)] = sentencize(doc) + else: + single_filter[(shortcut, name(kb.filter))] = sentencize(doc) + + +if __name__ == '__main__': + + here = abspath(dirname(__file__)) + dest = join(here, 'source', 'config', 'shortcuts') + + with open(join(dest, 'single_filtered.csv'), 'w') as csv: + for k, v in sorted(single_filter.items()): + csv.write(':kbd:`{}`\t{}\t{}\n'.format(k[0], k[1], v)) + + with open(join(dest, 'multi_filtered.csv'), 'w') as csv: + for k, v in sorted(multi_filter.items()): + csv.write(':kbd:`{}`\t{}\t{}\n'.format(k[0], k[1], v)) diff --git a/docs/make.cmd b/docs/make.cmd index e2347617f07..3f95b10e466 100644 --- a/docs/make.cmd +++ b/docs/make.cmd @@ -25,6 +25,7 @@ FOR %%L IN (html html_noapi pickle htmlhelp latex changes linkcheck) DO ( MD build\%1 || GOTO DIR_EXIST %PYTHON% autogen_config.py && ECHO Created docs for config options %PYTHON% autogen_magics.py && ECHO Created docs for line ^& cell magics + %PYTHON% autogen_shortcuts.py && ECHO Created docs for shortcuts IF NOT "%1" == "html_noapi" ( %PYTHON% autogen_api.py && ECHO Build API docs finished %SPHINXBUILD% -b %1 %ALLSPHINXOPTS% build\%1 diff --git a/docs/source/conf.py b/docs/source/conf.py old mode 100644 new mode 100755 diff --git a/docs/source/config/index.rst b/docs/source/config/index.rst index c0cf66d695f..0fe4f20f668 100644 --- a/docs/source/config/index.rst +++ b/docs/source/config/index.rst @@ -12,6 +12,7 @@ Configuring IPython intro options/index + shortcuts/index details .. seealso:: diff --git a/docs/source/config/shortcuts/index.rst b/docs/source/config/shortcuts/index.rst new file mode 100755 index 00000000000..2d446341fbf --- /dev/null +++ b/docs/source/config/shortcuts/index.rst @@ -0,0 +1,25 @@ +================= +IPython shortcuts +================= + +Available shortcut in IPython terminal. + + +Single Filtered shortcuts +========================= + +.. csv-table:: + :header: Shortcut,Filter,Description + :widths: 30, 30, 100 + :delim: tab + :file: single_filtered.csv + + +Multi Filtered shortcuts +========================= + +.. csv-table:: + :header: Shortcut,Filter,Description + :widths: 30, 30, 100 + :delim: tab + :file: multi_filtered.csv From eb59cfd7e98d1fbfabe8abd1e6e5d110f91cf15b Mon Sep 17 00:00:00 2001 From: klonuo Date: Sun, 26 Jun 2016 03:30:12 +0200 Subject: [PATCH 0480/4859] Add WUC version requirement in setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 09f15404ea3..e3ef6014b28 100755 --- a/setup.py +++ b/setup.py @@ -209,7 +209,7 @@ 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'], + ':sys_platform == "win32"': ['colorama', 'win_unicode_console>=0.5'], 'test:python_version == "2.7"': ['mock'], }) # FIXME: re-specify above platform dependencies for pip < 6 @@ -235,7 +235,7 @@ def run(self): extras_require['terminal'].append('pyreadline>=2.0') else: install_requires.append('pexpect') - + # workaround pypa/setuptools#147, where setuptools misspells # platform_python_implementation as python_implementation if 'setuptools' in sys.modules: From 31d9e5ff2c691a2323bcf3f2c4f8d4c6e0aa35ad Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Mon, 27 Jun 2016 10:04:39 -0700 Subject: [PATCH 0481/4859] Add updates to conf.py --- docs/source/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 262ef2e303f..013e41f7666 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -162,7 +162,7 @@ def is_stable(extra): # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. # html_style = 'default.css' -html_favicon = 'favicon.ico' +# html_favicon = 'favicon.ico' # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -176,7 +176,7 @@ def is_stable(extra): # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] - +html_favicon = '_static/favicon.ico' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' From 1798d32430d0b3353fdfaac0e89085e70119192a Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Mon, 27 Jun 2016 10:45:04 -0700 Subject: [PATCH 0482/4859] First pass at editing pr --- docs/requirements.txt | 2 +- docs/source/conf.py | 4 +++- docs/source/coredev/release_process.rst | 4 ++-- docs/source/index.rst | 7 ++++--- docs/source/install/index.rst | 12 +++++------- docs/source/install/install.rst | 23 ++++++++++++----------- docs/source/overview.rst | 2 +- docs/source/whatsnew/version5.rst | 15 ++++++++------- 8 files changed, 36 insertions(+), 33 deletions(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 958b938fc76..830b9057cf1 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ --e . +-e ../. ipykernel setuptools>=18.5 diff --git a/docs/source/conf.py b/docs/source/conf.py index 013e41f7666..8e0e6fff35a 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -162,7 +162,7 @@ def is_stable(extra): # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. # html_style = 'default.css' -# html_favicon = 'favicon.ico' + # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". @@ -176,6 +176,8 @@ def is_stable(extra): # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] + +# Favicon needs the directory name html_favicon = '_static/favicon.ico' # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 94255d6f015..d7b07dc5497 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -91,7 +91,7 @@ release is: ``1.3rc1``. Notice that there is no separator between the '3' and the 'r'. Check the environment variable `$VERSION` as well. -Comment remove the `developpement` entry in `whatsnew/index.rst`. TODO, figure +Comment remove the `development` entry in `whatsnew/index.rst`. TODO, figure out how to make that automatic. 5. Run the `tools/build_release` script @@ -120,7 +120,7 @@ Create and push the tag:: git push origin --tags Update release.py back to `x.y-dev` or `x.y-maint`, and re-add the -`developpement` entry in `docs/source/whatsnew/index.rst` and push:: +`development` entry in `docs/source/whatsnew/index.rst` and push:: git commit -am "back to development" git push origin $BRANCH diff --git a/docs/source/index.rst b/docs/source/index.rst index fd308e1d361..d64e4b8a234 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -15,6 +15,7 @@ IPython provides a rich toolkit to help you make the most out of using Python interactively. Its main components are: * A powerful interactive Python shell + * A `Jupyter `_ kernel to work with Python code in Jupyter notebooks and other interactive frontends. @@ -50,11 +51,11 @@ features: The Command line interface inherit all the above functionality and posses -* real multiline editting. +* real multi-line editing. * syntax highlighting as you type -* intgration with command line editor for a better workflow. +* integration with command line editor for a better workflow. The kernel also have its share of feature, when used with a compatible frontend it allows for: @@ -62,7 +63,7 @@ it allows for: * rich display system for object allowing to display Html, Images, Latex,Sounds Video. -* interactive widgets with the use of the ``ipywigets`` package. +* interactive widgets with the use of the ``ipywidgets`` package. This documentation will walk through most of the features of the IPython diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst index d50aaad7309..78c85360cd8 100644 --- a/docs/source/install/index.rst +++ b/docs/source/install/index.rst @@ -14,18 +14,16 @@ Installation -This sections will guide you into `installing IPython itself `_, and -installing `kernels for jupyter `_ if you are working with -multiple version of Python, or multiple environments. - -To know more, head to the next section. +This sections will guide you through `installing IPython itself `_, and +installing `kernels for Jupyter `_ if you wish to work with +multiple version of Python, or multiple environments. Quick install reminder ~~~~~~~~~~~~~~~~~~~~~~ -Here is a quick reminder of the various commands needed if you are already -familiar with IPython and are just searching to refresh your memory: +Here is a quick reminder of the commands needed for installation if you are +already familiar with IPython and are just searching to refresh your memory: Install IPython: diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index 4e73713d328..c6610ff4a99 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -14,10 +14,10 @@ With ``pip`` already installed : $ pip install ipython -This should install IPython as well as all the other dependency required. +This installs IPython as well as its dependencies. -If you try to use IPython with notebooks or the Qt console, you should also install -``jupyter``. +If you want to use IPython with notebooks or the Qt console, you should also +install Jupyter ``pip install jupyter``. @@ -44,15 +44,15 @@ Installing IPython itself ~~~~~~~~~~~~~~~~~~~~~~~~~ IPython requires several dependencies to work correctly, it is not recommended -to install IPython and all it's dependencies manually as this can be quite long and trouble some. -You should likely use the python package manager ``pip`` +to install IPython and all its dependencies manually as this can be quite long and troublesome. +You should use the python package manager ``pip``. Installation using pip ~~~~~~~~~~~~~~~~~~~~~~ -Make sure you have the latest version of :mod:`pip` ( the Python package +Make sure you have the latest version of :mod:`pip` (the Python package manager) installed. If you do not, head to `Pip documentation -`_ and install it first. +`_ and install :mod:`pip` first. The quickest way to get up and running with IPython is to install it with pip: @@ -81,9 +81,9 @@ Try to also avoid any usage of ``easy_install`` that can have similar undesirabl 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 -also install in user specific location by using the ``--user`` flag in conjunction with pip +also install in user specific location by using the ``--user`` flag in conjunction with pip. -To can run IPython's test suite, use the :command:`iptest` command from outside of the IPython source tree: +To run IPython's test suite, use the :command:`iptest` command from outside of the IPython source tree: .. code-block:: bash @@ -127,5 +127,6 @@ Dependencies IPython relies on a number of other Python packages. Installing using a package manager like pip or conda will ensure the necessary packages are installed. If you install manually, it's up to you to make sure dependencies are installed. -They're not listed here, because they may change from release to release, and -depending on platform so a static list will inevitably get out of date. +They're not listed here since a static list would inevitably fall out of date as +dependencies may change from release to release and also vary depending on +the platform. diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 0419b6c84d5..55c54ee7736 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -219,7 +219,7 @@ different numbers which correspond to the Process ID of the kernel. You can read more about using `jupyter qtconsole `_, and -`ipython notebook `_. There +`jupyter notebook `_. There is also a :ref:`message spec ` which documents the protocol for communication between kernels and clients. diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index fc2d1aaccff..be46ef69f98 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -126,8 +126,9 @@ Removed Feature Deprecated Features ------------------- -Some deprecated feature, don't forget to enable ``DeprecationWarning`` as error -of you are using IPython in Continuous Integration setup or in your testing in general: +Some deprecated features are listed in this section. Don't forget to enable +``DeprecationWarning`` as an error if you are using IPython in a Continuous +Integration setup or in your testing in general: .. code-block:: python @@ -135,12 +136,12 @@ of you are using IPython in Continuous Integration setup or in your testing in g warnings.filterwarnings('error', '.*', DeprecationWarning, module='yourmodule.*') -- ``hooks.fix_error_editor`` seem to be unused and is pending deprecation. +- ``hooks.fix_error_editor`` seems unused and is pending deprecation. - `IPython/core/excolors.py:ExceptionColors` is deprecated. -- `IPython.core.InteractiveShell:write()` is deprecated, use `sys.stdout` instead. -- `IPython.core.InteractiveShell:write_err()` is deprecated, use `sys.stderr` instead. -- The `formatter` keyword argument to `Inspector.info` in `IPython.core.oinspec` has now no effects. -- The `global_ns` keyword argument of IPython Embed was deprecated, and will now have no effect. Use `module` keyword argument instead. +- `IPython.core.InteractiveShell:write()` is deprecated; use `sys.stdout` instead. +- `IPython.core.InteractiveShell:write_err()` is deprecated; use `sys.stderr` instead. +- The `formatter` keyword argument to `Inspector.info` in `IPython.core.oinspec` has no effect. +- The `global_ns` keyword argument of IPython Embed was deprecated, and has no effect. Use `module` keyword argument instead. Known Issues: From f4fdafb6ef97d0d6f9c0a8de5dacfe26762a97cc Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 27 Jun 2016 14:13:08 -0700 Subject: [PATCH 0483/4859] One more pass on the docs. A few shuffling things around and remove old-inaccurate statements. --- docs/source/interactive/index.rst | 14 ++++- docs/source/interactive/magics.rst | 17 ++++++ docs/source/interactive/plotting.rst | 22 ++++--- docs/source/interactive/reference.rst | 84 ++++++++++++++------------ docs/source/interactive/tutorial.rst | 85 +++++++++++++++------------ 5 files changed, 138 insertions(+), 84 deletions(-) diff --git a/docs/source/interactive/index.rst b/docs/source/interactive/index.rst index a306258787d..9852e566122 100644 --- a/docs/source/interactive/index.rst +++ b/docs/source/interactive/index.rst @@ -2,16 +2,28 @@ Using IPython for interactive work ================================== +This section of IPython documentation walk you through most of the IPython +functionality. You do not need to have any deep knowledge of Python to read this +tutorial, though some section might make slightly more sens if you have already +done some work in the REPL. + +.. note:: + + Some part of this documentation are more than a decade old so might be out + of date, we welcome any report of inacuracy, and Pull Requests that make + that up to date. + .. toctree:: :maxdepth: 2 + :hidden: tutorial - magics plotting reference shell tips python-ipython-diff + magics .. seealso:: diff --git a/docs/source/interactive/magics.rst b/docs/source/interactive/magics.rst index 1a242894da5..520da1af2e2 100644 --- a/docs/source/interactive/magics.rst +++ b/docs/source/interactive/magics.rst @@ -2,4 +2,21 @@ Built-in magic commands ======================= +.. note:: + + To Jupyter users: Magics are specifit to the IPython kernel. Other kernels + may be implementing magics but this decision is a per-kernel one. To be able + to work, Magics need to use a syntax which is not valid in the language they + are implemented. IPython choosed the `%` as it is not a valid unary operator + in Python. It is in other languages. + + +Here is the help auto generated from the docstrings of all the available magics +function that IPython ships with. + +You can create an register your own magics with IPython. You can find many user +defined magics on `PyPI `_. Feel free to publish your own and +use the ``Framework :: IPython`` trove classifier. + + .. include:: magics-generated.txt diff --git a/docs/source/interactive/plotting.rst b/docs/source/interactive/plotting.rst index 473d52c8cf2..8d243d8c2d0 100644 --- a/docs/source/interactive/plotting.rst +++ b/docs/source/interactive/plotting.rst @@ -6,11 +6,11 @@ One major feature of the IPython kernel is the ability to display plots that are the output of running code cells. The IPython kernel is designed to work seamlessly with the matplotlib_ plotting library to provide this functionality. -To set this up, before any plotting is performed you must execute the -``%matplotlib`` :ref:`magic command `. This performs the -necessary behind-the-scenes setup for IPython to work correctly hand in hand -with ``matplotlib``; it does *not*, however, actually execute any Python -``import`` commands, that is, no names are added to the namespace. +To set this up, before any plotting or import of matplotlib is performed you +must execute the ``%matplotlib`` :ref:`magic command `. This +performs the necessary behind-the-scenes setup for IPython to work correctly +hand in hand with ``matplotlib``; it does *not*, however, actually execute any +Python ``import`` commands, that is, no names are added to the namespace. If the ``%matplotlib`` magic is called without an argument, the output of a plotting command is displayed using the default ``matplotlib`` @@ -25,12 +25,18 @@ Jupyter QtConsole. It can be invoked as follows:: %matplotlib inline -With this backend, the output of plotting commands is displayed *inline* -within the notebook, directly below the code cell that produced it. The -resulting plots will then also be stored in the notebook document. +With this backend, the output of plotting commands is displayed *inline* within +frontends like the Jupyter notebook, directly below the code cell that produced +it. The resulting plots will then also be stored in the notebook document. .. seealso:: `Plotting with Matplotlib`_ example notebook + +The matplotlib_ library also ships with ``%matplotlib notebook`` command that +allows interactive figures if your environment allows it. + +See the matplotlib_ documentation for more information. + .. include:: ../links.txt diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 1ba626625ea..3007eb512c3 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -11,20 +11,21 @@ You start IPython with the command:: $ ipython [options] files -If invoked with no options, it executes all the files listed in sequence -and drops you into the interpreter while still acknowledging any options -you may have set in your ipython_config.py. This behavior is different from -standard Python, which when called as python -i will only execute one -file and ignore your configuration setup. - -Please note that some of the configuration options are not available at -the command line, simply because they are not practical here. Look into -your configuration files for details on those. There are separate configuration -files for each profile, and the files look like :file:`ipython_config.py` or +If invoked with no options, it executes all the files listed in sequence and +exit. If you add the ``-i`` flag, it drops you into the interpreter while still +acknowledging any options you may have set in your ``ipython_config.py``. This +behavior is different from standard Python, which when called as python ``-i`` +will only execute one file and ignore your configuration setup. + +Please note that some of the configuration options are not available at the +command line, simply because they are not practical here. Look into your +configuration files for details on those. There are separate configuration files +for each profile, and the files look like :file:`ipython_config.py` or :file:`ipython_config_{frontendname}.py`. Profile directories look like -:file:`profile_{profilename}` and are typically installed in the :envvar:`IPYTHONDIR` directory, -which defaults to :file:`$HOME/.ipython`. For Windows users, :envvar:`HOME` -resolves to :file:`C:\\Users\\{YourUserName}` in most instances. +:file:`profile_{profilename}` and are typically installed in the +:envvar:`IPYTHONDIR` directory, which defaults to :file:`$HOME/.ipython`. For +Windows users, :envvar:`HOME` resolves to :file:`C:\\Users\\{YourUserName}` in +most instances. Command-line Options -------------------- @@ -36,6 +37,20 @@ alias to control them, but IPython lets you configure all of its objects from the command-line by passing the full class name and a corresponding value; type ``ipython --help-all`` to see this full list. For example:: +:: + $ ipython --help-all + <...snip...> + --matplotlib= (InteractiveShellApp.matplotlib) + Default: None + Choices: ['auto', 'gtk', 'gtk3', 'inline', 'nbagg', 'notebook', 'osx', 'qt', 'qt4', 'qt5', 'tk', 'wx'] + Configure matplotlib for interactive use with the default matplotlib + backend. + <...snip...> + + +Indicate that the following:: + + ipython --matplotlib qt is equivalent to:: @@ -145,9 +160,9 @@ use it: /home/fperez/ipython -Line magics, if they return a value, can be assigned to a variable using the syntax -``l = %sx ls`` (which in this particular case returns the result of `ls` as a python list). -See :ref:`below ` for more information. +Line magics, if they return a value, can be assigned to a variable using the +syntax ``l = %sx ls`` (which in this particular case returns the result of `ls` +as a python list). See :ref:`below ` for more information. Type ``%magic`` for more information, including a list of all available magic functions at any time and their docstrings. You can also type @@ -215,15 +230,6 @@ The dynamic object information functions (?/??, ``%pdoc``, directly on variables. For example, after doing ``import os``, you can use ``os.path.abspath??``. -.. _readline: - -Readline-based features ------------------------ - -These features require the GNU readline library, so they won't work if your -Python installation lacks readline support. We will first describe the default -behavior IPython uses, and then how to change it to suit your preferences. - Command line completion +++++++++++++++++++++++ @@ -313,8 +319,8 @@ before logging has been started. System shell access ------------------- -Any input line beginning with a ! character is passed verbatim (minus -the !, of course) to the underlying operating system. For example, +Any input line beginning with a ``!`` character is passed verbatim (minus +the ``!``, of course) to the underlying operating system. For example, typing ``!ls`` will run 'ls' in the current directory. .. _manual_capture: @@ -368,9 +374,9 @@ system shell commands. These aliases can have parameters. Then, typing ``alias_name params`` will execute the system command 'cmd params' (from your underlying operating system). -You can also define aliases with parameters using %s specifiers (one per +You can also define aliases with parameters using ``%s`` specifiers (one per parameter). The following example defines the parts function as an -alias to the command 'echo first %s second %s' where each %s will be +alias to the command ``echo first %s second %s`` where each ``%s`` will be replaced by a positional parameter to the call to %parts:: In [1]: %alias parts echo first %s second %s @@ -427,12 +433,14 @@ up for editing on the next command line. The following variables always exist: -* _i, _ii, _iii: store previous, next previous and next-next previous inputs. -* In, _ih : a list of all inputs; _ih[n] is the input from line n. If you - overwrite In with a variable of your own, you can remake the assignment to the - internal list with a simple ``In=_ih``. +* ``_i``, ``_ii``, ``_iii``: store previous, next previous and next-next + previous inputs. + +* ``In``, ``_ih`` : a list of all inputs; ``_ih[n]`` is the input from line + ``n``. If you overwrite In with a variable of your own, you can remake the + assignment to the internal list with a simple ``In=_ih``. -Additionally, global variables named _i are dynamically created ( +Additionally, global variables named ``_i`` are dynamically created (```` being the prompt counter), so ``_i == _ih[] == In[]``. For example, what you typed at prompt 14 is available as ``_i14``, ``_ih[14]`` @@ -443,10 +451,10 @@ by printing them out: they print like a clean string, without prompt characters. You can also manipulate them like regular variables (they are strings), modify or exec them. -You can also re-execute multiple lines of input easily by using the -magic :magic:`rerun` or :magic:`macro` functions. The macro system also allows you to re-execute -previous lines which include magic function calls (which require special -processing). Type %macro? for more details on the macro system. +You can also re-execute multiple lines of input easily by using the magic +:magic:`rerun` or :magic:`macro` functions. The macro system also allows you to +re-execute previous lines which include magic function calls (which require +special processing). Type %macro? for more details on the macro system. A history function :magic:`history` allows you to see any part of your input history by printing a range of the _i variables. diff --git a/docs/source/interactive/tutorial.rst b/docs/source/interactive/tutorial.rst index 1113d9a0e28..c8effca66ad 100644 --- a/docs/source/interactive/tutorial.rst +++ b/docs/source/interactive/tutorial.rst @@ -34,9 +34,8 @@ Tab completion Tab completion, especially for attributes, is a convenient way to explore the structure of any object you're dealing with. Simply type ``object_name.`` -to view the object's attributes (see :ref:`the readline section ` for -more). Besides Python objects and keywords, tab completion also works on file -and directory names. +to view the object's attributes. Besides Python objects and keywords, tab +completion also works on file and directory names. Exploring your objects ====================== @@ -53,15 +52,19 @@ Magic functions IPython has a set of predefined 'magic functions' that you can call with a command line style syntax. There are two kinds of magics, line-oriented and -cell-oriented. **Line magics** are prefixed with the ``%`` character and work much -like OS command-line calls: they get as an argument the rest of the line, where -arguments are passed without parentheses or quotes. **Cell magics** are -prefixed with a double ``%%``, and they are functions that get as an argument -not only the rest of the line, but also the lines below it in a separate -argument. +cell-oriented. **Line magics** are prefixed with the ``%`` character and work +much like OS command-line calls: they get as an argument the rest of the line, +where arguments are passed without parentheses or quotes. **Lines magics** can +return results and can be use in the right and side of an assignment. **Cell +magics** are prefixed with a double ``%%``, and they are functions that get as +an argument not only the rest of the line, but also the lines below it in a +separate argument. -The following examples show how to call the builtin :magic:`timeit` magic, both in -line and cell mode:: +Magics are useful as convenient functions where Python syntax is not the most +natural one, or when one want to embed invalid python syntax in their work flow. + +The following examples show how to call the builtin :magic:`timeit` magic, both +in line and cell mode:: In [1]: %timeit range(1000) 100000 loops, best of 3: 7.76 us per loop @@ -73,20 +76,23 @@ line and cell mode:: The builtin magics include: -- Functions that work with code: :magic:`run`, :magic:`edit`, :magic:`save`, :magic:`macro`, - :magic:`recall`, etc. -- Functions which affect the shell: :magic:`colors`, :magic:`xmode`, :magic:`autoindent`, - :magic:`automagic`, etc. -- Other functions such as :magic:`reset`, :magic:`timeit`, :cellmagic:`writefile`, :magic:`load`, or - :magic:`paste`. +- Functions that work with code: :magic:`run`, :magic:`edit`, :magic:`save`, + :magic:`macro`, :magic:`recall`, etc. + +- Functions which affect the shell: :magic:`colors`, :magic:`xmode`, + :magic:`autoindent`, :magic:`automagic`, etc. + +- Other functions such as :magic:`reset`, :magic:`timeit`, + :cellmagic:`writefile`, :magic:`load`, or :magic:`paste`. -You can always call them using the ``%`` prefix, and if you're calling a line -magic on a line by itself, you can omit even that:: +You can always call magics using the ``%`` prefix, and if you're calling a line +magic on a line by itself, as long as the identifier is not defined in your +namespace, you can omit even that:: run thescript.py -You can toggle this behavior by running the :magic:`automagic` magic. Cell magics -must always have the ``%%`` prefix. +You can toggle this behavior by running the :magic:`automagic` magic. Cell +magics must always have the ``%%`` prefix. A more detailed explanation of the magic system can be obtained by calling ``%magic``, and for more details on any magic function, call ``%somemagic?`` to @@ -95,18 +101,20 @@ read its docstring. To see all the available magic functions, call .. seealso:: - :doc:`magics` + The :ref:`magic` section of the documentation goes more in depth into how + the magics works and how to define your own, and :doc:`magics` for a list of + built-in magics. `Cell magics`_ example notebook Running and Editing ------------------- -The :magic:`run` magic command allows you to run any python script and load all of -its data directly into the interactive namespace. Since the file is re-read +The :magic:`run` magic command allows you to run any python script and load all +of its data directly into the interactive namespace. Since the file is re-read from disk each time, changes you make to it are reflected immediately (unlike -imported modules, which have to be specifically reloaded). IPython also -includes :ref:`dreload `, a recursive reload function. +imported modules, which have to be specifically reloaded). IPython also includes +:ref:`dreload `, a recursive reload function. ``%run`` has special flags for timing the execution of your scripts (-t), or for running them under the control of either Python's pdb debugger (-d) or @@ -114,7 +122,9 @@ profiler (-p). The :magic:`edit` command gives a reasonable approximation of multiline editing, by invoking your favorite editor on the spot. IPython will execute the -code you type in there as if it were typed interactively. +code you type in there as if it were typed interactively. Note that for +:magic:`edit` to work, the call to startup your editor have to be a blocking +call. In a GUI environment, your editor likely have such an option. Debugging --------- @@ -122,9 +132,9 @@ Debugging After an exception occurs, you can call :magic:`debug` to jump into the Python debugger (pdb) and examine the problem. Alternatively, if you call :magic:`pdb`, IPython will automatically start the debugger on any uncaught exception. You can -print variables, see code, execute statements and even walk up and down the -call stack to track down the true source of the problem. This can be an efficient -way to develop and debug code, in many cases eliminating the need for print +print variables, see code, execute statements and even walk up and down the call +stack to track down the true source of the problem. This can be an efficient way +to develop and debug code, in many cases eliminating the need for print statements or external debugging tools. You can also step through a program from the beginning by calling @@ -157,7 +167,7 @@ This will take line 3 and lines 18 to 20 from the current session, and lines System shell commands ===================== -To run any command at the system shell, simply prefix it with !, e.g.:: +To run any command at the system shell, simply prefix it with ``!``, e.g.:: !ping www.bbc.co.uk @@ -169,12 +179,13 @@ with $: ``!grep -rF $pattern ipython/*``. See :ref:`our shell section Define your own system aliases ------------------------------ -It's convenient to have aliases to the system commands you use most often. -This allows you to work seamlessly from inside IPython with the same commands -you are used to in your system shell. IPython comes with some pre-defined -aliases and a complete system for changing directories, both via a stack (see -:magic:`pushd`, :magic:`popd` and :magic:`dhist`) and via direct :magic:`cd`. The latter keeps a history of -visited directories and allows you to go to any previously visited one. +It's convenient to have aliases to the system commands you use most often. This +allows you to work seamlessly from inside IPython with the same commands you are +used to in your system shell. IPython comes with some pre-defined aliases and a +complete system for changing directories, both via a stack (see :magic:`pushd`, +:magic:`popd` and :magic:`dhist`) and via direct :magic:`cd`. The latter keeps a +history of visited directories and allows you to go to any previously visited +one. Configuration From 387a17c1b61e86fff75ce7ff10fd746b3a3fb5db Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 27 Jun 2016 14:37:02 -0700 Subject: [PATCH 0484/4859] 'update intersphinx' --- docs/source/conf.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 8e0e6fff35a..14f2d5348f5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -216,12 +216,12 @@ def is_stable(extra): # Output file base name for HTML help builder. htmlhelp_basename = 'ipythondoc' -intersphinx_mapping = {'python': ('http://docs.python.org/3/', None), - 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), - 'traitlets': ('http://traitlets.readthedocs.io/en/latest/', None), - 'jupyterclient': ('http://jupyter-client.readthedocs.io/en/latest/', None), - 'ipyparallel': ('http://ipyparallel.readthedocs.io/en/latest/', None), - 'jupyter': ('http://jupyter.readthedocs.io/en/latest/', None), +intersphinx_mapping = {'python': ('https://docs.python.org/3/', None), + 'rpy2': ('https://rpy2.readthedocs.io/en/version_2.8.x/', None), + 'traitlets': ('https://traitlets.readthedocs.io/en/latest/', None), + 'jupyterclient': ('https://jupyter-client.readthedocs.io/en/latest/', None), + 'ipyparallel': ('https://ipyparallel.readthedocs.io/en/latest/', None), + 'jupyter': ('https://jupyter.readthedocs.io/en/latest/', None), } # Options for LaTeX output From 1b77b06604ee01c7e90f52c453366014ee21a588 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 27 Jun 2016 14:51:04 -0700 Subject: [PATCH 0485/4859] 'fix some indent warnigns' --- docs/source/interactive/reference.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 3007eb512c3..447880c1192 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -37,7 +37,6 @@ alias to control them, but IPython lets you configure all of its objects from the command-line by passing the full class name and a corresponding value; type ``ipython --help-all`` to see this full list. For example:: -:: $ ipython --help-all <...snip...> --matplotlib= (InteractiveShellApp.matplotlib) @@ -50,12 +49,12 @@ the command-line by passing the full class name and a corresponding value; type Indicate that the following:: + $ ipython --matplotlib qt - ipython --matplotlib qt is equivalent to:: - ipython --TerminalIPythonApp.matplotlib='qt' + $ ipython --TerminalIPythonApp.matplotlib='qt' Note that in the second form, you *must* use the equal sign, as the expression is evaluated as an actual Python assignment. While in the above example the From 1f6c347842ca53830d238956c21318f51a0ab51d Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Mon, 27 Jun 2016 16:24:24 -0700 Subject: [PATCH 0486/4859] Edits to magics doc --- docs/source/interactive/magics.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/source/interactive/magics.rst b/docs/source/interactive/magics.rst index 520da1af2e2..0cc1c4f3315 100644 --- a/docs/source/interactive/magics.rst +++ b/docs/source/interactive/magics.rst @@ -4,12 +4,13 @@ Built-in magic commands .. note:: - To Jupyter users: Magics are specifit to the IPython kernel. Other kernels - may be implementing magics but this decision is a per-kernel one. To be able - to work, Magics need to use a syntax which is not valid in the language they - are implemented. IPython choosed the `%` as it is not a valid unary operator - in Python. It is in other languages. - + To Jupyter users: Magics are specific to and provided by the IPython kernel. + Whether magics are available on a kernel is a decision that is made by + the kernel developer on a per-kernel basis. To work properly, Magics must + use a syntax element which is not valid in the underlying language. For + example, the IPython kernel uses the `%` syntax element for magics as `%` + is not a valid unary operator in Python. While, the syntax element has + meaning in other languages. Here is the help auto generated from the docstrings of all the available magics function that IPython ships with. From ae45e283fe7f481d80a4f8a97ae179456723c17c Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Mon, 27 Jun 2016 16:25:36 -0700 Subject: [PATCH 0487/4859] Edits to reference doc --- docs/source/interactive/reference.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/interactive/reference.rst b/docs/source/interactive/reference.rst index 447880c1192..c18e32fb8ca 100644 --- a/docs/source/interactive/reference.rst +++ b/docs/source/interactive/reference.rst @@ -12,7 +12,7 @@ You start IPython with the command:: $ ipython [options] files If invoked with no options, it executes all the files listed in sequence and -exit. If you add the ``-i`` flag, it drops you into the interpreter while still +exits. If you add the ``-i`` flag, it drops you into the interpreter while still acknowledging any options you may have set in your ``ipython_config.py``. This behavior is different from standard Python, which when called as python ``-i`` will only execute one file and ignore your configuration setup. From c276c550cac332afb116b645f4b78ce4dcc12b96 Mon Sep 17 00:00:00 2001 From: Carol Willing Date: Mon, 27 Jun 2016 16:27:03 -0700 Subject: [PATCH 0488/4859] Minor edits to tutorial doc --- docs/source/interactive/tutorial.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/interactive/tutorial.rst b/docs/source/interactive/tutorial.rst index c8effca66ad..b6fd550647a 100644 --- a/docs/source/interactive/tutorial.rst +++ b/docs/source/interactive/tutorial.rst @@ -55,7 +55,7 @@ command line style syntax. There are two kinds of magics, line-oriented and cell-oriented. **Line magics** are prefixed with the ``%`` character and work much like OS command-line calls: they get as an argument the rest of the line, where arguments are passed without parentheses or quotes. **Lines magics** can -return results and can be use in the right and side of an assignment. **Cell +return results and can be used in the right hand side of an assignment. **Cell magics** are prefixed with a double ``%%``, and they are functions that get as an argument not only the rest of the line, but also the lines below it in a separate argument. @@ -123,8 +123,8 @@ profiler (-p). The :magic:`edit` command gives a reasonable approximation of multiline editing, by invoking your favorite editor on the spot. IPython will execute the code you type in there as if it were typed interactively. Note that for -:magic:`edit` to work, the call to startup your editor have to be a blocking -call. In a GUI environment, your editor likely have such an option. +:magic:`edit` to work, the call to startup your editor has to be a blocking +call. In a GUI environment, your editor likely will have such an option. Debugging --------- From 7b70143b6f1567e2b45c059daa696a1ff1c09f42 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 28 Jun 2016 15:42:39 +0100 Subject: [PATCH 0489/4859] Fix switching prompts in doctest mode --- IPython/terminal/interactiveshell.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 86326a95b88..4dcb2800789 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -98,6 +98,7 @@ def _space_for_menu_changed(self, old, new): pt_cli = None debugger_history = None + _pt_app = None simple_prompt = Bool(_use_simple_prompt, help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. @@ -203,7 +204,6 @@ def init_display_formatter(self): self.display_formatter.active_types = ['text/plain'] def init_prompt_toolkit_cli(self): - self._app = None if self.simple_prompt: # Fall back to plain non-interactive output for tests. # This is very limited, and only accepts a single line. @@ -350,7 +350,7 @@ def _paste(event): editing_mode = getattr(EditingMode, self.editing_mode.upper()) - self._app = create_prompt_application( + self._pt_app = create_prompt_application( editing_mode=editing_mode, key_bindings_registry=kbmanager.registry, history=history, @@ -361,7 +361,7 @@ def _paste(event): **self._layout_options() ) self._eventloop = create_eventloop(self.inputhook) - self.pt_cli = CommandLineInterface(self._app, eventloop=self._eventloop) + self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self._eventloop) def _make_style_from_name(self, name): """ @@ -432,8 +432,8 @@ def _update_layout(self): Ask for a re computation of the application layout, if for example , some configuration options have changed. """ - if getattr(self, '._app', None): - self._app.layout = create_prompt_layout(**self._layout_options()) + if self._pt_app: + self._pt_app.layout = create_prompt_layout(**self._layout_options()) def prompt_for_code(self): document = self.pt_cli.run( @@ -563,6 +563,7 @@ def switch_doctest_mode(self, mode): elif self._prompts_before: self.prompts = self._prompts_before self._prompts_before = None + self._update_layout() InteractiveShellABC.register(TerminalInteractiveShell) From 7b3d1e9ae99dc2c06866392d9e760a700a369fca Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 28 Jun 2016 17:41:43 +0100 Subject: [PATCH 0490/4859] Create method on parent class to get rid of warning A magic calls this, and it was failing when used in ipykernel --- IPython/core/interactiveshell.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3157d7c8c79..cb2e36195e3 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -649,6 +649,10 @@ def init_syntax_highlighting(self): pyformat = PyColorize.Parser().format self.pycolorize = lambda src: pyformat(src,'str',self.colors) + def refresh_style(self): + # No-op here, used in subclass + pass + def init_pushd_popd_magic(self): # for pushd/popd management self.home_dir = get_home_dir() From 69d2a89c417c09277f6b0f3858c901936d85b6a5 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 28 Jun 2016 17:45:11 +0100 Subject: [PATCH 0491/4859] Remove outdated colors_force attribute --- IPython/core/interactiveshell.py | 9 --------- IPython/core/magics/basic.py | 27 ++++++--------------------- IPython/terminal/interactiveshell.py | 2 -- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index cb2e36195e3..3eeb0491d7d 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -254,15 +254,6 @@ class InteractiveShell(SingletonConfigurable): default_value=get_default_colors(), help="Set the color scheme (NoColor, Linux, or LightBG)." ).tag(config=True) - colors_force = Bool(False, help= - """ - Force use of ANSI color codes, regardless of OS and readline - availability. - """ - # FIXME: This is essentially a hack to allow ZMQShell to show colors - # without readline on Win32. When the ZMQ formatting system is - # refactored, this should be removed. - ) debug = Bool(False).tag(config=True) deep_reload = Bool(False, help= """ diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 1108ffbe1c1..b70f977bdb5 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -335,31 +335,16 @@ def color_switch_err(name): # local shortcut shell = self.shell - - - if not shell.colors_force: - if sys.platform in {'win32', 'cli'}: - import IPython.utils.rlineimpl as readline - if not readline.have_readline: - msg = """\ -Proper color support under MS Windows requires the pyreadline library. -You can find it at: -http://ipython.org/pyreadline.html - -Defaulting color scheme to 'NoColor'""" - new_scheme = 'NoColor' - warn(msg) - - elif not shell.has_readline: - # Coloured prompts get messed up without readline - # Will remove this check after switching to prompt_toolkit - new_scheme = 'NoColor' + # Set shell colour scheme + try: + shell.colors = new_scheme + shell.refresh_style() + except: + color_switch_err('shell') # Set exception colors try: shell.InteractiveTB.set_colors(scheme = new_scheme) - shell.colors = new_scheme - shell.refresh_style() shell.SyntaxTB.set_colors(scheme = new_scheme) except: color_switch_err('exception') diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 86326a95b88..7c0f94c98c5 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -87,8 +87,6 @@ def get_default_editor(): _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) class TerminalInteractiveShell(InteractiveShell): - colors_force = True - space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' 'to reserve for the completion menu' ).tag(config=True) From 78907568be7d3eed934e8dd13005d963ab252835 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 28 Jun 2016 13:51:19 -0700 Subject: [PATCH 0492/4859] Make everyone happy with a neutral colortheme by default. --- IPython/core/debugger.py | 6 ++++- IPython/core/excolors.py | 31 +++++++++++++++++++++++++- IPython/core/interactiveshell.py | 14 +++++------- IPython/core/magics/basic.py | 2 +- IPython/core/ultratb.py | 3 +++ IPython/terminal/interactiveshell.py | 9 +++++++- IPython/utils/PyColorize.py | 29 +++++++++++++++++++++++- IPython/utils/colorable.py | 2 +- IPython/utils/tests/test_pycolorize.py | 2 +- 9 files changed, 83 insertions(+), 15 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index bc3ba778986..e97eb7ab8a2 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -233,6 +233,10 @@ def __init__(self,color_scheme='NoColor',completekey=None, cst['LightBG'].colors.breakpoint_enabled = C.LightRed cst['LightBG'].colors.breakpoint_disabled = C.Red + cst['Neutral'].colors.prompt = C.Blue + 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 @@ -313,7 +317,7 @@ def print_stack_trace(self, context=None): except KeyboardInterrupt: pass - def print_stack_entry(self,frame_lineno,prompt_prefix='\n-> ', + def print_stack_entry(self,frame_lineno, prompt_prefix='\n-> ', context=None): if context is None: context = self.context diff --git a/IPython/core/excolors.py b/IPython/core/excolors.py index 9d5725890bd..279924bd6ce 100644 --- a/IPython/core/excolors.py +++ b/IPython/core/excolors.py @@ -18,7 +18,7 @@ def exception_colors(): """Return a color table with fields for exception reporting. The table is an instance of ColorSchemeTable with schemes added for - 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled + 'Neutral', 'Linux', 'LightBG' and 'NoColor' and fields for exception handling filled in. Examples: @@ -127,6 +127,35 @@ def exception_colors(): Normal = C.Normal, )) + ex_colors.add_scheme(ColorScheme( + 'Neutral', + # The color to be used for the top line + topline = C.Red, + + # The colors to be used in the traceback + filename = C.LightGreen, + lineno = C.LightGreen, + name = C.LightPurple, + vName = C.Cyan, + val = C.LightGreen, + em = C.Cyan, + + # Emphasized colors for the last frame of the traceback + normalEm = C.Cyan, + filenameEm = C.Green, + linenoEm = C.Green, + nameEm = C.Purple, + valEm = C.Blue, + + # Colors for printing the exception + excName = C.Red, + #line = C.Brown, # brown often is displayed as yellow + line = C.Red, + caret = C.Normal, + Normal = C.Normal, + )) + + return ex_colors class Deprec(object): diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 3157d7c8c79..481f1e99292 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -137,12 +137,10 @@ class SpaceInInput(Exception): pass def get_default_colors(): - if sys.platform=='darwin': - return "LightBG" - elif os.name=='nt': - return 'Linux' - else: - return 'Linux' + "DEPRECATED" + warn('get_default_color is Deprecated, and is `Neutral` on all platforms.', + DeprecationWarning, stacklevel=2) + return 'Neutral' class SeparateUnicode(Unicode): @@ -250,8 +248,8 @@ class InteractiveShell(SingletonConfigurable): get confused with color codes, this capability can be turned off. """ ).tag(config=True) - colors = CaselessStrEnum(('NoColor','LightBG','Linux'), - default_value=get_default_colors(), + colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'), + default_value='Neutral', help="Set the color scheme (NoColor, Linux, or LightBG)." ).tag(config=True) colors_force = Bool(False, help= diff --git a/IPython/core/magics/basic.py b/IPython/core/magics/basic.py index 1108ffbe1c1..692ea32a0d6 100644 --- a/IPython/core/magics/basic.py +++ b/IPython/core/magics/basic.py @@ -325,7 +325,7 @@ def colors(self, parameter_s=''): """ def color_switch_err(name): warn('Error changing %s color schemes.\n%s' % - (name, sys.exc_info()[1])) + (name, sys.exc_info()[1]), stacklevel=2) new_scheme = parameter_s.strip() diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 38ba74eac0b..3e636b3d848 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -67,6 +67,9 @@ - LightBG: similar to Linux but swaps dark/light colors to be more readable in light background terminals. + - Neutral: a neutral color scheme that should be readable on both light and + dark background + You can implement other color schemes easily, the syntax is fairly self-explanatory. Please send back new schemes you develop to the author for possible inclusion in future releases. diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 86326a95b88..a0277e101e1 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -369,6 +369,7 @@ def _make_style_from_name(self, name): We need that to add style for prompt ... etc. """ + style_overrides = {} if name == 'legacy': legacy = self.colors.lower() if legacy == 'linux': @@ -376,10 +377,12 @@ def _make_style_from_name(self, name): style_overrides = _style_overrides_linux elif legacy == 'lightbg': style_overrides = _style_overrides_light_bg - style_cls = get_style_by_name('default') + style_cls = get_style_by_name('pastie') + elif legacy == 'neutral': # The default theme needs to be visible on both a dark background # and a light background, because we can't tell what the terminal # looks like. These tweaks to the default theme help with that. + style_cls = get_style_by_name('default') style_overrides.update({ Token.Number: '#007700', Token.Operator: 'noinherit', @@ -387,6 +390,10 @@ def _make_style_from_name(self, name): Token.Name.Function: '#2080D0', Token.Name.Class: 'bold #2080D0', Token.Name.Namespace: 'bold #2080D0', + Token.Prompt: '#009900', + Token.PromptNum: '#00ff00 bold', + Token.OutPrompt: '#990000', + Token.OutPromptNum: '#ff0000 bold', }) elif legacy =='nocolor': style_cls=_NoStyle diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index def43864f22..1dda22f9a52 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -122,6 +122,32 @@ 'normal' : Colors.Normal # color off (usu. Colors.Normal) } ) +NeutralColors = ColorScheme( + 'Neutral',{ + 'header' : Colors.Red, + token.NUMBER : Colors.Cyan, + token.OP : Colors.Blue, + token.STRING : Colors.Blue, + tokenize.COMMENT : Colors.Red, + token.NAME : Colors.Normal, + token.ERRORTOKEN : Colors.Red, + + _KEYWORD : Colors.Green, + _TEXT : Colors.Blue, + + 'in_prompt' : InputTermColors.Blue, + 'in_number' : InputTermColors.LightBlue, + 'in_prompt2' : InputTermColors.Blue, + 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal) + + 'out_prompt' : Colors.Red, + 'out_number' : Colors.LightRed, + + 'normal' : Colors.Normal # color off (usu. Colors.Normal) + } ) + + + LightBGColors = ColorScheme( 'LightBG',{ 'header' : Colors.Red, @@ -132,6 +158,7 @@ token.NAME : Colors.Normal, token.ERRORTOKEN : Colors.Red, + _KEYWORD : Colors.Green, _TEXT : Colors.Blue, @@ -147,7 +174,7 @@ } ) # Build table of color schemes (needed by the parser) -ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors], +ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors, NeutralColors], _scheme_default) class Parser(Colorable): diff --git a/IPython/utils/colorable.py b/IPython/utils/colorable.py index 77e9dbf904f..9f7c5ac213c 100644 --- a/IPython/utils/colorable.py +++ b/IPython/utils/colorable.py @@ -16,7 +16,7 @@ from traitlets import Unicode -available_themes = lambda : [s for s in pygments.styles.get_all_styles()]+['NoColor','LightBG','Linux'] +available_themes = lambda : [s for s in pygments.styles.get_all_styles()]+['NoColor','LightBG','Linux', 'Neutral'] class Colorable(Configurable): """ diff --git a/IPython/utils/tests/test_pycolorize.py b/IPython/utils/tests/test_pycolorize.py index 2a2ff334993..6c7f36e76e1 100644 --- a/IPython/utils/tests/test_pycolorize.py +++ b/IPython/utils/tests/test_pycolorize.py @@ -49,7 +49,7 @@ def __init__(self): def test_loop_colors(): - for scheme in ('Linux', 'NoColor','LightBG'): + for scheme in ('Linux', 'NoColor','LightBG', 'Neutral'): def test_unicode_colorize(): p = Parser() From 07fa0f4acc63be63be8784cffbfe81e3791e4f8f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Jun 2016 14:08:21 +0100 Subject: [PATCH 0493/4859] Improve release notes and config details --- IPython/core/interactiveshell.py | 2 +- docs/source/_images/ptshell_features.png | Bin 0 -> 13520 bytes docs/source/config/details.rst | 153 +++++++++++------------ docs/source/whatsnew/version5.rst | 118 +++++++++-------- 4 files changed, 132 insertions(+), 141 deletions(-) create mode 100644 docs/source/_images/ptshell_features.png diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 481f1e99292..a4adebe6e44 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -250,7 +250,7 @@ class InteractiveShell(SingletonConfigurable): ).tag(config=True) colors = CaselessStrEnum(('Neutral', 'NoColor','LightBG','Linux'), default_value='Neutral', - help="Set the color scheme (NoColor, Linux, or LightBG)." + help="Set the color scheme (NoColor, Neutral, Linux, or LightBG)." ).tag(config=True) colors_force = Bool(False, help= """ diff --git a/docs/source/_images/ptshell_features.png b/docs/source/_images/ptshell_features.png new file mode 100644 index 0000000000000000000000000000000000000000..79d4b0025764f72a7d38a09af2eef353f749b49d GIT binary patch literal 13520 zcmbumWl$Ya*Di>=1$WQE-Q6v?LvTH~ySqzp2oAvs65K7gTX467YjC+I?>F;}+&uJ&IkDd{F|?-fO!pz5Z8)1{)D_sy+1P}hO0qK_*t!Vkv%hCr#sJuc zNaanDJ>sLg3PR?RHcgJ+%%+ei?dhO=0&8rUjR~fv@(d1zfrmM5iin7a^g=?p3kw>_ zDJjQWJtE==6wEA#-yMQ5#G}5`^ob%+guy^lgkfN!gkgx2{~N>ne-X=hGeiO1cW^v# zyi0EKUw}2kz19t01(Aub1F@KVi*C?UZD=4}(9z%COEiZ89Ix&Xvs!3697nB+iC&BX zmTlPOAf0U)^3v~l4XfUm6J(u|@JbvZ1a_YrO0zYHboFkx$XeJOC+H0I-rz*SX-uk) zxzm2PAqq*a5BRd67hP}fbk=<)(44o&Y*HHSGlp@}Od7W99T(N&Y69S90tJ;l*m`($ ztz0A^JiE_j-g=a8#=^YRkUrooA!`Y?T3{S1N4iRZZH(JG*)GxAW=WF`rdet=%&`h$H zfA%|W7b=+MInKFP$|?@A4vHa|Dx6fAx99tpkL(u5)|3GF!0i+~5sPzwBH5&QXjR!! zA=~e&YBRa6oJa6b9IUt?$v#y%&USS{)uwpPrzdu66LR~X(t7j)SJrS2(w>J#5HuvO zFL@vnrj7t<$S5db@s@cUd|3Tx;gDEZE$A2IH+y7q7_0CLNeJvZ_{WvUZsHv1vO1>? z-#EwfZ~|GO=Jd8{C5z{2nsI`j$ps*T(M;8h8EW*l5?YRSEp+iya=lwA-35esefr}1 zfS=Mgz3xMsJP=0}H;99t!>4Bw9*xl5FSsN4d1xB3m)>}*%`)TC6$FDKL$=&ngf3VV zWEA%dfoqJ>j`aYM9Ng49)gSLsye5%2Pj%r6H_4}<L*R;d?zjj+U*W!QkqOuz@`K)kMWpcd0n1h*dKH>*}NN#!=H)lmT=sT4>j=i+kq-= zroU|bMj1JIW-9a|f38V5pCHURn9GRf5@DxLFy$3sf`X>>;~AnWcmR~(%6tXw)UJ~2 zcDFtY9J(}{9SH0mx*Wgdg&x1K?iAyx=xW95-XuCu%op?2TwwlEj z`knvTA%?%^25Tg`mtyaQdRwdj(W!GzkGbF`I+H{UX4~5y$BqSF2Lc8{kKyWJIL?J; z25lMbRrQCGyx9w1FXJ7-A17mcC$4sAMnOAYl*ciz2?7#P;(|G}Uv9x~PCf!1O57H6 zt-5i?pgtLzC0*uZbJ9u+1wrjA-C=Kybz8Sr-G*I*0MJhG&!jc7D(xu#cnYl+ovA%$nL^L?mS(1Pq<8OMPBYh{kPS~6` znVY)~7B+WD?XQo^vN4lCgr}%Gv>pb-fV|Rh+X*z?I`o(*U-sfJ8bj$oj|F$i4ztsR z`PWU2RPG{opYDGSzB0pa%+lAjKJ8jh0qFV4JWvXM7u04#TS4fD3RC&x`QvJ81kl%8 zZ?E(gXYR!lQ>OO}s*hJy)faJBtr{DDT(W8&Yn_(HuBhv*U4wpUcFuWynqGgywjG#r zMs3fk4G1U-A<{tWOpEcmiEGz<9nzZ_5XuA9zcqlAd|k2>`>noNCPtP>(fMvXfr?N2 zU67lz@}1K)vKhL&neQJ}e1Aj7&H$@O=!Eezg|2Rc?!xZc{b#ewT{13(XwPQ`xEvN6 z-_(be4ne*c5bXp;X3mczJsJ-7ZSBZszCglD#?_IU9?wth&Yt!DV&2P9JT;^aic}Lp zh{%6p$@X$*C4{nPftsosXS*;jw7RisC(E_n)*%6bNE!VDs>j32xM=o~FxqP}Wolzy zDHDGM=9fgW2LzPxTup*GCS^nh^=cJLS}qUPxb$nj2y5X4|MvNon9f#3g;>yLZ!WhN-;fX$a)inpb+dwbm)Z_G2Btz>~78Y zeps03@j_^%PPZJH5G4bj^id#kO_w7Qjqa0YBH&{bud3t^&65l!o~{~^c9?GB@d z5NGTInSY`%%Xya*WgDGSU}63Xkp+&FgK)##Zlx-WfZq1=8t8RI?GN8g`&qChE3CFs zICMVV?K4EfmXo1ZJ_hrhLk8^H!mFCXC8`pSjC5K5Bls zL@^||{PW3|qRjEIQCR7RFt%=sC7cNUJjrtAW?hYzgx)Ib>fc{gnTMLkzUKX2{r>UZ z8Y(r7QYIfHGwDw|=``QO`trr8xqsZVH|~&YG4s2HbNFm-L3T%Ipbo=BA;DH&iuZmW zV&gBZQYC^oYH>10-SOKuzms)w6ik%g;eNCEadX<040^8H+(_RN%9MB6xAA^A zyP}<^Gsj}*?TvS)6?QJ!t3xPp5=T;XTSm^98(DZ$s480QSw5f=jA6Xd{UpznXTHw8J8^!nwSc|IZ}AqDCO{F&bpOt1-O0OwzW<3@Opn^Q~4{di>QRy z;H5u(axVujxS&N?Kuc&kvrh*b&}7l5j#u^LJt3NPpL4xMb4zV+ANo=;sJ!Xwgusj= z?`mOjW=)=jFEtCv)}!xL9adg1YhznvqaaY->H@K5=)^nl4Y7gpZbLG&@D#^M2Hxrb zsg2<3i1hJBr!RgH0K{J*azF|30Yu3!&_v-eikOCoh3?EA*14hj;S4-w{7yF`(@J9( zAyP8*0)7YiY-QNloy3-{!D#)I-MtHDdezv1Mkd(LC{q&VkGGoDjG!t0fZv^V)XtI% zv#A*8z{gf}aQ!8%r|u27bHAel38FHC8e<54l8c!8@ zRsf&yyW@k4F2!|U>MB#8Rz`#;)_rStDvj$Qd2i z5`j}3F}7Jrl2(6S*8dDgl4bB-l`a*4r&EKwP0>Cr>|$SxtVARl4M_yALR*cUfXL^K z8rh<@@~f6wu@@3Raw z(ln6Ri!+#LtshVI+aBUlQxKJ&@%^Vaw&iS?(3o+kO!zH_kOowWyP5D{h_TH`%@Vfx12IteeVLFVM5uH5f;@lfUH3$ z$`0!DbF;D4Tr!>)i)~P1uqlLTG^z@dpU>$ww**X%5WEfmyu@&}3B5y^A0%AsNmXOv}6JV}9rK z^KU=%S^Nq9N4-^wbpLl!ld7X%M`SFe-RV)6&$oCx49dB#P{DM)XylElLuub7%RSot zLi-N3O;I&heO=&b#>W(})eq!+=~);)8NR@VKyO!aJ5AHJzHv@0LzE$r0IJykq}S20 zX3MWwSmN`b06O|x3hQ`qa=NyYC=!~M%u^Qw`+rf&95)Nfsv2{x+SEv-Usj%AZ zfyz_~0{1{%hf*s7!^sy^9GHU&1ekGa=+1a~&TA?63fV&fu?b1YnNy8bPIGycMK?Pm zhz5r|!JabxB#JvF2qSXyDK!Q}1L)D8&wPk}9|d^|Iq`^TIR_6Qwm*qKGC!WDZYIzT zTOt7Y~8B_(WZn30%^jVgRfmljYl#62;HOD-Ni~aBn7|qboc~kt0lLL%MI`K z0WYEEJWYqIr@y9Bi}Xw>h5m}hj*D>ye@=v_->Yf(bj%1cLqvNWF@{rvCKY z+)6Fpq;by2L95)K6{}mu{Hw6`>{?WLH6Zk2fx(pPxwPSQ=Ear-cBN;G0ai#w2+3d3 zgSifu*REDYx(Giq`CfxvRlz&6*CvA0z$C=kOihd5ZVl0B4P6c=%pqdhXF##bxE0ZK z+K{&h!yCi0eIPe?Cvd31#T1jc`7+2)=M~=TZ+Lb@P?@fyz-Jr}eiuNM@g=tx1&+fp zL?S^S?=hnvsU`6W!*UnS=17p<>Og}*JinY%Iq3MS@L590x5GMyQg(IKG{2ro!9sO9 zMv&D-aQ8}eT`uT#Jv=o_vb?#HYt;USMyHO7V8ZVG*BRVMc@hQeJ!9t^F@HDslQv7P zt@Kq5o6{G~3bl+B1Uc4Lm@m0#aJ1E8He#v0}oPr@%fsupsf zPtL#jjA_i*R;VNytF&y^BH`KEavfw?mE62*)kZE<^&Yia%AaR(U}UgRsZOBQ)*Abk zU=7|K94pF|+gO#B(`SHQER-p+*;9|W7rUs%lh>sYC?uKMzsrIz@kz$y|KUd%;s}Uv z;AGpkf8&sGF8s{dXgWjbT5;MijEuJb!ZWIW;%Wo;?4Vl(pyiWz6jHljD5U=LsC^hl zKV-%cYZ5p~cl(d#p>^GN=`mIOdmwt1L&02`cQ3~9;eDF0=HIQPRaZ-6W!@B-6*+5W zX%dRC*0_<%67a`uX0w99uOOuQpYnVKW0|K9M}@kVx3YL`&SD6v53;P~luD@Zx7&LU z?EPD9rP-8W7-$Ss_?g$;H>z5nSC&P7GR;jcQhT$6VJw#YHa50jPo%r7*}1CmBsezf zcVpB0JVkXGj#1Q}hJmsUx>*o3B=CyRUD_N?Zu}w`>}W)q+Y>s%7_NqtmhyYleg1g& zYk9J~{7_G4X5j9PTkd*8*!gQXjQ~-aeh0^GD&_NhcPmk#sr>^Zye6)^jCcN8oa;7r zfKZ-z_uO=viyLY~4f^kr8FgJk^u1%g@#O%)ghu^h#kNn3_($3^qx>%%yKUiT(TnG! zF^}L#n14^V9FN=A^XQ$W1uM5qg+7-`WJB?E*CR+B8Svp2@j4NhiL3}P46KAuN2HKM8V8hwhYbU{^S~w}XNsRnFI|o3&RBn22wm+=* zc+NaHmvLeGT*@(X=yB-BAKf=u-TCII)t1l15`cVLs(kprA{(R-e-6#OyiR0yg?-{W zw8;ScixD09EY<=kst^D&xSkihst=;^$i(=g540>R&w*RNt3kpXrRKd0kz`feK!ATo zuyPIGRL*b>aFl?ort{s}5TvhAtRIRm)KAt>C1M80b+Dp1y3gB)UUkw1RtL5JR}d6* z8@t5X#Hv{VJ-oXns0xKV25a*o2QrT~DtQVpP~{JVYK$ zKZY=!5?8-x6yYk{l~3Fc=Y}q(yrh0H;MMmIc0uz|IM?KEI@pA;plcA)S~Q)Qw>hj* z*K{;$Fng(`-$JHS`yoqLqH(z>NuRW+EZoQbK%+~Brv&n>W&iwxuO@ux%X&y{5j2f% zGiBV_7vbE757|7uy7&}e!^reBx#c*r+aQ7G(oK&-%eIMIqt|u5RQ*vzw#L*aOAn~& zbfzoLP}@^T80Tb>=HK6p4sl(hbl!25g?KW~qnpP%1u4SHxflJcD=6Rc(ecTa;{saz zMhtt19=*(9cE(8y8#;t2Gg%Ak=rm6}ZtRWg`O^ds9qfmT$F;7tT?HTNUsj!zTMYQtw zfmxjA0`RA=*^=}nMdFd8JT@K+9?hvhh0l#Wy3^GiihzS1!!}FLt@H_0=5?A@ad)4# z#vg{!q#pfNJ35)~VNYoM7o~rRVEt`vz9cqne}sxSmgNY$yn7;*N=<= znQXHw$N!&C-@8s32)*^3`CHWW0B(`6I#c6Fly^_Um!K zW)~5}1**C(mX4zdOW$9VEPjw2-QW9Sc>dg^41Z)kED>0(y}jNqd!ubnUT*E;lHupK zMKjlux;R0##r(&h73Hu-F5WDw@ZBjQ0W3_43m_h?@;B$UqjzB@zpC#azab8Q%;mtF zi<*lUmyVbz^)D5i?z@-8^c^7cYIz3t0pGw%b%LP?J8OEEEf=n?>}=KHAM2}|)th>* zI-mFP-CgE2&aNkI{yTVp_yl%xc&FA z{OSm>)>95Xod0QFf7|>3kz9XHG!*!L-O@FdaOin8d(#5CbWYNvMF9xMB<)p`XKUI*{DF}%6YLJzlX7Y_ON!bC z`pAo}))inV(0Rkk0Iu`-X@#G^N(rs3Xnu6($m}1?NlrY}+TBKHi>?j?mn<#i%3PN}>98A>B`b6=3JjpsZfFbg*Ht z5qME^?B;%xzlXQUg^E;$YjdLv)Cf2fvC)zpyby&;Eg5Y(c^Q#xy4ZO?Nk{!sp_r1I zUtzkIOeqzUT2%5|Uf#Yfe5up9NK6Hb@mPj0^_%uwKDI>inuc&2>h^jJ-B!R<5Kha? zUJ7)W{t*Z+45J9e0?^X;qtoY2*?xLVtuV1gql%mfS*4gT z0QT>~@4qgVQ40^Q8w3<*gq+Jm`{nBI^Y_#!QR6 zq+asm1LTkC@AtXMv{hZQ%eMTZE2!G%`iG^}>;QkA0c}vD_RowlU98TE?Me=zN$ZFH zGRbRe7c%;RN@G#5o$hi9HqyXPaWRukXN+qxTGl<2{V1_2k z3T9}*)L_x&_pxCT*!vNGwj4?LSUQpqn~68?-10pBrSu)(l{!%xARoQ>$Of}zQ;~7Iv&sw<#VZuVsP*wr1KA522Zxb(fX&Am2rgv|8@1W23r>W^6D%Y80jJ z&8Y$X1mbp*UTVl~=lAS{s>a?^T)~f9q^#+zzg_i9+qs>z9sIi8^Jw@yH=*dSxBIL~ z{YxtsqiF7n0Eg2*7_MibPrb@+7g!#wx1s`TYDvmk>w_v;o+`cP8VXl=v}V>s%~=f7^{l*xu=(L$F5 z)&?xE=7mvv{rG+EK;Go_!?rd%B)s%_Y3hJ2ZH1fAhB8cN zYQzc*@zfu8hU^cF!w(K78_JhXm!OWvd0WAG2OFs;mb}z`?ld6Pb*(o3@nwvWC{YM> z_IBW+psB3sT0}}3T7ftMWC9q6Z|dn-1$2qKf2e}ZoU=`lfw}-mY<=GIla~v6WHCn_CuoE#v2%>|s7tWrQSymK^mCgccrt?s z5`(7P5FHfD-V*TDD9OBU4m(dc;3{NHzTD z@Wl~yv%$g1e--*=U5LPm+>w8Q0RlC?27#OdRap5rSo-u|(gXxR-TDDL`x@0de#0B7 z$r>{tS+ykM{}u+=Bg%*9T%CJRO$Xk>zZ7$fC_hGjGQ?}k5|84qh~t39$`dMUa2Xun zWbl>ZR#mKye_=b=;3D4q%S`33FvtRLdh_FDZ=COL>GV#~aB#wRnBD1-!%n_u`6rI} zf>a3{w0uhRgzgQ@@x08<@*gDO|BfAAkP75-^m%fbYr^T<8qHtFW1nc4m6t|^(6 zynZ#Pjy4H!DAN^*oX2)t)BN$6c2TjYcT0U}o8*O8+F9D8JJKRj1Fp)@{<+E>t?KQ?&&t?)SjouE;A`Rck3Y*LV$OZbJ+(8Wwxp>axsetzsB)fig4ZB%9bn;H0=)xEG+K~ zEH1xvt0v)$0F7_X3Whd#l?)bpT246jeYpJPs@0n9PYShQ$9X^pv@VMm=wxa<@kE6Y zC#l`{Dm6N+<*IoiWdvS%oY~VTdEXres;Hx=_vK@);c^hNmb+s z+1w8-Rj@57seZh?e;Z?A&JRAq_-l}CShqXldY;xq*%Fhj@a)|cQ4wD8g(UNj79ZYw z*NV|bx3EmbW8h+U6n0vbi^gu!qRpQlNND5>q@yZ637qiuQZrnv18`C^dS8$+Kgvwxd)^sWA)H z7!ts*N26)@+9tD6=;;PNT^#KaKk7ErG$jXhG|O6CPS;QgkqOJbe1Vk?S0-1|p8U&{ zug>G=xk<4G;TRTlr5T*_PLEV^6-$|GS^#_!Q_5I4XlOhPvJccyq45rHIR{s^@=m)O zh)cjGY)dLo#+8%Q58BW6$o^0~>T5}+u`yM^s5!sq`IjZv&tWtk(7t7CyypA@B>FN& zU=JeZlC4&rI&c;j;!*6Yw&jJC0wnU`4CU~h=FJolLvZG!Z~mB+M=~=~+mSi>l!~OI z^y_2WdTw06g&GWJ#x>JrI1?F?K*M^g8lW6#3SqD!2Gkl!VD3U z3oL@pX5q+9<$!*jvK}wc=|D1}I)Z95W-WlfR>KKO_dkC^lWnr&IdXuS-W&{z#>7NEkJ5M_~F?bf3)e-wjI(r6xtEL3!Z;hUl*s+uZuW zN3nwU{NL2BEz?eHjA^fE>e|2O74tt58e!Qs;((V2TmWT-YONeG?1Ux6^HGXh5!&2}2LL zLGGdfT*5}0SqOJ<+>i`5txVvT7ymz7e$FsIif(R#HE2N_T(0UO4tZN4$ZWP3b6awedk#0PcRG=89zdBu(s5ho?d`nr>~UueQcSGD^^iW~YZl{h z;+P?QgyKCm4)rODY&zqIc7);!Cp}FN?zn-y2~roeCC7UtAhF5~k{jA19oia%vW?$b zYlA8dVt@n|PuUm;7VB<12}BK94JoS% zU^GFl{to$~M08F9HysE=9MMt}D(Ts3%h1R+P-$yCU=4c5jKfFkHvEPMS;k)AE-)g5 zB(eqlA$@xE{SMIR084ryD*XE$*48LIaNw^iY&X<{A^Zx%_FtMiVB^8K)7IZ_?^vCD z#l$RM5LB=CB(Y}TMj*Q3x+Oe?JymAvH3_8p9aZht>`@TuX0)LWow+x)p7U{s5jQ+& z+>VaRsmW2I7)z9>+{mNY@@NpEpsIVV_SiTu;x>&CrLDtAH&2Z1hM`{Z{5>oorwH90 zN{lm++>B2Z#K3!8~MS-Ll0X;(|LlkB)%rM!7Z}`t`GyWmrC;Fy;ir`AgV`q z>D;Q=l_|FE56EdK4%$q-x|XM)>s!*jqqbi0yOmf8%I#CzouAPd@H3EKd7PYxX0L9s zdB2wt-JffieKa!Pv{M?t$6wvEE@MJJ_FviFy^pTK)BFks%yjc@!`jEI*LA(Hcu7-8 zURQd+tOP73*rqxBB~HnJm*_d}{ac(O^D78%Am~THOzaE2HYf=^#Db zp)(_MKDc7$_g8|9q=hpep}_cK^`$ieWK!JkLYLVyQt}LVIlnO@pYlrf5l;B%8VikM z>_s|6G5hdJtqW8$nI?PI>meN?2V&ZxFDAN^AYJs$OhBEGAt-xv3W@8NR&wJnM-o=< zSt_A>);u>0E!{PJdji6cDezBTx4T%I&r)R0-7C*x<=&ueE#SkpNlOZQ;?+)CwP5k4 z?F|&z#Em7ZndZ*h1n!$u= z6l7oP*s)D(;=V{h1cZ~i7TVNeHk5$;Pc~5qy(RRm<0pb({o~%$Ys2{Ow~fQM-=Eih z_`?E4vjmKl1@BNpoQEnFrsDD7v?wH_zo5b8NncCni*SnN_Yb>VCu#`^;`5Fo1yyP% zUf&``P~A-D9JCx?Q}fQzeGSf@A@O4NxhS9ncTF|mUGe&Sm_v|h8|$GHt~Geh6@sRi ziAgZNLe0-$_1tHC2qYNI`C#G)<@p7`y&0|sc~i;fu$ukQ{mCHFX;gf-Roo7YBEd=PPJHDQQoF&O0R;4wz+^hA_plN)$!!WJeA3T>+vth_-f=`O*?z);ki(KY~MO^yKvIM+rE*vH%}am zh|tJA*o>F!Ia*q|X1MZLALZ%~M%D&MXxIod2iOzvdQgHP8oRnZH@`m#bzJv(DPZcy zn$rzp!BP}r+~q6`o*7kh<6gB_67P~-^03V`zOJDxS@q<8o#wK zT7hq{rIBQoZX7@rU1B5d>}d}l4E76d0B2Zh;8H#4$a~q345;?4YKkw_FKTivad$Ql zg$Iu3_xPZsgEZjJVU6_6=+5t(T3x@H{G^nNqTE`Jr{n0~rBB;TN4G_U;M_z8Oxd%2 zYmq-|4b1!yPu?5Zxv8=nvo?(Gco%BQAo2%pFpN1@zu$7~VX(c`^3P8US~5vF=-tvZ zXA3s0#c(itNN#opiK$txE1hgPCOq&vIj`vB%@$6B`|z1FqtI9w*fT*Bdks2We>t&2 zRL=jd@jUOeSI2xDL@861;f@t@2fPx0V0yI>- zGPKc4iCMsU&0jVP;4fUg9=It^ZF;45Q1O`9ujY4@8i+l<3!N=Dr5IV(0=+xx*8^=u zzVpjVVra^T1h?L0ZCtsB-YvuY(jfoC{;c|-9k&PXJzU@Gj&^b+01K5E|KYQRhDV_;-DLKD+gX5;RZbW z4z6$<2Hm=;{$5e#8#BrZ&}yl7^e~^-?=U?r#ux7QshVosI5NzFBd8O16NO7uzh)1# z{1OAH50Ch3@{|VWEY8b~Y=|Wn(%CA;grA0^V$>$UVgW2Nu#MskGV-^NDu!%@?{jRa7DOl^=2}PJcU}Pi&ff+JYxFd z`xF2BT?E=#(d|?FO4~t&cW8F9Lg+vR+Fw(7=9h<)XYpg=kUFm*-}$CS)Q|W}p21}J z%v1Nh2%=hQ??FE;sr~K!rCe32j@gOv=+0D*ut6Ow+y$7WI0TOx!{IIGwjo#4Vn-DT zKYb=qQtR2_Wvur2P-i~c-u=z=>lV}@`=e>b^|UC|-hH_;TSrUdcew7ia|D7C#t?c* z#Uu`B)t0R41;@ig$9u6qwfdtmT!mp3>33~_u=E3iXGqo#o}y?V=2`}eg=-F(y&l86 zK~qd_h2k*@W?b3IyT0O;+($;!ct(TiUypvKzAy!RDInQf?T=qYyrk&DOxe2*fj(7a zklo+B*drJbVT#hh9+nyLi4Mq15b!;!4%%+TDaZ{N81hOiaIM*_uxnP#hm-!JCsBBE zwpeakmn>2IgYKz9RWc`mdiQq#cdd?$j-gq*r{fRh2K(bMGQ}V`dn-#xXqv5b&R;)1 zIRg~)=@3+r|0!n9>s^Dn@!-JM`otFc)CuX_jH-gncHLRxSnXDBJ98KmB5RY#C=RY4 z1{^#JI#&*x*h>@hVV|`aR}wJrLczL*sD@1vuZpB_coVR$Sur}vTy8*ZxICx)iv{z$ zn@x1&V5nvArnwC9k)7dF3*GNQ0M^Lv9B>@KM5OQERsX$cl%cqITDU%^jRr!YHKWNM zXaseVJ;H~j9N~{5YvFWqnX;eI9diGU3+30qi$f^mP+}B?u_*J;TERd?CLh%8kMCC! z??0QR<41)3Md1=ZHju~1aOaEp_bfOPpZPwfEFoXB>C>}@;(Hfzcgl^(`~DpN942Q> zB*}9?pQt{Z9rdN&0AXU^-6?nKtP+H`IkhxqifS;O!GZWKsl@Rak~dx1lkcLm#}FO? z^q9Qy)|6~J%3m7y%K+2QxKUq~z}<~&c5-KitQi~Oq-q2*kM8$Lx2FeXn7Hk6bu+s> zDOlG6Mt+8Os!~IRgA;t_uT~0t`!e=s*Oz6ZbWJ8PXFnRu_w}A0j49dO8EralLxM*& z-cNspW8kst`djHt$Bh0&G!W-6LSsI1`lYWzZzICTfl-9S#|0W%+*{o>87DuSflGIc zXWl~*k6PX7Bp#uoqq{p@sx4ik4#U``OnLdYS?50)?Eln${x>^zu09|!34rr`*NEoe QElCh^Qc99F;>IEW1564fa{vGU literal 0 HcmV?d00001 diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 250f1aa6a38..d89cc3aab87 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -2,89 +2,85 @@ Specific config details ======================= +.. _custom_prompts: + +Custom Prompts +============== + +.. versionchanged:: 5.0 + +From IPython 5, prompts are produced as a list of Pygments tokens, which are +tuples of (token_type, text). You can customise prompts by writing a method +which generates a list of tokens. + +There are four kinds of prompt: + +* The **in** prompt is shown before the first line of input + (default like ``In [1]:``). +* The **continuation** prompt is shown before further lines of input + (default like ``...:``). +* The **rewrite** prompt is shown to highlight how special syntax has been + interpreted (default like ``----->``). +* The **out** prompt is shown before the result from evaluating the input + (default like ``Out[1]:``). + +Custom prompts are supplied together as a class. If you want to customise only +some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`, +which defines the defaults. The required interface is like this: + +.. class:: MyPrompts(shell) + + Prompt style definition. *shell* is a reference to the + :class:`~.TerminalInteractiveShell` instance. + + .. method:: in_prompt_tokens(cli=None) + continuation_prompt_tokens(self, cli=None, width=None) + rewrite_prompt_tokens() + out_prompt_tokens() + + Return the respective prompts as lists of ``(token_type, text)`` tuples. + + For continuation prompts, *width* is an integer representing the width of + the prompt area in terminal columns. + + *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance. + This is mainly for compatibility with the API prompt_toolkit expects. + +Inside IPython or in a startup script, you can use a custom prompts class +by setting ``get_ipython().prompts`` to an *instance* of the class. +In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to +either the class object, or a string of its full importable name. + .. _termcolour: Terminal Colors =============== -The default IPython configuration has most bells and whistles turned on -(they're pretty safe). But there's one that may cause problems on some -systems: the use of color on screen for displaying information. This is -very useful, since IPython can show prompts and exception tracebacks -with various colors, display syntax-highlighted source code, and in -general make it easier to visually parse information. - -The following terminals seem to handle the color sequences fine: - - * Linux main text console, KDE Konsole, Gnome Terminal, E-term, - rxvt, xterm. - * CDE terminal (tested under Solaris). This one boldfaces light colors. - * (X)Emacs buffers. See the :ref:`emacs` section for more details on - using IPython with (X)Emacs. - * A Windows (XP/2k) CygWin shell. Although some users have reported - problems; it is not clear whether there is an issue for everyone - or only under specific configurations. If you have full color - support under cygwin, please post to the IPython mailing list so - this issue can be resolved for all users. - -These have shown problems: - - * Windows command prompt in WinXP/2k logged into a Linux machine via - telnet or ssh. - * Windows native command prompt in WinXP/2k, without Gary Bishop's - extensions. Once Gary's readline library is installed, the normal - WinXP/2k command prompt works perfectly. - -IPython uses colors for various groups of things that may be -controlled by different configuration options: prompts, tracebacks, "as -you type" in the terminal, and the object introspection system which -passes large sets of data through a pager. There are various way to -change the colors. - -We can distinguish the coloration into 2 main categories: - -- The one that affects only the terminal client. -- The ones that also affect clients connected through the Jupyter - protocol. - -Traceback, debugger, and pager are highlighted kernel-side so they fall -into the second category. For historical reasons they are often -governed by a ``colors`` attribute or configuration option that can -take one of 3 case insensitive values: ``NoColors``, ``Linux`` and -``LightBG``. - -Colors that affect only the terminal client are governed mainly by -``TerminalInteractiveShell.highlight_style`` taking the name of a -``Pygments`` style. - -As of IPython 5.0 the color configuration works as follows: - - - by default, ``TerminalInteractiveShell.highlight_style`` is set to - ``legacy`` which **trys to** emulate the colors of IPython pre 5.0 - and respect the ``.color`` configuration option. - The emulation is an approximation of the current version of Pygments - (2.1) and only supports extended ANSI escape sequence, hence the - theme cannot adapt to your terminal custom mapping if you have - one. - - The last extra difference being that the "as you type" coloration - is present using the theme "default" if `color` is `LightBG`, and - using the theme "monokai" if `Linux`. - - - if ``TerminalInteractiveShell.highlight_style`` is set to any other - themes, this theme is used for "as you type" highlighting. The - prompt highlighting is then governed by - ``--TerminalInteractiveShell.highlighting_style_overrides`` - -As a summary, by default IPython 5.0 should mostly behave unchanged -from IPython 4.x and before. Use -``TerminalInteractiveShell.highlight_style`` and -``--TerminalInteractiveShell.highlighting_style_overrides`` for extra -flexibility. - -With default configuration `--colors=[nocolors|linux|ightbg]` as well -as the `%colors` magic should behave identically as before. +.. versionchanged:: 5.0 + +There are two main configuration options controlling colours. + +``InteractiveShell.colors`` sets the colour of tracebacks and object info (the +output from e.g. ``zip?``). It may also affect other things if the option below +is set to ``'legacy'``. It has four case-insensitive values: +``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which +should be legible on either dark or light terminal backgrounds. *linux* is +optimised for dark backgrounds and *lightbg* for light ones. + +``TerminalInteractiveShell.highlight_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``. +You can see the Pygments styles available on your system by running:: + + import pygments + list(pygments.styles.get_all_styles()) + +Additionally, ``TerminalInteractiveShell.highlight_style_overrides`` can override +specific styles in the highlighting. It should be a dictionary mapping Pygments +token types to strings defining the style. See `Pygments' documentation +`__ for the language used +to define styles. Colors in the pager ------------------- @@ -98,9 +94,6 @@ To configure your default pager to allow these: properly interpret control sequences, which is how color information is given to your terminal. - - - .. _editors: Editor configuration diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index e425aad0217..fbf55e782b4 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -5,10 +5,27 @@ IPython 5.0 =========== -Released June, 2016 +Released July, 2016 -IPython 5.0 now uses ``prompt-toolkit`` for the command line interface, thus -allowing real multi-line editing and syntactic coloration as you type. +New terminal interface +---------------------- + +IPython 5 features a major upgrade to the terminal interface, bringing live +syntax highlighting as you type, proper multiline editing and multiline paste, +and tab completions that don't clutter up your history. + +.. image:: ../_images/ptshell_features.png + :alt: New terminal interface features + :align: center + :target: ../_images/ptshell_features.png + +These features are provided by the Python library `prompt_toolkit +`__, which replaces +``readline`` throughout our terminal interface. + +Relying on this pure-Python, cross platform module also makes it simpler to +install IPython. We have removed dependencies on ``pyreadline`` for Windows and +``gnureadline`` for Mac. When using IPython as a subprocess, like for emacs inferior-shell, IPython can @@ -19,57 +36,44 @@ disabled. Backwards incompatible changes ------------------------------ - -The `install_ext magic` function which was deprecated since 4.0 has now been deleted. -You can still distribute and install extensions as packages on PyPI. - -Update IPython event triggering to ensure callback registration and -unregistration will only affect the set of callbacks the *next* time that event is -triggered. See :ghissue:`9447` and :ghpull:`9453`. - -This is a change to the existing semantics, wherein one callback registering a -second callback when triggered for an event would previously be invoked for -that same event. - -Integration with pydb has been removed since pydb development has been stopped -since 2012, and pydb is not installable from PyPI. - - - -Replacement of readline in TerminalInteractiveShell and PDB -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -IPython 5.0 now uses ``prompt_toolkit``. The -``IPython.terminal.interactiveshell.TerminalInteractiveShell`` now uses -``prompt_toolkit``. It is an almost complete rewrite, so many settings have -thus changed or disappeared. The class keep the same name to avoid breaking -user configuration for the options with names that are unchanged. - -The usage of ``prompt_toolkit`` is accompanied by a complete removal of all -code, using ``readline``. A particular effect of not using `readline` anymore -is that `.inputrc` settings are note effective anymore. Options having similar -effects have likely been replaced by a configuration option on IPython itself -(e.g: vi input mode). - -The `PromptManager` class have been removed, and the prompt machinery simplified. -See `TerminalInteractiveShell.prompts` configurable for how to setup your prompts. - -.. note:: - - During development and beta cycle, ``TerminalInteractiveShell`` was - temporarly moved to ``IPython.terminal.ptshell``. - - -Most of the above remarks also affect `IPython.core.debugger.Pdb`, the `%debug` -and `%pdb` magic which do not use readline anymore either. - -The color handling has been slightly changed and is now exposed, -in particular the colors of prompts and as you type -highlighting can be affected by : -``TerminalInteractiveShell.highlight_style``. With default -configuration the ``--colors`` flag and ``%colors`` magic behavior -should be mostly unchanged. See the `colors `_ section of -our documentation +- The ``%install_ext`` magic function, deprecated since 4.0, has now been deleted. + You can distribute and install extensions as packages on PyPI. +- Callbacks registered while an event is being handled will now only be called + for subsequent events; previously they could be called for the current event. + Similarly, callbacks removed while handling an event *will* always get that + event. See :ghissue:`9447` and :ghpull:`9453`. +- Integration with pydb has been removed since pydb development has been stopped + since 2012, and pydb is not installable from PyPI. +- The ``autoedit_syntax`` option has apparently been broken for many years. + It has been removed. + +New terminal interface +~~~~~~~~~~~~~~~~~~~~~~ + +The overhaul of the terminal interface will probably cause a range of minor issues; +this is inevitable for such a significant change. These are some that we're aware of: + +IPython no longer uses readline configuration (``~/.inputrc``). We hope that +the functionality you want (e.g. vi input mode) will be available by configuring +IPython directly (see :doc:`/config/options/terminal`). +If something's missing, please file an issue. + +The ``PromptManager`` class has been removed, and the prompt machinery simplified. +See :ref:`custom_prompts` to customise prompts with the new machinery. + +:mod:`IPython.core.debugger` now provides a plainer interface. +:mod:`IPython.terminal.debugger` contains the terminal debugger using +prompt_toolkit. + +There are new options to configure the colours used in syntax highlighting. +We have tried to integrate them with our classic ``--colors`` option and +``%colors`` magic, but there's a mismatch in possibilities, so some configurations +may produce unexpected results. See :ref:`termcolour` for more information. + +The new interface is not compatible with Emacs 'inferior-shell' feature. To +continue using this, add the ``--simple-prompt`` flag to the command Emacs +runs. This flag disables most IPython features, relying on Emacs to provide +things like tab completion. Provisional Changes ------------------- @@ -116,12 +120,6 @@ widgets... As stated above this is nightly experimental feature with a lot of it. -Removed Feature ---------------- - -- ``TerminalInteractiveShell.autoedit_syntax`` Has been broken for many years now - apparently. It has been removed. - Deprecated Features ------------------- From bd6336645dcc87f064e42771cb78f0fc14c4e710 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Jun 2016 14:10:07 +0100 Subject: [PATCH 0494/4859] Remove duplicated info --- docs/source/whatsnew/version5.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index fbf55e782b4..aaa042e4980 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -27,12 +27,6 @@ Relying on this pure-Python, cross platform module also makes it simpler to install IPython. We have removed dependencies on ``pyreadline`` for Windows and ``gnureadline`` for Mac. - -When using IPython as a subprocess, like for emacs inferior-shell, IPython can -be started with a ``--simple-prompt`` flag, which will bypass the prompt_toolkit -input layer. In this mode, prompt color and many other features are -disabled. - Backwards incompatible changes ------------------------------ From b7f74ca86c4d699c87e14310441fbfaf09e9bf2f Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Jun 2016 15:10:24 +0100 Subject: [PATCH 0495/4859] Update docs and add registration interface for inputhooks --- IPython/terminal/pt_inputhooks/__init__.py | 11 +++- docs/source/config/eventloops.rst | 74 ++++++++++------------ 2 files changed, 43 insertions(+), 42 deletions(-) diff --git a/IPython/terminal/pt_inputhooks/__init__.py b/IPython/terminal/pt_inputhooks/__init__.py index e98ea2ec1d2..0f37b135a52 100644 --- a/IPython/terminal/pt_inputhooks/__init__.py +++ b/IPython/terminal/pt_inputhooks/__init__.py @@ -15,6 +15,12 @@ 'osx', ] +registered = {} + +def register(name, inputhook): + """Register the function *inputhook* as an event loop integration.""" + registered[name] = inputhook + class UnknownBackend(KeyError): def __init__(self, name): self.name = name @@ -22,9 +28,12 @@ def __init__(self, name): def __str__(self): return ("No event loop integration for {!r}. " "Supported event loops are: {}").format(self.name, - ', '.join(backends)) + ', '.join(backends + sorted(registered))) def get_inputhook_func(gui): + if gui in registered: + return registered[gui] + if gui not in backends: raise UnknownBackend(gui) diff --git a/docs/source/config/eventloops.rst b/docs/source/config/eventloops.rst index 79eb86ff0d4..da13d0a58ec 100644 --- a/docs/source/config/eventloops.rst +++ b/docs/source/config/eventloops.rst @@ -13,47 +13,39 @@ so different steps are needed to integrate with each. Event loops in the terminal --------------------------- -In the terminal, IPython uses a blocking Python function to wait for user input. -However, the Python C API provides a hook, :c:func:`PyOS_InputHook`, which is -called frequently while waiting for input. This can be set to a function which -briefly runs the event loop and then returns. - -IPython provides Python level wrappers for setting and resetting this hook. To -use them, subclass :class:`IPython.lib.inputhook.InputHookBase`, and define -an ``enable(app=None)`` method, which initialises the event loop and calls -``self.manager.set_inputhook(f)`` with a function which will briefly run the -event loop before exiting. Decorate the class with a call to -:func:`IPython.lib.inputhook.register`:: - - from IPython.lib.inputhook import register, InputHookBase - - @register('clutter') - class ClutterInputHook(InputHookBase): - def enable(self, app=None): - self.manager.set_inputhook(inputhook_clutter) - -You can also optionally define a ``disable()`` method, taking no arguments, if -there are extra steps needed to clean up. IPython will take care of resetting -the hook, whether or not you provide a disable method. - -The simplest way to define the hook function is just to run one iteration of the -event loop, or to run until no events are pending. Most event loops provide some -mechanism to do one of these things. However, the GUI may lag slightly, -because the hook is only called every 0.1 seconds. Alternatively, the hook can -keep running the event loop until there is input ready on stdin. IPython -provides a function to facilitate this: - -.. currentmodule:: IPython.lib.inputhook - -.. function:: stdin_ready() - - Returns True if there is something ready to read on stdin. - - If this is the case, the hook function should return immediately. - - This is implemented for Windows and POSIX systems - on other platforms, it - always returns True, so that the hook always gives Python a chance to check - for input. +.. versionchanged:: 5.0 + + There is a new API for event loop integration using prompt_toolkit. + +In the terminal, IPython uses prompt_toolkit to prompt the user for input. +prompt_toolkit provides hooks to integrate with an external event loop. + +To integrate an event loop, define a function which runs the GUI event loop +until there is input waiting for prompt_toolkit to process. There are two ways +to detect this condition:: + + # Polling for input. + def inputhook(context): + while not context.input_is_ready(): + # Replace this with the appropriate call for the event loop: + iterate_loop_once() + + # Using a file descriptor to notify the event loop to stop. + def inputhook2(context): + fd = context.fileno() + # Replace the functions below with those for the event loop. + add_file_reader(fd, callback=stop_the_loop) + run_the_loop() + +Once you have defined this function, register it with IPython: + +.. currentmodule:: IPython.terminal.pt_inputhooks + +.. function:: register(name, inputhook) + + Register the function *inputhook* as the event loop integration for the + GUI *name*. If ``name='foo'``, then the user can enable this integration + by running ``%gui foo``. Event loops in the kernel From 3d83950a1ea602e3fbdd9292f0281f6bc28ba186 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Jun 2016 16:16:27 +0100 Subject: [PATCH 0496/4859] Revert part of gh-9567 --- docs/autogen_config.py | 5 +++-- docs/source/config/options/index.rst | 5 ++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/autogen_config.py b/docs/autogen_config.py index f2f6f66667d..1579d5f0ae5 100755 --- a/docs/autogen_config.py +++ b/docs/autogen_config.py @@ -11,7 +11,8 @@ def write_doc(name, title, app, preamble=None): - with open(generated, 'a') as f: + filename = join(options, name+'.rst') + with open(filename, 'w') as f: f.write(title + '\n') f.write(('=' * len(title)) + '\n') f.write('\n') @@ -21,7 +22,7 @@ def write_doc(name, title, app, preamble=None): if __name__ == '__main__': - # create empty file + # Touch this file for the make target with open(generated, 'w'): pass diff --git a/docs/source/config/options/index.rst b/docs/source/config/options/index.rst index 70907995c94..a0f38e2a231 100644 --- a/docs/source/config/options/index.rst +++ b/docs/source/config/options/index.rst @@ -6,4 +6,7 @@ Any of the options listed here can be set in config files, at the command line, or from inside IPython. See :ref:`setting_config` for details. -.. include:: config-generated.txt +.. toctree:: + + terminal + kernel From f4d1b8d48dc04ccf621ae46e874b7fa9c7b36310 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 29 Jun 2016 17:17:10 +0100 Subject: [PATCH 0497/4859] Reword intro to breaking changes from PT overhaul --- docs/source/whatsnew/version5.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index aaa042e4980..7df222448ce 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -44,8 +44,11 @@ Backwards incompatible changes New terminal interface ~~~~~~~~~~~~~~~~~~~~~~ -The overhaul of the terminal interface will probably cause a range of minor issues; -this is inevitable for such a significant change. These are some that we're aware of: +The overhaul of the terminal interface will probably cause a range of minor +issues for existing users. +This is inevitable for such a significant change, and we've done our best to +minimise these issues. +Some changes that we're aware of, with suggestions on how to handle them: IPython no longer uses readline configuration (``~/.inputrc``). We hope that the functionality you want (e.g. vi input mode) will be available by configuring From 12e05563fce19803bd8b146a57505a7120150bb4 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 30 Jun 2016 10:55:48 +0100 Subject: [PATCH 0498/4859] Handle bad __all__ for module completions Closes gh-9678 --- IPython/core/completerlib.py | 6 ++---- IPython/core/tests/bad_all.py | 14 ++++++++++++++ IPython/core/tests/test_completerlib.py | 16 ++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 IPython/core/tests/bad_all.py diff --git a/IPython/core/completerlib.py b/IPython/core/completerlib.py index 57dd2b50997..3fbc7e6cc56 100644 --- a/IPython/core/completerlib.py +++ b/IPython/core/completerlib.py @@ -153,7 +153,6 @@ def is_importable(module, attr, only_modules): else: return not(attr[:2] == '__' and attr[-2:] == '__') - def try_import(mod, only_modules=False): try: m = __import__(mod) @@ -173,9 +172,8 @@ def try_import(mod, only_modules=False): completions.extend(getattr(m, '__all__', [])) if m_is_init: completions.extend(module_list(os.path.dirname(m.__file__))) - completions = set(completions) - if '__init__' in completions: - completions.remove('__init__') + completions = {c for c in completions if isinstance(c, string_types)} + completions.discard('__init__') return list(completions) diff --git a/IPython/core/tests/bad_all.py b/IPython/core/tests/bad_all.py new file mode 100644 index 00000000000..a7716ab6f32 --- /dev/null +++ b/IPython/core/tests/bad_all.py @@ -0,0 +1,14 @@ +"""Module with bad __all__ + +To test https://github.com/ipython/ipython/issues/9678 +""" + +def evil(): + pass + +def puppies(): + pass + +__all__ = [evil, # Bad + 'puppies', # Good + ] diff --git a/IPython/core/tests/test_completerlib.py b/IPython/core/tests/test_completerlib.py index 9cc46097eaf..71a6cd246e0 100644 --- a/IPython/core/tests/test_completerlib.py +++ b/IPython/core/tests/test_completerlib.py @@ -145,3 +145,19 @@ def test_import_invalid_module(): nt.assert_equal(intersection, set()) assert valid_module_names.issubset(s), valid_module_names.intersection(s) + + +def test_bad_module_all(): + """Test module with invalid __all__ + + https://github.com/ipython/ipython/issues/9678 + """ + testsdir = os.path.dirname(__file__) + sys.path.insert(0, testsdir) + try: + results = module_completion('from bad_all import ') + nt.assert_in('puppies', results) + for r in results: + nt.assert_is_instance(r, py3compat.string_types) + finally: + sys.path.remove(testsdir) From c70a965bb3690cff28c71098fd8221928ee54886 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 10:13:33 -0700 Subject: [PATCH 0499/4859] Add extra warnings in docs, and improve Makefile. Have the shortcuts actually depends on what generate them. --- docs/Makefile | 2 +- docs/source/config/shortcuts/index.rst | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index 20ddd10bd14..4f2a73b78bf 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -87,7 +87,7 @@ source/api/generated/gen.txt: $(PYTHON) autogen_api.py @echo "Build API docs finished." -autogen_shortcuts: +autogen_shortcuts: autogen_shortcuts.py ../IPython/terminal/interactiveshell.py $(PYTHON) autogen_shortcuts.py @echo "Created docs for shortcuts" diff --git a/docs/source/config/shortcuts/index.rst b/docs/source/config/shortcuts/index.rst index 2d446341fbf..9905f078c8e 100755 --- a/docs/source/config/shortcuts/index.rst +++ b/docs/source/config/shortcuts/index.rst @@ -4,6 +4,12 @@ IPython shortcuts Available shortcut in IPython terminal. +.. warnings:: + + This list is automatically generated, and may not hold all the available + shortcut. In particular, it may depends on the version of ``prompt_toolkit`` + installed during the generation of this page. + Single Filtered shortcuts ========================= From 6a6ea02b22d270a5e45904f9fe0459dd9d9a2b31 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 10:31:20 -0700 Subject: [PATCH 0500/4859] Clenup of documentation buildr --- IPython/utils/warn.py | 21 +++++++++++++++++---- docs/Makefile | 2 +- docs/source/config/shortcuts/index.rst | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 1b67423de45..127f692f78e 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -10,11 +10,15 @@ import sys import warnings +from IPython.utils.decorators import undoc warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning) +@undoc def warn(msg,level=2,exit_val=1): - """Standard warning printer. Gives formatting consistency. + """Deprecated + + Standard warning printer. Gives formatting consistency. Output is sent to io.stderr (sys.stderr by default). @@ -39,19 +43,28 @@ def warn(msg,level=2,exit_val=1): sys.exit(exit_val) +@undoc def info(msg): - """Equivalent to warn(msg,level=1).""" + """Deprecated + + Equivalent to warn(msg,level=1).""" warn(msg,level=1) +@undoc def error(msg): - """Equivalent to warn(msg,level=3).""" + """Deprecated + + Equivalent to warn(msg,level=3).""" warn(msg,level=3) +@undoc def fatal(msg,exit_val=1): - """Equivalent to warn(msg,exit_val=exit_val,level=4).""" + """Deprecated + + Equivalent to warn(msg,exit_val=exit_val,level=4).""" warn(msg,exit_val=exit_val,level=4) diff --git a/docs/Makefile b/docs/Makefile index 4f2a73b78bf..46add14d882 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -87,7 +87,7 @@ source/api/generated/gen.txt: $(PYTHON) autogen_api.py @echo "Build API docs finished." -autogen_shortcuts: autogen_shortcuts.py ../IPython/terminal/interactiveshell.py +autogen_shortcuts: autogen_shortcuts.py ../IPython/terminal/interactiveshell.py source/config/shortcuts/index.rst $(PYTHON) autogen_shortcuts.py @echo "Created docs for shortcuts" diff --git a/docs/source/config/shortcuts/index.rst b/docs/source/config/shortcuts/index.rst index 9905f078c8e..29088f6d19e 100755 --- a/docs/source/config/shortcuts/index.rst +++ b/docs/source/config/shortcuts/index.rst @@ -4,7 +4,7 @@ IPython shortcuts Available shortcut in IPython terminal. -.. warnings:: +.. warning:: This list is automatically generated, and may not hold all the available shortcut. In particular, it may depends on the version of ``prompt_toolkit`` From 53ba3de01cf119ee59c8613b05b0c37faa318520 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 11:47:03 -0700 Subject: [PATCH 0501/4859] Improve grouping of filter --- docs/autogen_shortcuts.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/autogen_shortcuts.py b/docs/autogen_shortcuts.py index 96e9815f531..65108ff891d 100755 --- a/docs/autogen_shortcuts.py +++ b/docs/autogen_shortcuts.py @@ -5,6 +5,10 @@ def name(c): s = c.__class__.__name__ + if s == '_Invert': + return '(Not: %s)' % name(c.filter) + if s in log_filters.keys(): + return '(%s: %s)' % (log_filters[s], ', '.join(name(x) for x in c.filters)) return log_filters[s] if s in log_filters.keys() else s @@ -32,15 +36,11 @@ def multi_filter_str(flt): """Yield readable conditional filter """ assert hasattr(flt, 'filters'), 'Conditional filter required' - yield name(flt) - for subfilter in flt.filters: - yield name(subfilter) - if hasattr(subfilter, 'filter'): - yield name(subfilter.filter) -log_filters = dict(_AndList='(And)', _OrList='(Or)', _Invert='(Inv)') +log_filters = dict(_AndList='And', _OrList='Or') +log_invert = {'_Invert'} kbm = KeyBindingManager.for_prompt() ipy_bindings = kbm.registry.key_bindings From 3bd0bd55cc094a831ee6b2a1cd6e35f6847fd600 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 11:57:19 -0700 Subject: [PATCH 0502/4859] Sort by filter, before sorting by shortcut. Tend to group Vi/Emacs things separately. --- docs/autogen_shortcuts.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/autogen_shortcuts.py b/docs/autogen_shortcuts.py index 65108ff891d..b65ad99df41 100755 --- a/docs/autogen_shortcuts.py +++ b/docs/autogen_shortcuts.py @@ -71,13 +71,15 @@ def multi_filter_str(flt): if __name__ == '__main__': + sort_key = lambda k:(str(k[0][1]),str(k[0][0])) + here = abspath(dirname(__file__)) dest = join(here, 'source', 'config', 'shortcuts') with open(join(dest, 'single_filtered.csv'), 'w') as csv: - for k, v in sorted(single_filter.items()): + for k, v in sorted(single_filter.items(), key=sort_key): csv.write(':kbd:`{}`\t{}\t{}\n'.format(k[0], k[1], v)) with open(join(dest, 'multi_filtered.csv'), 'w') as csv: - for k, v in sorted(multi_filter.items()): + for k, v in sorted(multi_filter.items(), key=sort_key): csv.write(':kbd:`{}`\t{}\t{}\n'.format(k[0], k[1], v)) From 2ce4c4443132357d7fc68cb5947e4e86b3c95033 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 14:00:12 -0700 Subject: [PATCH 0503/4859] Cleanup IPython bash completion from Jupyter commands. --- examples/IPython Kernel/ipython-completion.bash | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/IPython Kernel/ipython-completion.bash b/examples/IPython Kernel/ipython-completion.bash index c70d96d5cfb..61b2ce40138 100644 --- a/examples/IPython Kernel/ipython-completion.bash +++ b/examples/IPython Kernel/ipython-completion.bash @@ -24,7 +24,7 @@ _ipython() { local cur=${COMP_WORDS[COMP_CWORD]} local prev=${COMP_WORDS[COMP_CWORD - 1]} - local subcommands="notebook qtconsole console kernel profile locate history nbconvert kernelspec install-nbextension trust " + local subcommands="kernel profile locate history kernelspec" local opts="help" if [ -z "$__ipython_complete_baseopts" ]; then _ipython_get_flags baseopts @@ -46,11 +46,11 @@ _ipython() if [[ ${cur} == -* ]]; then case $mode in - "notebook" | "qtconsole" | "console" | "kernel" | "nbconvert") + "kernel") _ipython_get_flags $mode opts=$"${opts} ${baseopts}" ;; - "locate" | "profile" | "install-nbextension" | "trust") + "locate" | "profile") _ipython_get_flags $mode ;; "history" | "kernelspec") From a18858802b09d1cd2b24d3b1acb7dc5e078a35b9 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 14:55:15 -0700 Subject: [PATCH 0504/4859] Remove readline related code. Pass 1 --- IPython/core/completer.py | 108 ++----------------------------- IPython/core/interactiveshell.py | 35 +--------- IPython/core/usage.py | 10 +-- setup.py | 16 +---- 4 files changed, 10 insertions(+), 159 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 16c2942f80c..ba8cdcddb16 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1,50 +1,13 @@ # encoding: utf-8 """Word completion for IPython. -This module is a fork of the rlcompleter module in the Python standard +This module stared as fork of the rlcompleter module in the Python standard library. The original enhancements made to rlcompleter have been sent -upstream and were accepted as of Python 2.3, but we need a lot more -functionality specific to IPython, so this module will continue to live as an -IPython-specific utility. +upstream and were accepted as of Python 2.3, -Original rlcompleter documentation: -This requires the latest extension to the readline module (the -completes keywords, built-ins and globals in __main__; when completing -NAME.NAME..., it evaluates (!) the expression up to the last dot and -completes its attributes. - -It's very cool to do "import string" type "string.", hit the -completion key (twice), and see the list of names defined by the -string module! - -Tip: to use the tab key as the completion key, call - - readline.parse_and_bind("tab: complete") - -Notes: - -- Exceptions raised by the completer function are *ignored* (and - generally cause the completion to fail). This is a feature -- since - readline sets the tty device in raw (or cbreak) mode, printing a - traceback wouldn't work well without some complicated hoopla to save, - reset and restore the tty state. - -- The evaluation of the NAME.NAME... form may cause arbitrary - application defined code to be executed if an object with a - ``__getattr__`` hook is found. Since it is the responsibility of the - application (or the user) to enable this feature, I consider this an - acceptable risk. More complicated expressions (e.g. function calls or - indexing operations) are *not* evaluated. - -- GNU readline is also used by the built-in functions input() and - raw_input(), and thus these also benefit/suffer from the completer - features. Clearly an interactive application can benefit by - specifying its own completer function and using raw_input() for all - its input. - -- When the original stdin is not a tty device, GNU readline is never - used, and this module (and the readline module) are silently inactive. +This is now mostly Completer implementation made to function with +prompt_toolkit, but that should still work with readline. """ # Copyright (c) IPython Development Team. @@ -1211,66 +1174,3 @@ def complete(self, text=None, line_buffer=None, cursor_pos=None): self.matches = sorted(set(self.matches), key=completions_sorting_key) return text, self.matches - - def rlcomplete(self, text, state): - """Return the state-th possible completion for 'text'. - - This is called successively with state == 0, 1, 2, ... until it - returns None. The completion should begin with 'text'. - - Parameters - ---------- - text : string - Text to perform the completion on. - - state : int - Counter used by readline. - """ - if state==0: - - self.line_buffer = line_buffer = self.readline.get_line_buffer() - cursor_pos = self.readline.get_endidx() - - #io.rprint("\nRLCOMPLETE: %r %r %r" % - # (text, line_buffer, cursor_pos) ) # dbg - - # if there is only a tab on a line with only whitespace, instead of - # the mostly useless 'do you want to see all million completions' - # message, just do the right thing and give the user his tab! - # Incidentally, this enables pasting of tabbed text from an editor - # (as long as autoindent is off). - - # It should be noted that at least pyreadline still shows file - # completions - is there a way around it? - - # don't apply this on 'dumb' terminals, such as emacs buffers, so - # we don't interfere with their own tab-completion mechanism. - if not (self.dumb_terminal or line_buffer.strip()): - self.readline.insert_text('\t') - sys.stdout.flush() - return None - - # Note: debugging exceptions that may occur in completion is very - # tricky, because readline unconditionally silences them. So if - # during development you suspect a bug in the completion code, turn - # this flag on temporarily by uncommenting the second form (don't - # flip the value in the first line, as the '# dbg' marker can be - # automatically detected and is used elsewhere). - DEBUG = False - #DEBUG = True # dbg - if DEBUG: - try: - self.complete(text, line_buffer, cursor_pos) - except: - import traceback; traceback.print_exc() - else: - # The normal production version is here - - # This method computes the self.matches array - self.complete(text, line_buffer, cursor_pos) - - try: - return self.matches[state] - except IndexError: - return None - diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index c170efc49ab..7b686f9b076 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -343,9 +343,6 @@ def _exiter_default(self): Automatically call the pdb debugger after every exception. """ ).tag(config=True) - multiline_history = Bool(sys.platform != 'win32', - help="Save multi-line entries as one entry in readline history" - ).tag(config=True) display_page = Bool(False, help="""If True, anything that would be passed to the pager will be displayed as regular output instead.""" @@ -387,40 +384,10 @@ def _prompt_trait_changed(self, change): history_load_length = Integer(1000, help= """ The number of saved history entries to be loaded - into the readline buffer at startup. + into the history buffer at startup. """ ).tag(config=True) - # The readline stuff will eventually be moved to the terminal subclass - # but for now, we can't do that as readline is welded in everywhere. - readline_use = Bool(True).tag(config=True) - readline_remove_delims = Unicode('-/~').tag(config=True) - readline_delims = Unicode() # set by init_readline() - # don't use \M- bindings by default, because they - # conflict with 8-bit encodings. See gh-58,gh-88 - readline_parse_and_bind = List([ - 'tab: complete', - '"\C-l": clear-screen', - 'set show-all-if-ambiguous on', - '"\C-o": tab-insert', - '"\C-r": reverse-search-history', - '"\C-s": forward-search-history', - '"\C-p": history-search-backward', - '"\C-n": history-search-forward', - '"\e[A": history-search-backward', - '"\e[B": history-search-forward', - '"\C-k": kill-line', - '"\C-u": unix-line-discard', - ]).tag(config=True) - - _custom_readline_config = False - - @observe('readline_parse_and_bind') - def _readline_parse_and_bind_changed(self, change): - # notice that readline config is customized - # indicates that it should have higher priority than inputrc - self._custom_readline_config = True - ast_node_interactivity = Enum(['all', 'last', 'last_expr', 'none'], default_value='last_expr', help=""" diff --git a/IPython/core/usage.py b/IPython/core/usage.py index 21de20b79e3..a3d17ddda04 100644 --- a/IPython/core/usage.py +++ b/IPython/core/usage.py @@ -109,12 +109,9 @@ variable names, and show you a list of the possible completions if there's no unambiguous one. It will also complete filenames in the current directory. - This feature requires the readline and rlcomplete modules, so it won't work - if your Python lacks readline support (such as under Windows). +* Search previous command history in two ways: -* Search previous command history in two ways (also requires readline): - - - Start typing, and then use Ctrl-p (previous,up) and Ctrl-n (next,down) to + - Start typing, and then use Ctrl-p (previous, up) and Ctrl-n (next,down) to search through only the history items that match what you've typed so far. If you use Ctrl-p/Ctrl-n at a blank prompt, they just behave like normal arrow keys. @@ -123,7 +120,7 @@ your history for lines that match what you've typed so far, completing as much as it can. - - %hist: search history by index (this does *not* require readline). + - %hist: search history by index. * Persistent command history across sessions. @@ -255,7 +252,6 @@ interactive_usage_min = """\ An enhanced console for Python. Some of its features are: -- Readline support if the readline library is present. - Tab completion in the local namespace. - Logging of input, see command-line options. - System shell escape via ! , eg !ls. diff --git a/setup.py b/setup.py index 8d78f9378a4..d23d5eb3f21 100755 --- a/setup.py +++ b/setup.py @@ -220,20 +220,8 @@ def run(self): if sys.platform == 'darwin': install_requires.extend(['appnope']) - have_readline = False - try: - import readline - except ImportError: - pass - else: - if 'libedit' not in readline.__doc__: - have_readline = True - if not have_readline: - install_requires.extend(['gnureadline']) - - if sys.platform.startswith('win'): - extras_require['terminal'].append('pyreadline>=2.0') - else: + + if not sys.platform.startswith('win'): install_requires.append('pexpect') # workaround pypa/setuptools#147, where setuptools misspells From 05331d1aecacf5bc72cbd5747791db9e08253bde Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 15:07:05 -0700 Subject: [PATCH 0505/4859] remove rest of readline, pass II --- IPython/core/interactiveshell.py | 20 ++----- IPython/core/magics/execution.py | 89 ++++++++++++++++---------------- IPython/core/shellapp.py | 6 --- IPython/core/ultratb.py | 1 - IPython/terminal/embed.py | 3 -- 5 files changed, 48 insertions(+), 71 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 7b686f9b076..5a69341d41e 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -62,7 +62,6 @@ from IPython.utils import io from IPython.utils import py3compat from IPython.utils import openpy -from IPython.utils.contexts import NoOpContext from IPython.utils.decorators import undoc from IPython.utils.io import ask_yes_no from IPython.utils.ipstruct import Struct @@ -574,9 +573,6 @@ def init_instance_attrs(self): self.tempfiles = [] self.tempdirs = [] - # Keep track of readline usage (later set by init_readline) - self.has_readline = False - # keep track of where we started running (mainly for crash post-mortem) # This is not being used anywhere currently. self.starting_dir = py3compat.getcwd() @@ -659,11 +655,8 @@ def init_io(self): # override sys.stdout and sys.stderr themselves, you need to do that # *before* instantiating this class, because io holds onto # references to the underlying streams. - if (sys.platform == 'win32' or sys.platform == 'cli') and self.has_readline: - io.stdout = io.stderr = io.IOStream(self.readline._outputfile) - else: - io.stdout = io.IOStream(sys.stdout) - io.stderr = io.IOStream(sys.stderr) + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) def init_prompts(self): # Set system prompts, so that scripts can decide if they are running @@ -984,9 +977,7 @@ def debugger(self,force=False): error('No traceback has been produced, nothing to debug.') return - - with self.readline_no_record: - self.InteractiveTB.debugger(force=True) + self.InteractiveTB.debugger(force=True) #------------------------------------------------------------------------- # Things related to IPython's various namespaces @@ -1889,10 +1880,7 @@ def showindentationerror(self): def init_readline(self): """Moved to terminal subclass, here only to simplify the init logic.""" - self.readline = None # Set a number of methods that depend on readline to be no-op - self.readline_no_record = NoOpContext() - self.set_readline_completer = no_op self.set_custom_completer = no_op @skip_doctest @@ -1929,7 +1917,7 @@ def init_completer(self): self.Completer = IPCompleter(shell=self, namespace=self.user_ns, global_namespace=self.user_global_ns, - use_readline=self.has_readline, + use_readline=False, parent=self, ) self.configurables.append(self.Completer) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 6ab3d24e720..6c3ad73d7e5 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -705,55 +705,54 @@ def run(self, parameter_s='', runner=None, try: stats = None - with self.shell.readline_no_record: - if 'p' in opts: - stats = self._run_with_profiler(code, opts, code_ns) + if 'p' in opts: + stats = self._run_with_profiler(code, opts, code_ns) + else: + if 'd' in opts: + bp_file, bp_line = parse_breakpoint( + opts.get('b', ['1'])[0], filename) + self._run_with_debugger( + code, code_ns, filename, bp_line, bp_file) else: - if 'd' in opts: - bp_file, bp_line = parse_breakpoint( - opts.get('b', ['1'])[0], filename) - self._run_with_debugger( - code, code_ns, filename, bp_line, bp_file) + if 'm' in opts: + def run(): + self.shell.safe_run_module(modulename, prog_ns) else: - if 'm' in opts: - def run(): - self.shell.safe_run_module(modulename, prog_ns) - else: - if runner is None: - runner = self.default_runner - if runner is None: - runner = self.shell.safe_execfile - - def run(): - runner(filename, prog_ns, prog_ns, - exit_ignore=exit_ignore) - - if 't' in opts: - # timed execution - try: - nruns = int(opts['N'][0]) - if nruns < 1: - error('Number of runs must be >=1') - return - except (KeyError): - nruns = 1 - self._run_with_timing(run, nruns) - else: - # regular execution - run() - - if 'i' in opts: - self.shell.user_ns['__name__'] = __name__save - else: - # update IPython interactive namespace + if runner is None: + runner = self.default_runner + if runner is None: + runner = self.shell.safe_execfile + + def run(): + runner(filename, prog_ns, prog_ns, + exit_ignore=exit_ignore) + + if 't' in opts: + # timed execution + try: + nruns = int(opts['N'][0]) + if nruns < 1: + error('Number of runs must be >=1') + return + except (KeyError): + nruns = 1 + self._run_with_timing(run, nruns) + else: + # regular execution + run() + + if 'i' in opts: + self.shell.user_ns['__name__'] = __name__save + else: + # update IPython interactive namespace - # Some forms of read errors on the file may mean the - # __name__ key was never set; using pop we don't have to - # worry about a possible KeyError. - prog_ns.pop('__name__', None) + # Some forms of read errors on the file may mean the + # __name__ key was never set; using pop we don't have to + # worry about a possible KeyError. + prog_ns.pop('__name__', None) - with preserve_keys(self.shell.user_ns, '__file__'): - self.shell.user_ns.update(prog_ns) + with preserve_keys(self.shell.user_ns, '__file__'): + self.shell.user_ns.update(prog_ns) finally: # It's a bit of a mystery why, but __builtins__ can change from # being a module to becoming a dict missing some key data after diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 821e593139d..3e54d63f57b 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -343,12 +343,6 @@ def _run_startup_files(self): except: self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup) self.shell.showtraceback() - finally: - # Many PYTHONSTARTUP files set up the readline completions, - # but this is often at odds with IPython's own completions. - # Do not allow PYTHONSTARTUP to set up readline. - if self.shell.has_readline: - self.shell.set_readline_completer() startup_files += glob.glob(os.path.join(startup_dir, '*.py')) startup_files += glob.glob(os.path.join(startup_dir, '*.ipy')) diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 3e636b3d848..7fc7c72d48d 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -115,7 +115,6 @@ ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode # IPython's own modules -# Modified pdb which doesn't damage IPython's readline handling from IPython import get_ipython from IPython.core import debugger from IPython.core.display_trap import DisplayTrap diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 275cacea8d2..9cac1afc448 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -140,9 +140,6 @@ def __call__(self, header='', local_ns=None, module=None, dummy=None, if dummy or (dummy != 0 and self.dummy_mode): return - if self.has_readline: - self.set_readline_completer() - # self.banner is auto computed if header: self.old_banner2 = self.banner2 From ece4cd07115392ccef152b11d56e76709dc1e16c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 15:27:04 -0700 Subject: [PATCH 0506/4859] deprecated noop context managers --- IPython/utils/contexts.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/IPython/utils/contexts.py b/IPython/utils/contexts.py index fcc97d7d933..567a7538ccf 100644 --- a/IPython/utils/contexts.py +++ b/IPython/utils/contexts.py @@ -2,6 +2,8 @@ """Miscellaneous context managers. """ +import warnings + # Copyright (c) IPython Development Team. # Distributed under the terms of the Modified BSD License. @@ -59,6 +61,13 @@ def __exit__(self, *exc_info): class NoOpContext(object): - """Context manager that does nothing.""" + """ + Deprecated + + Context manager that does nothing.""" + + def __init__(self): + warnings.warn("""NoOpContext is deprecated since IPython 5.0 """) + def __enter__(self): pass def __exit__(self, type, value, traceback): pass From 4e3f13246eb705a277bbe6dbc8f2c17d1d829d01 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 08:58:15 -0700 Subject: [PATCH 0507/4859] Also remove kernelspec --- examples/IPython Kernel/ipython-completion.bash | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/examples/IPython Kernel/ipython-completion.bash b/examples/IPython Kernel/ipython-completion.bash index 61b2ce40138..30eafdf95c8 100644 --- a/examples/IPython Kernel/ipython-completion.bash +++ b/examples/IPython Kernel/ipython-completion.bash @@ -24,7 +24,7 @@ _ipython() { local cur=${COMP_WORDS[COMP_CWORD]} local prev=${COMP_WORDS[COMP_CWORD - 1]} - local subcommands="kernel profile locate history kernelspec" + local subcommands="kernel profile locate history" local opts="help" if [ -z "$__ipython_complete_baseopts" ]; then _ipython_get_flags baseopts @@ -53,7 +53,7 @@ _ipython() "locate" | "profile") _ipython_get_flags $mode ;; - "history" | "kernelspec") + "history") if [[ $COMP_CWORD -ge 3 ]]; then # 'history trim' and 'history clear' covered by next line _ipython_get_flags $mode\ "${COMP_WORDS[2]}" @@ -83,15 +83,6 @@ _ipython() fi local IFS=$'\t\n' COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) - elif [[ $mode == "kernelspec" ]]; then - if [[ $COMP_CWORD -ge 3 ]]; then - # drop into flags - opts="--" - else - opts="list install " - fi - local IFS=$'\t\n' - COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) elif [[ $mode == "locate" ]]; then if [[ $COMP_CWORD -ge 3 ]]; then # drop into flags From f4c87c4c70913a2340e617816bb78b7eec67ff6d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 30 Jun 2016 14:18:32 -0700 Subject: [PATCH 0508/4859] Do not emit single completions trailing with space. Workaround #9658, that can thus be delayed post 5.0 --- IPython/core/completer.py | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 16c2942f80c..7583628bbf4 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -77,6 +77,8 @@ from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 from traitlets import Bool, Enum, observe +from functools import wraps + #----------------------------------------------------------------------------- # Globals #----------------------------------------------------------------------------- @@ -90,6 +92,44 @@ PROTECTABLES = ' ()[]{}?=\\|;:\'#*"^&' +#----------------------------------------------------------------------------- +# Work around BUG decorators. +#----------------------------------------------------------------------------- + +def _strip_single_trailing_space(complete): + """ + This is a workaround for a weird IPython/Prompt_toolkit behavior, + that can be removed once we rely on a slightly more recent prompt_toolkit + version (likely > 1.0.3). So this can likely be removed in IPython 6.0 + + cf https://github.com/ipython/ipython/issues/9658 + and https://github.com/jonathanslenders/python-prompt-toolkit/pull/328 + + The bug is due to the fact that in PTK the completer will reinvoke itself + after trying to completer to the longuest common prefix of all the + completions, unless only one completion is available. + + This logic is faulty if the completion ends with space, which can happen in + case like:: + + from foo import im + + which only matching completion is `import `. Note the leading space at the + end. So leaving a space at the end is a reasonable request, but for now + we'll strip it. + """ + + @wraps(complete) + def comp(*args, **kwargs): + text, matches = complete(*args, **kwargs) + if len(matches) == 1: + return text, [matches[0].rstrip()] + return text, matches + + return comp + + + #----------------------------------------------------------------------------- # Main functions and classes #----------------------------------------------------------------------------- @@ -1121,6 +1161,7 @@ def dispatch_custom_completer(self, text): return None + @_strip_single_trailing_space def complete(self, text=None, line_buffer=None, cursor_pos=None): """Find completions for the given text and line context. From 18d1281cd709ef1b636226a20f2db6321650345e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 09:08:48 -0700 Subject: [PATCH 0509/4859] Typo + Add Warning class for deprecation. Also set the stack level to 2, to get the warning where the context manager is constructed, if used. --- IPython/core/completer.py | 2 +- IPython/utils/contexts.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index ba8cdcddb16..bb143b66759 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -1,7 +1,7 @@ # encoding: utf-8 """Word completion for IPython. -This module stared as fork of the rlcompleter module in the Python standard +This module started as fork of the rlcompleter module in the Python standard library. The original enhancements made to rlcompleter have been sent upstream and were accepted as of Python 2.3, diff --git a/IPython/utils/contexts.py b/IPython/utils/contexts.py index 567a7538ccf..4d379b0eda1 100644 --- a/IPython/utils/contexts.py +++ b/IPython/utils/contexts.py @@ -67,7 +67,8 @@ class NoOpContext(object): Context manager that does nothing.""" def __init__(self): - warnings.warn("""NoOpContext is deprecated since IPython 5.0 """) + warnings.warn("""NoOpContext is deprecated since IPython 5.0 """, + DeprecationWarning, stacklevel=2) def __enter__(self): pass def __exit__(self, type, value, traceback): pass From 54686d709fa13893043486dfc2a790cf64b78eb5 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 09:40:47 -0700 Subject: [PATCH 0510/4859] Precise you can use `:memory:` for the history --- IPython/core/history.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/IPython/core/history.py b/IPython/core/history.py index 5147ad9352a..682032b7d5b 100644 --- a/IPython/core/history.py +++ b/IPython/core/history.py @@ -161,6 +161,9 @@ class HistoryAccessor(HistoryAccessorBase): local disk, e.g:: ipython --HistoryManager.hist_file=/tmp/ipython_hist.sqlite + + you can also use the specific value `:memory:` (including the colon + at both end but not the back ticks), to avoid creating an history file. """).tag(config=True) From b0683fdae24c879537a35a5a6774474d5a6084a7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 14:02:02 -0700 Subject: [PATCH 0511/4859] fix docs requirement that prevent RTD to build --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 830b9057cf1..958b938fc76 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,3 @@ --e ../. +-e . ipykernel setuptools>=18.5 From 93d5d2edd0b5b81c3a11c5967845bd9c745685f7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 16:24:12 -0700 Subject: [PATCH 0512/4859] Update readme instructions. --- README.rst | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/README.rst b/README.rst index 9da53f02b44..6911d8c933e 100644 --- a/README.rst +++ b/README.rst @@ -18,28 +18,30 @@ Overview ======== -Welcome to IPython. Our full documentation is available on `our website -`_; if you downloaded a built source -distribution the ``docs/source`` directory contains the plaintext version of -these manuals. If you have Sphinx installed, you can build them by typing -``cd docs; make html`` for local browsing. +Welcome to IPython. Our full documentation is available on `ipython.readthedocs.io +`_ and contain information on how to install, use +contribute to the project. - -See the `install page `__ to install IPython. +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. The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*. See the `Jupyter installation docs `__ if you want to use these. -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. -Instant running -=============== + +Developement 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 +Documentation and installation instructions for older version of IPython can be found on the +`IPython website `_ From dfb9e32b1c73a0e11c3fa925d86c2fdef1994931 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 1 Jul 2016 16:56:01 -0700 Subject: [PATCH 0513/4859] Sum documentation improvement from Mike getting-started session. --- docs/source/coredev/index.rst | 18 +++++++-- docs/source/install/install.rst | 65 ++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index 3d2953933a0..fa861115b54 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -1,18 +1,28 @@ .. _core_developer_guide: ================================== -Developer's guide to core IPython +Guide for IPtyhon core Developpers ================================== This guide documents the development of core IPython. Alternatively, developers of third party tools and libraries that use IPython should see the :doc:`../development/index`. -Developers working on core IPython should also consult the -`developer information `_ -on the IPython GitHub wiki. + +For instruction on how to make a developer install see devinstall_. .. toctree:: :maxdepth: 1 release_process + + +Old Documentation +================= + +Out of date documentation is still available and have been kept for archival +reason. + +Developers working on core IPython should also consult the +`developer information `_ +on the IPython GitHub wiki. diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index c6610ff4a99..769e3074507 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -24,11 +24,13 @@ install Jupyter ``pip install jupyter``. Overview -------- -This document describes in detail the steps required to install IPython. -For a few quick ways to get started with package managers or full Python distributions, -see `the install page `_ of the IPython website. +This document describes in detail the steps required to install IPython. For a +few quick ways to get started with package managers or full Python +distributions, see `the install page `_ of the +IPython website. -Please let us know if you have problems installing IPython or any of its dependencies. +Please let us know if you have problems installing IPython or any of its +dependencies. IPython and most dependencies should be installed via :command:`pip`. In many scenarios, this is the simplest method of installing Python packages. @@ -39,13 +41,25 @@ More information about :mod:`pip` can be found on More general information about installing Python packages can be found in `Python's documentation `_. +.. _dependencies: + +Dependencies +~~~~~~~~~~~~ + +IPython relies on a number of other Python packages. Installing using a package +manager like pip or conda will ensure the necessary packages are installed. If +you install manually, it's up to you to make sure dependencies are installed. +They're not listed here since a static list would inevitably fall out of date as +dependencies may change from release to release and also vary depending on +the platform. + Installing IPython itself ~~~~~~~~~~~~~~~~~~~~~~~~~ IPython requires several dependencies to work correctly, it is not recommended -to install IPython and all its dependencies manually as this can be quite long and troublesome. -You should use the python package manager ``pip``. +to install IPython and all its dependencies manually as this can be quite long +and troublesome. You should use the python package manager ``pip``. Installation using pip ~~~~~~~~~~~~~~~~~~~~~~ @@ -76,40 +90,42 @@ grab the latest stable tarball of IPython `from PyPI $ cd ipython $ pip install . -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. +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. 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 -also install in user specific location by using the ``--user`` flag in conjunction with pip. +also install in user specific location by using the ``--user`` flag in +conjunction with pip. -To run IPython's test suite, use the :command:`iptest` command from outside of the IPython source tree: +To run IPython's test suite, use the :command:`iptest` command from outside of +the IPython source tree: .. code-block:: bash $ iptest - +.. _devinstall: Installing the development version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is also possible to install the development version of IPython from our `Git `_ source code repository. To do this you will -need to have Git installed on your system. Then do: - -.. code-block:: bash +need to have Git installed on your system. - $ git clone https://github.com/ipython/ipython.git - $ cd ipython - $ pip install . -Some users want to be able to follow the development branch as it changes. -With :mod:`pip` installed, you can replace the last step by: +Then do: .. code-block:: bash + $ git clone https://github.com/ipython/ipython.git + $ cd ipython $ pip install -e . +The `pip install -e .` allow users and developers to be able to follow the +development branch as it changes. + This creates links in the right places and installs the command line script to the appropriate location. @@ -119,14 +135,3 @@ Then, if you want to update your IPython at any time, do: $ git pull -.. _dependencies: - -Dependencies -~~~~~~~~~~~~ - -IPython relies on a number of other Python packages. Installing using a package -manager like pip or conda will ensure the necessary packages are installed. If -you install manually, it's up to you to make sure dependencies are installed. -They're not listed here since a static list would inevitably fall out of date as -dependencies may change from release to release and also vary depending on -the platform. From f2af3b381dc097bd35d1139463c90eee0042c772 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 5 Jul 2016 16:23:24 +0100 Subject: [PATCH 0514/4859] Pull shortcut definitions out to a separate module --- IPython/terminal/interactiveshell.py | 134 +--------------------- IPython/terminal/shortcuts.py | 165 +++++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 129 deletions(-) create mode 100644 IPython/terminal/shortcuts.py diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 88159a0e931..046fc0d16fa 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -3,28 +3,22 @@ import os import sys -import signal from warnings import warn -from IPython.core.error import TryNext from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC from IPython.utils.py3compat import PY3, cast_unicode_py2, input 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 prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER, EditingMode -from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, - ViInsertMode, EmacsInsertMode, IsDone, HasCompletions) -from prompt_toolkit.filters.cli import ViMode +from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode +from prompt_toolkit.filters import (HasFocus, Condition, IsDone) from prompt_toolkit.history import InMemoryHistory from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager -from prompt_toolkit.keys import Keys from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor from prompt_toolkit.styles import PygmentsStyle, DynamicStyle -from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline from pygments.styles import get_style_by_name, get_all_styles from pygments.token import Token @@ -34,6 +28,7 @@ from .pt_inputhooks import get_inputhook_func from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook from .ptutils import IPythonPTCompleter, IPythonPTLexer +from .shortcuts import register_ipython_shortcuts DISPLAY_BANNER_DEPRECATED = object() @@ -212,128 +207,9 @@ def prompt(): self.prompt_for_code = prompt return + # Set up keyboard shortcuts kbmanager = KeyBindingManager.for_prompt() - insert_mode = ViInsertMode() | EmacsInsertMode() - # Ctrl+J == Enter, seemingly - @kbmanager.registry.add_binding(Keys.ControlJ, - filter=(HasFocus(DEFAULT_BUFFER) - & ~HasSelection() - & insert_mode - )) - def _(event): - b = event.current_buffer - d = b.document - - if b.complete_state: - cc = b.complete_state.current_completion - if cc: - b.apply_completion(cc) - else: - b.cancel_completion() - return - - if not (d.on_last_line or d.cursor_position_row >= d.line_count - - d.empty_line_count_at_the_end()): - b.newline() - return - - status, indent = self.input_splitter.check_complete(d.text + '\n') - - if (status != 'incomplete') and b.accept_action.is_returnable: - b.accept_action.validate_and_handle(event.cli, b) - else: - b.insert_text('\n' + (' ' * (indent or 0))) - - @kbmanager.registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) - def _previous_history_or_previous_completion(event): - """ - Control-P in vi edit mode on readline is history next, unlike default prompt toolkit. - - If completer is open this still select previous completion. - """ - event.current_buffer.auto_up() - - @kbmanager.registry.add_binding(Keys.ControlN, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER))) - def _next_history_or_next_completion(event): - """ - Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit. - - If completer is open this still select next completion. - """ - event.current_buffer.auto_down() - - @kbmanager.registry.add_binding(Keys.ControlG, filter=( - HasFocus(DEFAULT_BUFFER) & HasCompletions() - )) - def _dismiss_completion(event): - b = event.current_buffer - if b.complete_state: - b.cancel_completion() - - @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER)) - def _reset_buffer(event): - b = event.current_buffer - if b.complete_state: - b.cancel_completion() - else: - b.reset() - - @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) - def _reset_search_buffer(event): - if event.current_buffer.document.text: - event.current_buffer.reset() - else: - event.cli.push_focus(DEFAULT_BUFFER) - - supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) - - @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) - def _suspend_to_bg(event): - event.cli.suspend_to_background() - - @Condition - def cursor_in_leading_ws(cli): - before = cli.application.buffer.document.current_line_before_cursor - return (not before) or before.isspace() - - # Ctrl+I == Tab - @kbmanager.registry.add_binding(Keys.ControlI, - filter=(HasFocus(DEFAULT_BUFFER) - & ~HasSelection() - & insert_mode - & cursor_in_leading_ws - )) - def _indent_buffer(event): - event.current_buffer.insert_text(' ' * 4) - - - if self.display_completions == 'readlinelike': - @kbmanager.registry.add_binding(Keys.ControlI, - filter=(HasFocus(DEFAULT_BUFFER) - & ~HasSelection() - & insert_mode - & ~cursor_in_leading_ws - )) - def _disaply_compl(ev): - display_completions_like_readline(ev) - - - if sys.platform == 'win32': - from IPython.lib.clipboard import (ClipboardEmpty, - win32_clipboard_get, tkinter_clipboard_get) - @kbmanager.registry.add_binding(Keys.ControlV, - filter=(HasFocus(DEFAULT_BUFFER) & ~ViMode())) - def _paste(event): - try: - text = win32_clipboard_get() - except TryNext: - try: - text = tkinter_clipboard_get() - except (TryNext, ClipboardEmpty): - return - except ClipboardEmpty: - return - event.current_buffer.insert_text(text.replace('\t', ' ' * 4)) + register_ipython_shortcuts(kbmanager.registry, self) # Pre-populate history from IPython's history database history = InMemoryHistory() diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py new file mode 100644 index 00000000000..2c8cfec6a5c --- /dev/null +++ b/IPython/terminal/shortcuts.py @@ -0,0 +1,165 @@ +import signal +import sys + +from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER +from prompt_toolkit.filters import (HasFocus, HasSelection, Condition, + ViInsertMode, EmacsInsertMode, HasCompletions) +from prompt_toolkit.filters.cli import ViMode +from prompt_toolkit.keys import Keys +from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline + +@Condition +def cursor_in_leading_ws(cli): + before = cli.application.buffer.document.current_line_before_cursor + return (not before) or before.isspace() + +def register_ipython_shortcuts(registry, shell): + """Set up the prompt_toolkit keyboard shortcuts for IPython""" + insert_mode = ViInsertMode() | EmacsInsertMode() + + # Ctrl+J == Enter, seemingly + registry.add_binding(Keys.ControlJ, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + ))(newline_or_execute_outer(shell)) + + registry.add_binding(Keys.ControlP, + filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER) + ))(previous_history_or_previous_completion) + + registry.add_binding(Keys.ControlN, + filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER) + ))(next_history_or_next_completion) + + registry.add_binding(Keys.ControlG, + filter=(HasFocus(DEFAULT_BUFFER) & HasCompletions() + ))(dismiss_completion) + + registry.add_binding(Keys.ControlC, filter=HasFocus(DEFAULT_BUFFER) + )(reset_buffer) + + registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER) + )(reset_search_buffer) + + supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) + registry.add_binding(Keys.ControlZ, filter=supports_suspend + )(suspend_to_bg) + + # Ctrl+I == Tab + registry.add_binding(Keys.ControlI, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + & cursor_in_leading_ws + ))(indent_buffer) + + if shell.display_completions == 'readlinelike': + registry.add_binding(Keys.ControlI, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode + & ~cursor_in_leading_ws + ))(display_completions_like_readline) + + if sys.platform == 'win32': + registry.add_binding(Keys.ControlV, + filter=( + HasFocus( + DEFAULT_BUFFER) & ~ViMode() + ))(win_paste) + + +def newline_or_execute_outer(shell): + def newline_or_execute(event): + """When the user presses return, insert a newline or execute the code.""" + b = event.current_buffer + d = b.document + + if b.complete_state: + cc = b.complete_state.current_completion + if cc: + b.apply_completion(cc) + else: + b.cancel_completion() + return + + if not (d.on_last_line or d.cursor_position_row >= d.line_count + - d.empty_line_count_at_the_end()): + b.newline() + return + + status, indent = shell.input_splitter.check_complete(d.text + '\n') + + if (status != 'incomplete') and b.accept_action.is_returnable: + b.accept_action.validate_and_handle(event.cli, b) + else: + b.insert_text('\n' + (' ' * (indent or 0))) + return newline_or_execute + + +def previous_history_or_previous_completion(event): + """ + Control-P in vi edit mode on readline is history next, unlike default prompt toolkit. + + If completer is open this still select previous completion. + """ + event.current_buffer.auto_up() + + +def next_history_or_next_completion(event): + """ + Control-N in vi edit mode on readline is history previous, unlike default prompt toolkit. + + If completer is open this still select next completion. + """ + event.current_buffer.auto_down() + + +def dismiss_completion(event): + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + + +def reset_buffer(event): + b = event.current_buffer + if b.complete_state: + b.cancel_completion() + else: + b.reset() + + +def reset_search_buffer(event): + if event.current_buffer.document.text: + event.current_buffer.reset() + else: + event.cli.push_focus(DEFAULT_BUFFER) + +def suspend_to_bg(event): + event.cli.suspend_to_background() + +def indent_buffer(event): + event.current_buffer.insert_text(' ' * 4) + + + + +if sys.platform == 'win32': + from IPython.core.error import TryNext + from IPython.lib.clipboard import (ClipboardEmpty, + win32_clipboard_get, + tkinter_clipboard_get) + + + def win_paste(event): + try: + text = win32_clipboard_get() + except TryNext: + try: + text = tkinter_clipboard_get() + except (TryNext, ClipboardEmpty): + return + except ClipboardEmpty: + return + event.current_buffer.insert_text(text.replace('\t', ' ' * 4)) From 6ef113e4197bf8aab76bbb95b059b49459576214 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Jul 2016 08:42:07 -0700 Subject: [PATCH 0515/4859] Remove readline mention, add Deprecation Warning --- IPython/core/completer.py | 3 --- IPython/core/interactiveshell.py | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index bb143b66759..a21638a9f09 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -5,9 +5,6 @@ library. The original enhancements made to rlcompleter have been sent upstream and were accepted as of Python 2.3, - -This is now mostly Completer implementation made to function with -prompt_toolkit, but that should still work with readline. """ # Copyright (c) IPython Development Team. diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 5a69341d41e..d1f87e44365 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -1879,8 +1879,12 @@ def showindentationerror(self): #------------------------------------------------------------------------- def init_readline(self): - """Moved to terminal subclass, here only to simplify the init logic.""" + """DEPRECATED + + Moved to terminal subclass, here only to simplify the init logic.""" # Set a number of methods that depend on readline to be no-op + warnings.warn('`init_readline` is no-op since IPython 5.0 and is Deprecated', + DeprecationWarning, stacklevel=2) self.set_custom_completer = no_op @skip_doctest From 4f93c0fdb5f8024d924bd2d5386b1095d6fddc41 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Jul 2016 08:56:16 -0700 Subject: [PATCH 0516/4859] Skip module as a whole --- IPython/utils/warn.py | 5 ----- docs/autogen_api.py | 2 ++ 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index 127f692f78e..cfbf3b757da 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -10,11 +10,9 @@ import sys import warnings -from IPython.utils.decorators import undoc warnings.warn("The module IPython.utils.warn is deprecated since IPython 4.0, use the standard warnings module instead", DeprecationWarning) -@undoc def warn(msg,level=2,exit_val=1): """Deprecated @@ -43,7 +41,6 @@ def warn(msg,level=2,exit_val=1): sys.exit(exit_val) -@undoc def info(msg): """Deprecated @@ -52,7 +49,6 @@ def info(msg): warn(msg,level=1) -@undoc def error(msg): """Deprecated @@ -61,7 +57,6 @@ def error(msg): warn(msg,level=3) -@undoc def fatal(msg,exit_val=1): """Deprecated diff --git a/docs/autogen_api.py b/docs/autogen_api.py index 504ab0f3e5c..f1064a0fdf5 100755 --- a/docs/autogen_api.py +++ b/docs/autogen_api.py @@ -54,6 +54,8 @@ r'\.nbformat', r'\.parallel', r'\.qt', + # this is deprecated. + r'\.utils\.warn', ] # main API is in the inputhook module, which is documented. From 192b3e4c7a290ce87932965ab2d36343eea6dd19 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Jul 2016 09:27:28 -0700 Subject: [PATCH 0517/4859] release 5.0.0rc1 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index f2486977c89..2a5f45c6bff 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -# _version_extra = 'b4' +_version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From 74b03690fe78a04e28a5003988c81033af9d8771 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Tue, 5 Jul 2016 09:30:29 -0700 Subject: [PATCH 0518/4859] Back to dev --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 2a5f45c6bff..e98d10a7ff7 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -23,7 +23,7 @@ _version_minor = 0 _version_patch = 0 _version_extra = '.dev' -_version_extra = 'rc1' +# _version_extra = 'rc1' # _version_extra = '' # Uncomment this for full releases # release.codename is deprecated in 2.0, will be removed in 3.0 From e9301c9b52a1ebd4f72527098da896097f46c5fa Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 6 Jul 2016 11:20:00 +0100 Subject: [PATCH 0519/4859] Try to fix Qt event loop, take III This involves neither threads nor calling in to the old inputhook machinery. --- IPython/terminal/pt_inputhooks/qt.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/pt_inputhooks/qt.py b/IPython/terminal/pt_inputhooks/qt.py index 1fd4e9290f3..ebf3a94eaa0 100644 --- a/IPython/terminal/pt_inputhooks/qt.py +++ b/IPython/terminal/pt_inputhooks/qt.py @@ -1,3 +1,4 @@ +import sys from IPython.external.qt_for_kernel import QtCore, QtGui def inputhook(context): @@ -5,7 +6,20 @@ def inputhook(context): if not app: return event_loop = QtCore.QEventLoop(app) - notifier = QtCore.QSocketNotifier(context.fileno(), QtCore.QSocketNotifier.Read) - notifier.setEnabled(True) - notifier.activated.connect(event_loop.exit) - event_loop.exec_() + + if sys.platform == 'win32': + # The QSocketNotifier method doesn't appear to work on Windows. + # Use polling instead. + timer = QtCore.QTimer() + timer.timeout.connect(event_loop.quit) + while not context.input_is_ready(): + timer.start(50) # 50 ms + event_loop.exec_() + timer.stop() + else: + # On POSIX platforms, we can use a file descriptor to quit the event + # loop when there is input ready to read. + notifier = QtCore.QSocketNotifier(context.fileno(), QtCore.QSocketNotifier.Read) + notifier.setEnabled(True) + notifier.activated.connect(event_loop.exit) + event_loop.exec_() From b9b42998e692e3c14ae35b918a55964c51909ce4 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 6 Jul 2016 13:05:10 +0200 Subject: [PATCH 0520/4859] fix traitlets 4.2 API usage when creating parallel profiles ipython profile create --parallel would fail due to the 4.2-style decorator, but not updated signature --- IPython/core/profileapp.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IPython/core/profileapp.py b/IPython/core/profileapp.py index 37f47eed74e..b8e5fd26ac3 100644 --- a/IPython/core/profileapp.py +++ b/IPython/core/profileapp.py @@ -223,12 +223,12 @@ def _copy_config_files_default(self): ).tag(config=True) @observe('parallel') - def _parallel_changed(self, name, old, new): + def _parallel_changed(self, change): parallel_files = [ 'ipcontroller_config.py', 'ipengine_config.py', 'ipcluster_config.py' ] - if new: + if change['new']: for cf in parallel_files: self.config_files.append(cf) else: From 83b460be022bf9951cf6f52dc1a2b73f9019cd44 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 6 Jul 2016 14:32:51 +0200 Subject: [PATCH 0521/4859] minor docs updates Follow-up to #9697 Some wording changes, typos, and rst formatting. --- docs/source/coredev/index.rst | 15 +++++++-------- docs/source/install/install.rst | 25 +++++++++++++++---------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index fa861115b54..d4331a026da 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -1,15 +1,15 @@ .. _core_developer_guide: -================================== -Guide for IPtyhon core Developpers -================================== +================================= +Guide for IPython core Developers +================================= -This guide documents the development of core IPython. Alternatively, +This guide documents the development of IPython itself. Alternatively, developers of third party tools and libraries that use IPython should see the :doc:`../development/index`. -For instruction on how to make a developer install see devinstall_. +For instruction on how to make a developer install see :ref:`devinstall`. .. toctree:: :maxdepth: 1 @@ -20,9 +20,8 @@ For instruction on how to make a developer install see devinstall_. Old Documentation ================= -Out of date documentation is still available and have been kept for archival -reason. +Out of date documentation is still available and have been kept for archival purposes. -Developers working on core IPython should also consult the +Developers working on IPython should also consult the `developer information `_ on the IPython GitHub wiki. diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index 769e3074507..32ab774af97 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -47,11 +47,10 @@ Dependencies ~~~~~~~~~~~~ IPython relies on a number of other Python packages. Installing using a package -manager like pip or conda will ensure the necessary packages are installed. If -you install manually, it's up to you to make sure dependencies are installed. -They're not listed here since a static list would inevitably fall out of date as -dependencies may change from release to release and also vary depending on -the platform. +manager like pip or conda will ensure the necessary packages are installed. +Manual installation without dependencies is possible, but not recommended. +The dependencies can be viewed with package manager commands, +such as :command:`pip show ipython` or :command:`conda info ipython`. Installing IPython itself @@ -107,6 +106,7 @@ the IPython source tree: $ iptest .. _devinstall: + Installing the development version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -123,11 +123,9 @@ Then do: $ cd ipython $ pip install -e . -The `pip install -e .` allow users and developers to be able to follow the -development branch as it changes. - -This creates links in the right places and installs the command line script to -the appropriate location. +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 +installing the command line scripts to the appropriate locations. Then, if you want to update your IPython at any time, do: @@ -135,3 +133,10 @@ Then, if you want to update your IPython at any time, do: $ git pull +If the dependencies or entrypoints have changed, you may have to run + +.. code-block:: bash + + $ pip install -e . + +again, but this is infrequent. From 3e9f8b2bf454137534d74450647088647a68cbfb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 6 Jul 2016 08:43:21 -0700 Subject: [PATCH 0522/4859] Generate shortcuts on RTD Closes #9709 (I hope) --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 14f2d5348f5..1fbf9609745 100755 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ tags.add('rtd') # RTD doesn't use the Makefile, so re-run autogen_{things}.py here. - for name in ('config', 'api', 'magics'): + for name in ('config', 'api', 'magics', 'shortcuts'): fname = 'autogen_{}.py'.format(name) fpath = os.path.abspath(os.path.join('..', fname)) with open(fpath) as f: From 57b41e8403fa66179975cfd14f00a52fa6eb481c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 6 Jul 2016 11:49:53 -0700 Subject: [PATCH 0523/4859] Cleanup and add more deprecation warnings. --- IPython/core/interactiveshell.py | 12 --- IPython/lib/inputhook.py | 135 +++++++++++++++++++++++++------ 2 files changed, 110 insertions(+), 37 deletions(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index d1f87e44365..1cb0bc306fc 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -474,28 +474,16 @@ def __init__(self, ipython_dir=None, profile_dir=None, self.init_hooks() self.init_events() self.init_pushd_popd_magic() - # self.init_traceback_handlers use to be here, but we moved it below - # because it and init_io have to come after init_readline. self.init_user_ns() self.init_logger() self.init_builtins() # The following was in post_config_initialization self.init_inspector() - # init_readline() must come before init_io(), because init_io uses - # readline related things. - self.init_readline() - # We save this here in case user code replaces raw_input, but it needs - # to be after init_readline(), because PyPy's readline works by replacing - # raw_input. if py3compat.PY3: self.raw_input_original = input else: self.raw_input_original = raw_input - # init_completer must come after init_readline, because it needs to - # know whether readline is present or not system-wide to configure the - # completers, since the completion machinery can now operate - # independently of readline (e.g. over the network) self.init_completer() # TODO: init_io() needs to happen before init_traceback handlers # because the traceback handlers hardcode the stdout/stderr streams. diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py index 00b650a2ed7..c181005fb2a 100644 --- a/IPython/lib/inputhook.py +++ b/IPython/lib/inputhook.py @@ -1,5 +1,7 @@ # coding: utf-8 """ +Deprecated since IPython 5.0 + Inputhook management for GUI event loop integration. """ @@ -98,7 +100,9 @@ def _allow_CTRL_C_other(): class InputHookManager(object): - """Manage PyOS_InputHook for different GUI toolkits. + """DEPRECATED since IPython 5.0 + + Manage PyOS_InputHook for different GUI toolkits. This class installs various hooks under ``PyOSInputHook`` to handle GUI event loop integration. @@ -121,15 +125,25 @@ def _reset(self): self._current_gui = None def get_pyos_inputhook(self): - """Return the current PyOS_InputHook as a ctypes.c_void_p.""" + """DEPRECATED since IPython 5.0 + + Return the current PyOS_InputHook as a ctypes.c_void_p.""" + warn("`get_pyos_inputhook` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook") def get_pyos_inputhook_as_func(self): - """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE.""" + """DEPRECATED since IPython 5.0 + + Return the current PyOS_InputHook as a ctypes.PYFUNCYPE.""" + warn("`get_pyos_inputhook_as_func` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook") def set_inputhook(self, callback): - """Set PyOS_InputHook to callback and return the previous one.""" + """DEPRECATED since IPython 5.0 + + Set PyOS_InputHook to callback and return the previous one.""" # On platforms with 'readline' support, it's all too likely to # have a KeyboardInterrupt signal delivered *even before* an # initial ``try:`` clause in the callback can be executed, so @@ -145,7 +159,9 @@ def set_inputhook(self, callback): return original def clear_inputhook(self, app=None): - """Set PyOS_InputHook to NULL and return the previous one. + """DEPRECATED since IPython 5.0 + + Set PyOS_InputHook to NULL and return the previous one. Parameters ---------- @@ -155,6 +171,8 @@ def clear_inputhook(self, app=None): the actual value of the parameter is ignored. This uniform interface makes it easier to have user-level entry points in the main IPython app like :meth:`enable_gui`.""" + warn("`clear_inputhook` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) pyos_inputhook_ptr = self.get_pyos_inputhook() original = self.get_pyos_inputhook_as_func() pyos_inputhook_ptr.value = ctypes.c_void_p(None).value @@ -163,7 +181,9 @@ def clear_inputhook(self, app=None): return original def clear_app_refs(self, gui=None): - """Clear IPython's internal reference to an application instance. + """DEPRECATED since IPython 5.0 + + Clear IPython's internal reference to an application instance. Whenever we create an app for a user on qt4 or wx, we hold a reference to the app. This is needed because in some cases bad things @@ -177,13 +197,17 @@ def clear_app_refs(self, gui=None): the app for that toolkit. References are not held for gtk or tk as those toolkits don't have the notion of an app. """ + warn("`clear_app_refs` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) if gui is None: self.apps = {} elif gui in self.apps: del self.apps[gui] def register(self, toolkitname, *aliases): - """Register a class to provide the event loop for a given GUI. + """DEPRECATED since IPython 5.0 + + Register a class to provide the event loop for a given GUI. This is intended to be used as a class decorator. It should be passed the names with which to register this GUI integration. The classes @@ -196,6 +220,8 @@ class QtInputHook(InputHookBase): def enable(self, app=None): ... """ + warn("`register` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) def decorator(cls): if ctypes is not None: inst = cls(self) @@ -206,11 +232,17 @@ def decorator(cls): return decorator def current_gui(self): - """Return a string indicating the currently active GUI or None.""" + """DEPRECATED since IPython 5.0 + + Return a string indicating the currently active GUI or None.""" + warn("`current_gui` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) return self._current_gui def enable_gui(self, gui=None, app=None): - """Switch amongst GUI input hooks by name. + """DEPRECATED since IPython 5.0 + + Switch amongst GUI input hooks by name. This is a higher level method than :meth:`set_inputhook` - it uses the GUI name to look up a registered object which enables the input hook @@ -234,6 +266,8 @@ def enable_gui(self, gui=None, app=None): PyOS_InputHook wrapper object or the GUI toolkit app created, if there was one. """ + warn("`enable_gui` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) if gui in (None, GUI_NONE): return self.disable_gui() @@ -250,22 +284,28 @@ def enable_gui(self, gui=None, app=None): app = gui_hook.enable(app) if app is not None: app._in_event_loop = True - self.apps[gui] = app + self.apps[gui] = app return app def disable_gui(self): - """Disable GUI event loop integration. + """DEPRECATED since IPython 5.0 + + Disable GUI event loop integration. If an application was registered, this sets its ``_in_event_loop`` attribute to False. It then calls :meth:`clear_inputhook`. """ + warn("`disable_gui` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) gui = self._current_gui if gui in self.apps: self.apps[gui]._in_event_loop = False return self.clear_inputhook() class InputHookBase(object): - """Base class for input hooks for specific toolkits. + """DEPRECATED since IPython 5.0 + + Base class for input hooks for specific toolkits. Subclasses should define an :meth:`enable` method with one argument, ``app``, which will either be an instance of the toolkit's application class, or None. @@ -281,14 +321,19 @@ def disable(self): @inputhook_manager.register('osx') class NullInputHook(InputHookBase): - """A null inputhook that doesn't need to do anything""" + """DEPRECATED since IPython 5.0 + + A null inputhook that doesn't need to do anything""" def enable(self, app=None): - pass + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) @inputhook_manager.register('wx') class WxInputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with wxPython. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with wxPython. Parameters ---------- @@ -309,6 +354,8 @@ def enable(self, app=None): import wx app = wx.App(redirect=False, clearSigInt=False) """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) import wx wx_version = V(wx.__version__).version @@ -331,10 +378,14 @@ def enable(self, app=None): return app def disable(self): - """Disable event loop integration with wxPython. + """DEPRECATED since IPython 5.0 + + Disable event loop integration with wxPython. This restores appnapp on OS X """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) if _use_appnope(): from appnope import nap nap() @@ -342,7 +393,9 @@ def disable(self): @inputhook_manager.register('qt', 'qt4') class Qt4InputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with PyQt4. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with PyQt4. Parameters ---------- @@ -363,6 +416,8 @@ def enable(self, app=None): from PyQt4 import QtCore app = QtGui.QApplication(sys.argv) """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) from IPython.lib.inputhookqt4 import create_inputhook_qt4 app, inputhook_qt4 = create_inputhook_qt4(self.manager, app) self.manager.set_inputhook(inputhook_qt4) @@ -373,10 +428,14 @@ def enable(self, app=None): return app def disable_qt4(self): - """Disable event loop integration with PyQt4. + """DEPRECATED since IPython 5.0 + + Disable event loop integration with PyQt4. This restores appnapp on OS X """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) if _use_appnope(): from appnope import nap nap() @@ -385,6 +444,8 @@ def disable_qt4(self): @inputhook_manager.register('qt5') class Qt5InputHook(Qt4InputHook): def enable(self, app=None): + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) os.environ['QT_API'] = 'pyqt5' return Qt4InputHook.enable(self, app) @@ -392,7 +453,9 @@ def enable(self, app=None): @inputhook_manager.register('gtk') class GtkInputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with PyGTK. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with PyGTK. Parameters ---------- @@ -407,6 +470,8 @@ def enable(self, app=None): the PyGTK to integrate with terminal based applications like IPython. """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) import gtk try: gtk.set_interactive(True) @@ -419,7 +484,9 @@ def enable(self, app=None): @inputhook_manager.register('tk') class TkInputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with Tk. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with Tk. Parameters ---------- @@ -434,6 +501,8 @@ def enable(self, app=None): :class:`InputHookManager`, since creating that object automatically sets ``PyOS_InputHook``. """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) if app is None: try: from tkinter import Tk # Py 3 @@ -448,7 +517,9 @@ def enable(self, app=None): @inputhook_manager.register('glut') class GlutInputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with GLUT. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with GLUT. Parameters ---------- @@ -471,6 +542,8 @@ def enable(self, app=None): The default screen mode is set to: glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) import OpenGL.GLUT as glut from IPython.lib.inputhookglut import glut_display_mode, \ @@ -498,12 +571,16 @@ def enable(self, app=None): def disable(self): - """Disable event loop integration with glut. + """DEPRECATED since IPython 5.0 + + Disable event loop integration with glut. This sets PyOS_InputHook to NULL and set the display function to a dummy one and set the timer to a dummy timer that will be triggered very far in the future. """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) import OpenGL.GLUT as glut from glut_support import glutMainLoopEvent @@ -514,7 +591,9 @@ def disable(self): @inputhook_manager.register('pyglet') class PygletInputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with pyglet. + """DEPRECATED since IPython 5.0 + + Enable event loop integration with pyglet. Parameters ---------- @@ -530,6 +609,8 @@ def enable(self, app=None): IPython. """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) from IPython.lib.inputhookpyglet import inputhook_pyglet self.manager.set_inputhook(inputhook_pyglet) return app @@ -538,7 +619,9 @@ def enable(self, app=None): @inputhook_manager.register('gtk3') class Gtk3InputHook(InputHookBase): def enable(self, app=None): - """Enable event loop integration with Gtk3 (gir bindings). + """DEPRECATED since IPython 5.0 + + Enable event loop integration with Gtk3 (gir bindings). Parameters ---------- @@ -553,6 +636,8 @@ def enable(self, app=None): the Gtk3 to integrate with terminal based applications like IPython. """ + warn("This function is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) from IPython.lib.inputhookgtk3 import inputhook_gtk3 self.manager.set_inputhook(inputhook_gtk3) @@ -568,7 +653,7 @@ def enable(self, app=None): def _deprecated_disable(): - warn("This function is deprecated: use disable_gui() instead") + warn("This function is deprecated since IPython 4.0 use disable_gui() instead", DeprecationWarning) inputhook_manager.disable_gui() disable_wx = disable_qt4 = disable_gtk = disable_gtk3 = disable_glut = \ disable_pyglet = disable_osx = _deprecated_disable From d5110016729e53791d7b82669b4ab8baa0fd7499 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 6 Jul 2016 14:57:15 -0700 Subject: [PATCH 0524/4859] Readd warning at import time. --- IPython/lib/inputhook.py | 5 +++++ IPython/testing/iptest.py | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py index c181005fb2a..98d8c2c269b 100644 --- a/IPython/lib/inputhook.py +++ b/IPython/lib/inputhook.py @@ -21,6 +21,11 @@ from warnings import warn + +warn("`IPython.lib.inputhook` is deprecated since IPython 5.0 and will be removed in future versions.", + DeprecationWarning, stacklevel=2) + + #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- diff --git a/IPython/testing/iptest.py b/IPython/testing/iptest.py index 7bfa6496ae0..b2f19a44932 100644 --- a/IPython/testing/iptest.py +++ b/IPython/testing/iptest.py @@ -364,9 +364,6 @@ def run_iptest(): if '--with-xunit' in sys.argv and not hasattr(Xunit, 'orig_addError'): monkeypatch_xunit() - warnings.filterwarnings('ignore', - 'This will be removed soon. Use IPython.testing.util instead') - arg1 = sys.argv[1] if arg1 in test_sections: section = test_sections[arg1] From a89c3c992bb3e9998e94ca91041f4e97234d6503 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 7 Jul 2016 15:02:02 -0700 Subject: [PATCH 0525/4859] Update release instruction closes #9695 --- docs/README.rst | 24 +++--- docs/source/coredev/release_process.rst | 108 +++++++++++++++--------- 2 files changed, 78 insertions(+), 54 deletions(-) diff --git a/docs/README.rst b/docs/README.rst index 4fb8fb78b10..8b6f90b8cab 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -1,40 +1,36 @@ IPython Documentation --------------------- -This directory contains the majority of the documentation for IPython. +This directory contains the majority of the documentation for IPython. Deploy docs ----------- -Run ``make gh-pages``, and follow instruction, that is to say: -cd into ``gh-pages``, check that everything is alright and push. - +Documentation is automatically deployed on ReadTheDocs on every push or merged +Pull requests. Requirements ------------ The following tools are needed to build the documentation: -sphinx jsdoc + - sphinx On Debian-based systems, you should be able to run:: - sudo apt-get install python-sphinx npm - sudo npm install -g jsdoc@"<=3.3.0" + sudo apt-get install python-sphinx The documentation gets built using ``make``, and comes in several flavors. -``make html`` - build the API (both Javascript and Python) and narrative -documentation web pages, this is the the default ``make`` target, so -running just ``make`` is equivalent to ``make html``. +``make html`` - build the API and narrative documentation web pages, this is +the default ``make`` target, so running just ``make`` is equivalent to ``make +html``. -``make html_noapi`` - same as above, but without running the auto-generated -API docs. When you are working on the narrative documentation, the most time +``make html_noapi`` - same as above, but without running the auto-generated API +docs. When you are working on the narrative documentation, the most time consuming portion of the build process is the processing and rending of the API documentation. This build target skips that. -``make jsapi`` - build Javascript auto-generated API documents. - ``make pdf`` will compile a pdf from the documentation. You can run ``make help`` to see information on all possible make targets. diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index d7b07dc5497..c80c98a24dc 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -14,26 +14,33 @@ handy reminder and checklist for the release manager. ---------------------------- Set environment variables to document previous release tag, current -release milestone, current release version, and git tag:: - - PREV_RELEASE=4.0.0 - MILESTONE=4.1 - VERSION=4.1.0 - BRANCH=master +release milestone, current release version, and git tag. These variables may be used later to copy/paste as answers to the script questions instead of typing the appropriate command when the time comes. These variables are not used by the scripts directly; therefore, there is no need to -`export` the variables. +`export` the variables. Use the following in bash: + + PREV_RELEASE=4.2.1 + MILESTONE=5.0 + VERSION=5.0.0 + BRANCH=master + 2. Create GitHub stats and finish release note ---------------------------------------------- .. note:: - Before generating the GitHub stats, verify that all closed issues and - pull requests have `appropriate milestones `_. - `This search `_ + This step is optional if making a Beta or RC release. + +.. note:: + + Before generating the GitHub stats, verify that all closed issues and pull + requests have `appropriate milestones + `_. + `This search + `_ should return no results before creating the GitHub stats. If a major release: @@ -42,20 +49,22 @@ If a major release: python tools/update_whatsnew.py - - update `docs/source/whatsnew/development.rst`, to ensure it covers + - update ``docs/source/whatsnew/development.rst``, to ensure it covers the major release features - - move the contents of `development.rst` to `versionX.rst` where `X` is + + - move the contents of ``development.rst`` to ``versionX.rst`` where `X` is the numerical release version + - generate summary of GitHub contributions, which can be done with:: python tools/github_stats.py --milestone $MILESTONE > stats.rst - which may need some manual cleanup of `stats.rst`. Add the cleaned - `stats.rst` results to `docs/source/whatsnew/github-stats-X.rst` where - `X` is the numerical release version. If creating a major release, make - a new `github-stats-X.rst` file; if creating a minor release, the - content from `stats.rst` may simply be added to the top of an existing - `github-stats-X.rst` file. + which may need some manual cleanup of ``stats.rst``. Add the cleaned + ``stats.rst`` results to ``docs/source/whatsnew/github-stats-X.rst`` + where `X` is the numerical release version. If creating a major release, + make a new ``github-stats-X.rst`` file; if creating a minor release, the + content from ``stats.rst`` may simply be added to the top of an existing + ``github-stats-X.rst`` file. To find duplicates and update `.mailmap`, use:: @@ -79,29 +88,35 @@ of any file that could be problematic. 4. Update the release version number ------------------------------------ -Edit `IPython/core/release.py` to have the current version. +Edit ``IPython/core/release.py`` to have the current version. in particular, update version number and ``_version_extra`` content in ``IPython/core/release.py``. -Make sure the version number matches pep440, in particular, `rc` and `beta` are -not separated by `.` or the `sdist` and `bdist` will appear as different -releases. For example, a valid version number for a release candidate (rc) -release is: ``1.3rc1``. Notice that there is no separator between the '3' and -the 'r'. Check the environment variable `$VERSION` as well. +Step 5 will validate your changes automatically, but you might still want to +make sure the version number matches pep440. +In particular, ``rc`` and ``beta`` are not separated by ``.`` or the ``sdist`` +and ``bdist`` will appear as different releases. For example, a valid version +number for a release candidate (rc) release is: ``1.3rc1``. Notice that there +is no separator between the '3' and the 'r'. Check the environment variable +``$VERSION`` as well. -Comment remove the `development` entry in `whatsnew/index.rst`. TODO, figure -out how to make that automatic. +You will likely just have to modify/comment/uncomment one of the lines setting +``_version_extra`` + + +Comment remove the ``development`` entry in ``whatsnew/index.rst``. TODO, figure +out how to make that automatic. 5. Run the `tools/build_release` script --------------------------------------- -Running `tools/build_release` does all the file checking and building that +Running ``tools/build_release`` does all the file checking and building that the real release script will do. This makes test installations, checks that the build procedure runs OK, and tests other steps in the release process. -The `build_release` script will in particular verify that the version number +The ``build_release`` script will in particular verify that the version number match PEP 440, in order to avoid surprise at the time of build upload. We encourage creating a test build of the docs as well. @@ -119,8 +134,8 @@ Create and push the tag:: git tag -am "release $VERSION" "$VERSION" git push origin --tags -Update release.py back to `x.y-dev` or `x.y-maint`, and re-add the -`development` entry in `docs/source/whatsnew/index.rst` and push:: +Update release.py back to ``x.y-dev`` or ``x.y-maint``, and re-add the +``development`` entry in ``docs/source/whatsnew/index.rst`` and push:: git commit -am "back to development" git push origin $BRANCH @@ -132,30 +147,39 @@ Get a fresh clone of the tag for building the release:: cd /tmp git clone --depth 1 https://github.com/ipython/ipython.git -b "$VERSION" + cd ipython + +.. note:: + + You can aslo cleanup the current working repository with ``git clean -xfdi`` 8. Run the release script ------------------------- -Run the `release` script, this step requires having a current wheel, Python >=3.4 and Python 2.7.:: +Run the ``release`` script, this step requires having a current wheel, Python +>=3.4 and Python 2.7.:: - cd tools && ./release + ./tools/release -This makes the tarballs, zipfiles, and wheels, and put them under the `dist/` +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. +them to PyPI. -Use the following to actually upload the result of the build: +Use the following to actually upload the result of the build:: - ./release upload + ./tools/release upload -It should posts them to ``archive.ipython.org`` and registers the release -with PyPI if you have the various authorisations. +It should posts them to ``archive.ipython.org``. -You might need to use `twine `_ (`twine upload -dist/*`) manually to actually upload on PyPI. Unlike setuptools, twine is able +You will need to use `twine `_ (``twine upload +dist/*``) manually to actually upload on PyPI. Unlike setuptools, twine is able to upload packages over SSL. +PyPI/Warehouse will automatically hide previous releases. If you are uploading +a non-stable version, make sure to log-in to PyPI and un-hide previous version. + + 9. Draft a short release announcement ------------------------------------- @@ -167,6 +191,10 @@ The announcement should include: Post the announcement to the mailing list and or blog, and link from Twitter. +.. note:: + + If you are doing a RC or Beta, you can likely skip the next steps. + 10. Update milestones on GitHub ------------------------------- From 47b7800862ca974c93de7bcd22e873b4ff3c56f7 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 7 Jul 2016 16:00:06 -0700 Subject: [PATCH 0526/4859] double backticks. --- docs/source/coredev/release_process.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index c80c98a24dc..c0056c7fc3f 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -6,7 +6,7 @@ IPython release process This document contains the process that is used to create an IPython release. -Conveniently, the `release` script in the `tools` directory of the `IPython` +Conveniently, the ``release`` script in the ``tools`` directory of the ``IPython`` repository automates most of the release process. This document serves as a handy reminder and checklist for the release manager. @@ -19,7 +19,7 @@ release milestone, current release version, and git tag. These variables may be used later to copy/paste as answers to the script questions instead of typing the appropriate command when the time comes. These variables are not used by the scripts directly; therefore, there is no need to -`export` the variables. Use the following in bash: +``export`` the variables. Use the following in bash: PREV_RELEASE=4.2.1 MILESTONE=5.0 @@ -52,7 +52,7 @@ If a major release: - update ``docs/source/whatsnew/development.rst``, to ensure it covers the major release features - - move the contents of ``development.rst`` to ``versionX.rst`` where `X` is + - move the contents of ``development.rst`` to ``versionX.rst`` where ``X`` is the numerical release version - generate summary of GitHub contributions, which can be done with:: @@ -61,7 +61,7 @@ If a major release: which may need some manual cleanup of ``stats.rst``. Add the cleaned ``stats.rst`` results to ``docs/source/whatsnew/github-stats-X.rst`` - where `X` is the numerical release version. If creating a major release, + where ``X`` is the numerical release version. If creating a major release, make a new ``github-stats-X.rst`` file; if creating a minor release, the content from ``stats.rst`` may simply be added to the top of an existing ``github-stats-X.rst`` file. From f03f4a93eb64cdd09f33588f038c6cb4e5a88dbc Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 17:44:01 -0700 Subject: [PATCH 0527/4859] Tag windows-only function so it doesn't get picked up on *nix doc builds. --- IPython/terminal/shortcuts.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py index 2c8cfec6a5c..9c48fe4729a 100644 --- a/IPython/terminal/shortcuts.py +++ b/IPython/terminal/shortcuts.py @@ -8,6 +8,8 @@ from prompt_toolkit.keys import Keys from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline +from IPython.utils.decorators import undoc + @Condition def cursor_in_leading_ws(cli): before = cli.application.buffer.document.current_line_before_cursor @@ -151,7 +153,7 @@ def indent_buffer(event): win32_clipboard_get, tkinter_clipboard_get) - + @undoc def win_paste(event): try: text = win32_clipboard_get() From a5d3016a462442f7363b33c285464b1ffd6e98ea Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 17:44:20 -0700 Subject: [PATCH 0528/4859] Fix code block that was missing `::` in release instructions. --- 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 c0056c7fc3f..69a2052af5c 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -19,7 +19,7 @@ release milestone, current release version, and git tag. These variables may be used later to copy/paste as answers to the script questions instead of typing the appropriate command when the time comes. These variables are not used by the scripts directly; therefore, there is no need to -``export`` the variables. Use the following in bash: +``export`` the variables. Use the following in bash:: PREV_RELEASE=4.2.1 MILESTONE=5.0 From 9264e266b4067b393acee75c17439af6025e6e8b Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 18:37:07 -0700 Subject: [PATCH 0529/4859] Add release date --- docs/source/whatsnew/version5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 7df222448ce..921ba55ad66 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -5,7 +5,7 @@ IPython 5.0 =========== -Released July, 2016 +Released July 7, 2016 New terminal interface ---------------------- From 83f65acb3ea14a6a0e67b8e7e83a11403fbc1259 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 18:38:26 -0700 Subject: [PATCH 0530/4859] Update output streams so we can redirect stdout with only stats to a file. Previously, input prompts (like username/pwd) were going to stdout, effectively breaking the tool if used as directed in the instructions. --- tools/gh_api.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tools/gh_api.py b/tools/gh_api.py index de3fbf3646c..cac949c011c 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -49,10 +49,11 @@ def get_auth_token(): return token print("Please enter your github username and password. These are not " - "stored, only used to get an oAuth token. You can revoke this at " - "any time on Github.") - user = input("Username: ") - pw = getpass.getpass("Password: ") + "stored, only used to get an oAuth token. You can revoke this at " + "any time on Github.\n" + "Username: ", file=sys.stderr, end='') + user = input('') + pw = getpass.getpass("Password: ", stream=sys.stderr) auth_request = { "scopes": [ @@ -64,9 +65,10 @@ def get_auth_token(): } response = requests.post('https://api.github.com/authorizations', auth=(user, pw), data=json.dumps(auth_request)) - if response.status_code == 401 and response.headers.get('X-GitHub-OTP') == 'required; sms': - print("Your login API resquest a SMS one time password") - sms_pw = getpass.getpass("SMS password: ") + if response.status_code == 401 and \ + response.headers.get('X-GitHub-OTP') == 'required; sms': + print("Your login API resquest a SMS one time password", file=sys.stderr) + sms_pw = getpass.getpass("SMS password: ", stream=sys.stderr) response = requests.post('https://api.github.com/authorizations', auth=(user, pw), data=json.dumps(auth_request), From dbceae905dd3c3d1aaf84435f906a4c1f8681d13 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 18:56:11 -0700 Subject: [PATCH 0531/4859] Update release instructions for stats inclusion in whatsnew section. --- docs/source/coredev/release_process.rst | 19 +++++++++++-------- docs/source/whatsnew/index.rst | 2 +- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index 69a2052af5c..ee5db5d6c83 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -19,7 +19,9 @@ release milestone, current release version, and git tag. These variables may be used later to copy/paste as answers to the script questions instead of typing the appropriate command when the time comes. These variables are not used by the scripts directly; therefore, there is no need to -``export`` the variables. Use the following in bash:: +``export`` them. The format for bash is as follows, but note that these values +are just an example valid only for the 5.0 release; you'll need to update them +for the release you are actually making:: PREV_RELEASE=4.2.1 MILESTONE=5.0 @@ -61,10 +63,14 @@ If a major release: which may need some manual cleanup of ``stats.rst``. Add the cleaned ``stats.rst`` results to ``docs/source/whatsnew/github-stats-X.rst`` - where ``X`` is the numerical release version. If creating a major release, - make a new ``github-stats-X.rst`` file; if creating a minor release, the - content from ``stats.rst`` may simply be added to the top of an existing - ``github-stats-X.rst`` file. + where ``X`` is the numerical release version (don't forget to add it to + the git repo as well). If creating a major release, make a new + ``github-stats-X.rst`` file; if creating a minor release, the content + from ``stats.rst`` may simply be added to the top of an existing + ``github-stats-X.rst`` file. Finally, edit + ``docs/source/whatsnew/index.rst`` to list the new ``github-stats-X`` + file you just created and remove temporarily the first entry called + ``development`` (you'll need to add it back after release). To find duplicates and update `.mailmap`, use:: @@ -106,9 +112,6 @@ You will likely just have to modify/comment/uncomment one of the lines setting ``_version_extra`` -Comment remove the ``development`` entry in ``whatsnew/index.rst``. TODO, figure -out how to make that automatic. - 5. Run the `tools/build_release` script --------------------------------------- diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index 2ce01e81b8a..7812afb309e 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -20,8 +20,8 @@ development work they do here in a user friendly format. .. toctree:: :maxdepth: 1 - development version5 + github-stats-5 version4 github-stats-4 version3 From 53eeda9e6d6be7e874cfbc7535af2b3b5a362f1f Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 19:01:29 -0700 Subject: [PATCH 0532/4859] Add stats info for the 5.0 release. --- docs/source/whatsnew/github-stats-5.rst | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/source/whatsnew/github-stats-5.rst diff --git a/docs/source/whatsnew/github-stats-5.rst b/docs/source/whatsnew/github-stats-5.rst new file mode 100644 index 00000000000..835cf75b733 --- /dev/null +++ b/docs/source/whatsnew/github-stats-5.rst @@ -0,0 +1,37 @@ + +GitHub stats for 2016/07/05 - 2016/07/07 (tag: 5.0.0rc1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 95 issues and merged 191 pull requests. +The full list can be seen `on GitHub `__ + +The following 27 authors contributed 229 commits. + +* Adam Greenhall +* Adrian +* Antony Lee +* Benjamin Ragan-Kelley +* Carlos Cordoba +* Carol Willing +* Chris +* Craig Citro +* Dmitry Zotikov +* Fernando Perez +* Gil Forsyth +* Jason Grout +* Jonathan Frederic +* Jonathan Slenders +* Justin Zymbaluk +* Kelly Liu +* klonuo +* Matthias Bussonnier +* nvdv +* Pavol Juhas +* Pierre Gerold +* sukisuki +* Sylvain Corlay +* Thomas A Caswell +* Thomas Kluyver +* Trevor Bekolay +* Yuri Numerov From 1ba246d740cd242e377d722630a909d85433c313 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 19:41:15 -0700 Subject: [PATCH 0533/4859] Update final release number (5.0.0) and fix stats header. --- IPython/core/release.py | 4 ++-- docs/source/whatsnew/github-stats-5.rst | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index e98d10a7ff7..a02648c0c6d 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -22,9 +22,9 @@ _version_major = 5 _version_minor = 0 _version_patch = 0 -_version_extra = '.dev' +#_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 = '' diff --git a/docs/source/whatsnew/github-stats-5.rst b/docs/source/whatsnew/github-stats-5.rst index 835cf75b733..217bac540f6 100644 --- a/docs/source/whatsnew/github-stats-5.rst +++ b/docs/source/whatsnew/github-stats-5.rst @@ -1,5 +1,13 @@ +.. _issues_list_5: -GitHub stats for 2016/07/05 - 2016/07/07 (tag: 5.0.0rc1) +Issues closed in the 5.x development cycle +========================================== + + +Issues closed in 5.0 +-------------------- + +GitHub stats for 2016/07/05 - 2016/07/07 (tag: 5.0.0) These lists are automatically generated, and may be incomplete or contain duplicates. From 985d00cb76664cc72922fce0a3c9b1bd9dbd2e16 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 20:14:49 -0700 Subject: [PATCH 0534/4859] Open 5.1.0 development line. --- IPython/core/release.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index a02648c0c6d..9df73c235c6 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 = 0 +_version_minor = 1 _version_patch = 0 -#_version_extra = '.dev' +_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 b7f513057cf297d191fa4b42908ec4c82d671955 Mon Sep 17 00:00:00 2001 From: Fernando Perez Date: Thu, 7 Jul 2016 20:18:35 -0700 Subject: [PATCH 0535/4859] Add development doc back to whatsnew toctree --- docs/source/whatsnew/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index 7812afb309e..9580e4ce6c8 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -20,6 +20,7 @@ development work they do here in a user friendly format. .. toctree:: :maxdepth: 1 + development version5 github-stats-5 version4 From 367c6fe312b265b792ba2b4e6cde63beb6caa845 Mon Sep 17 00:00:00 2001 From: Gavin Cooper Date: Mon, 11 Jul 2016 14:13:15 +1000 Subject: [PATCH 0536/4859] Fix broken links on install/index.rst Currently the links in the section summary on the index.rst/index.html file are broken. Can be reproduced by going to http://ipython.readthedocs.io/en/stable/install/index.html and clicking on *installing IPython itself*, or *kernels for Jupyter* links. Specific changes ---------------- * Added a reference label to the `install.rst` file * Modified links from external link format to Sphinx arbitrary location cross-referencing format in the `index.rst` file Testing ------- Changes have been tested with a local sphinx build through the supplied makefile and specific links touched are fixed. Tested a few possibly overlapping links (Jupyter:install for instance) and they seem to be unaffected by the change. --- docs/source/install/index.rst | 4 ++-- docs/source/install/install.rst | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/install/index.rst b/docs/source/install/index.rst index 78c85360cd8..3793fae4e83 100644 --- a/docs/source/install/index.rst +++ b/docs/source/install/index.rst @@ -14,8 +14,8 @@ Installation -This sections will guide you through `installing IPython itself `_, and -installing `kernels for Jupyter `_ if you wish to work with +This sections will guide you through :ref:`installing IPython itself `, and +installing :ref:`kernels for Jupyter ` if you wish to work with multiple version of Python, or multiple environments. diff --git a/docs/source/install/install.rst b/docs/source/install/install.rst index 32ab774af97..eb6db4507ab 100644 --- a/docs/source/install/install.rst +++ b/docs/source/install/install.rst @@ -1,3 +1,5 @@ +.. _install: + Installing IPython ================== From 134c38b3fe6330d51118a417ea392c2dba0b3714 Mon Sep 17 00:00:00 2001 From: Pavol Juhas Date: Mon, 11 Jul 2016 19:08:21 -0400 Subject: [PATCH 0537/4859] Inform in the docs about removal of define_magic. --- docs/source/config/custommagics.rst | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/docs/source/config/custommagics.rst b/docs/source/config/custommagics.rst index c86ab6315ad..c5136654069 100644 --- a/docs/source/config/custommagics.rst +++ b/docs/source/config/custommagics.rst @@ -113,21 +113,13 @@ instantiate the class yourself before registration: ip = get_ipython() magics = StatefulMagics(ip, some_data) ip.register_magics(magics) - - -In earlier versions, IPython had an API for the creation of line magics (cell -magics did not exist at the time) that required you to create functions with a -method-looking signature and to manually pass both the function and the name. -While this API is no longer recommended, it remains indefinitely supported for -backwards compatibility purposes. With the old API, you'd create a magic as -follows: -.. sourcecode:: python - def func(self, line): - print("Line magic called with line:", line) - print("IPython object:", self.shell) +.. note:: - ip = get_ipython() - # Declare this function as the magic %mycommand - ip.define_magic('mycommand', func) + In early IPython versions 0.12 and before the line magics were + created using a :func:`define_magic` API function. This API has been + replaced with the above in IPython 0.13 and then completely removed + in IPython 5. Maintainers of IPython extensions that still use the + :func:`define_magic` function are advised to adjust their code + for the current API. From 5eefa70fb2b9bb35e250a06744d4e47cbc0bff43 Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Mon, 11 Jul 2016 16:20:13 -0700 Subject: [PATCH 0538/4859] Add true_color option for prompt_toolkit --- IPython/terminal/interactiveshell.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index c31ce10fcd6..b644b555d52 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -14,7 +14,7 @@ from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode from prompt_toolkit.filters import (HasFocus, Condition, IsDone) from prompt_toolkit.history import InMemoryHistory -from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout +from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output from prompt_toolkit.interface import CommandLineInterface from prompt_toolkit.key_binding.manager import KeyBindingManager from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor @@ -142,6 +142,13 @@ def refresh_style(self): help="Override highlighting format for specific tokens" ).tag(config=True) + true_color = Bool(False, + help=("Use 24bit colors instead of 256 colors in prompt highlighting. " + "If your terminal supports true color, the following command " + "should print 'TRUECOLOR' in orange: " + "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"") + ).tag(config=True) + editor = Unicode(get_default_editor(), help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." ).tag(config=True) @@ -235,7 +242,9 @@ def prompt(): **self._layout_options() ) self._eventloop = create_eventloop(self.inputhook) - self.pt_cli = CommandLineInterface(self._pt_app, eventloop=self._eventloop) + self.pt_cli = CommandLineInterface( + self._pt_app, eventloop=self._eventloop, + output=create_output(true_color=self.true_color)) def _make_style_from_name(self, name): """ From 7304bca3a12c141bba350addd435ec9d3d0e607e Mon Sep 17 00:00:00 2001 From: Jacob Niehus Date: Mon, 11 Jul 2016 21:16:35 -0700 Subject: [PATCH 0539/4859] Add whatsnew for true_color option --- docs/source/whatsnew/pr/truecolor-feature.rst | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/source/whatsnew/pr/truecolor-feature.rst diff --git a/docs/source/whatsnew/pr/truecolor-feature.rst b/docs/source/whatsnew/pr/truecolor-feature.rst new file mode 100644 index 00000000000..659205694c0 --- /dev/null +++ b/docs/source/whatsnew/pr/truecolor-feature.rst @@ -0,0 +1,9 @@ +prompt_toolkit uses pygments styles for syntax highlighting. By default, the +colors specified in the style are approximated using a standard 256-color +palette. prompt_toolkit also supports 24bit, a.k.a. "true", a.k.a. 16-million +color escape sequences which enable compatible terminals to display the exact +colors specified instead of an approximation. This true_color option exposes +that capability in prompt_toolkit to the IPython shell. + +Here is a good source for the current state of true color support in various +terminal emulators and software projects: https://gist.github.com/XVilka/8346728 From 462ff49623222f1f87c81c8db86d5d9e1771cdda Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 12 Jul 2016 12:14:17 +0100 Subject: [PATCH 0540/4859] Remove display_completions_in_columns Closes gh-9728 --- IPython/terminal/interactiveshell.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index c31ce10fcd6..ecdd710f88f 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -166,16 +166,6 @@ def _displayhook_class_default(self): help="Automatically set the terminal title" ).tag(config=True) - # Leaving that for beta/rc tester, shoudl remove for 5.0.0 final. - display_completions_in_columns = Bool(None, - help="DEPRECATED", allow_none=True - ).tag(config=True) - - @observe('display_completions_in_columns') - def _display_completions_in_columns_changed(self, new): - raise DeprecationWarning("The `display_completions_in_columns` Boolean has been replaced by the enum `display_completions`" - "with the following acceptable value: 'column', 'multicolumn','readlinelike'. ") - display_completions = Enum(('column', 'multicolumn','readlinelike'), default_value='multicolumn').tag(config=True) highlight_matching_brackets = Bool(True, From ec2d023d00896bbf498bfc7201b12b1c0572953e Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Sat, 9 Jul 2016 16:35:11 -0700 Subject: [PATCH 0541/4859] Simplify debugger classes. Directly get the color scheme from the interactive shell (which is created if not already present, anyways). The goal is ultimately to allow the IPython debugger to be a drop-in replacement of the stdlib pdb with the same signature (in particular, this would obviate the need for plugins such as nose-ipdb and pytest-ipdb; nose and pytest could instead let their `--pdb` command line arg take an argument specifying the Pdb (sub)class to use, e.g. `py.test --pdb=IPython.core.debugger.Pdb`). Also deprecate the `Tracer` class (and related utilities), which can be fairly trivially replaced by `IPython.core.debugger.Pdb().set_trace()` (we can let `Pdb` catch `BdbQuit` itself). --- IPython/core/debugger.py | 27 +++++++++++++++++++++++++-- IPython/core/magics/execution.py | 2 +- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index e97eb7ab8a2..efc614c8fd1 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -30,6 +30,7 @@ import functools import inspect import sys +import warnings from IPython import get_ipython from IPython.utils import PyColorize, ulinecache @@ -62,6 +63,8 @@ def BdbQuit_excepthook(et, ev, tb, excepthook=None): All other exceptions are processed using the `excepthook` parameter. """ + warnings.warn("`BdbQuit_excepthook` is deprecated since version 5.1", + DeprecationWarning) if et==bdb.BdbQuit: print('Exiting Debugger.') elif excepthook is not None: @@ -70,7 +73,11 @@ def BdbQuit_excepthook(et, ev, tb, excepthook=None): # Backwards compatibility. Raise deprecation warning? BdbQuit_excepthook.excepthook_ori(et,ev,tb) + def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None): + warnings.warn( + "`BdbQuit_IPython_excepthook` is deprecated since version 5.1", + DeprecationWarning) print('Exiting Debugger.') @@ -114,6 +121,9 @@ def __init__(self, colors=None): step through code, set breakpoints, etc. See the pdb documentation from the Python standard library for usage details. """ + warnings.warn("`Tracer` is deprecated since version 5.1, directly use " + "`IPython.core.debugger.Pdb.set_trace()`", + DeprecationWarning) ip = get_ipython() if ip is None: @@ -189,12 +199,12 @@ def _file_lines(fname): class Pdb(OldPdb, object): """Modified Pdb class, does not load readline.""" - def __init__(self,color_scheme='NoColor',completekey=None, + def __init__(self, color_scheme=None, completekey=None, stdin=None, stdout=None, context=5): # Parent constructor: try: - self.context=int(context) + self.context = int(context) if self.context <= 0: raise ValueError("Context must be a positive integer") except (TypeError, ValueError): @@ -211,6 +221,13 @@ def __init__(self,color_scheme='NoColor',completekey=None, TerminalInteractiveShell self.shell = TerminalInteractiveShell.instance() + if color_scheme is not None: + warnings.warn( + "The `color_scheme` argument is deprecated since version 5.1", + DeprecationWarning) + else: + color_scheme = self.shell.colors + self.aliases = {} # Create color table: we copy the default one from the traceback @@ -250,6 +267,12 @@ def set_colors(self, scheme): """Shorthand access to the color table scheme selector method.""" self.color_scheme_table.set_active_scheme(scheme) + def trace_dispatch(self, frame, event, arg): + try: + return super(Pdb, self).trace_dispatch(frame, event, arg) + except bdb.BdbQuit: + pass + def interaction(self, frame, traceback): try: OldPdb.interaction(self, frame, traceback) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index 6c3ad73d7e5..a2bc74e084c 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -801,7 +801,7 @@ def _run_with_debugger(self, code, code_ns, filename=None, If the break point given by `bp_line` is not valid. """ - deb = debugger.Pdb(self.shell.colors) + deb = debugger.Pdb() # reset Breakpoint state, which is moronically kept # in a class bdb.Breakpoint.next = 1 From 25dcaa5a3e1209cc93ae8673243020795e1bdbda Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 13 Jul 2016 15:58:32 +0100 Subject: [PATCH 0542/4859] Docs on adding keyboard shortcuts to terminal IPython Closes gh-9739 --- docs/source/config/details.rst | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index d89cc3aab87..1dadeed7113 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -159,3 +159,37 @@ With (X)EMacs >= 24, You can enable IPython in python-mode with: .. _`(X)Emacs`: http://www.gnu.org/software/emacs/ .. _TextMate: http://macromates.com/ .. _vim: http://www.vim.org/ + +.. _custom_keyboard_shortcuts + +Keyboard Shortcuts +================== + +.. versionchanged:: 5.0 + +You can customise keyboard shortcuts for terminal IPython. Put code like this in +a :ref:`startup file `:: + + from IPython import get_ipython + from prompt_toolkit.enums import DEFAULT_BUFFER + from prompt_toolkit.keys import Keys + from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode + + ip = get_ipython() + insert_mode = ViInsertMode() | EmacsInsertMode() + + def insert_unexpected(event): + buf = event.current_buffer + buf.insert_text('The Spanish Inquisition') + + # Register the shortcut if IPython is using prompt_toolkit + if getattr(ip, 'pt_cli'): + registry = ip.pt_cli.application.key_bindings_registry + registry.add_binding(Keys.ControlN, + filter=(HasFocus(DEFAULT_BUFFER) + & ~HasSelection() + & insert_mode))(insert_unexpected) + +For more information on filters and what you can do with the ``event`` object, +`see the prompt_toolkit docs +`__. From c206dc15c05e854850c6b185436446963fb1b6c8 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 13 Jul 2016 16:22:30 +0100 Subject: [PATCH 0543/4859] Unify docs on custom prompts We had unwittingly documented this in two different places; this condenses them into one, leaving a reference from the other location. --- docs/source/config/details.rst | 26 +++++++++++++++++++ docs/source/interactive/shell.rst | 43 +------------------------------ 2 files changed, 27 insertions(+), 42 deletions(-) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 1dadeed7113..05ef0b55d6f 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -46,6 +46,32 @@ which defines the defaults. The required interface is like this: *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance. This is mainly for compatibility with the API prompt_toolkit expects. +Here is an example Prompt class that will show the current working directory +in the input prompt: + +.. code-block:: python + + from IPython.terminal.prompts import Prompts, Token + import os + + class MyPrompt(Prompts): + def in_prompt_tokens(self, cli=None): + return [(Token, os.getcwd()), + (Token.Prompt, ' >>>')] + +To set the new prompt, assign it to the ``prompts`` attribute of the IPython +shell: + +.. code-block:: python + + In [2]: ip = get_ipython() + ...: ip.prompts = MyPrompt(ip) + + /home/bob >>> # it works + +See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an +extensions to customise prompts. + Inside IPython or in a startup script, you can use a custom prompts class by setting ``get_ipython().prompts`` to an *instance* of the class. In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to diff --git a/docs/source/interactive/shell.rst b/docs/source/interactive/shell.rst index be3999d8ba4..420f5a53ba1 100644 --- a/docs/source/interactive/shell.rst +++ b/docs/source/interactive/shell.rst @@ -63,49 +63,8 @@ switching to any of them. Type ``cd?`` for more details. Prompt customization ==================== -Starting at IPython 5.0 the prompt customisation is done by subclassing :class:`IPython.terminal.prompts.Prompt`. +See :ref:`custom_prompts`. -The custom ``Prompt`` receive the current IPython shell instance as first -argument, which by default is stored as the ``shell`` attribute of the object. -The class can implement optional methods for each of the available prompt types: - - - ``in_prompt_tokens(self, cli=None)``, input prompt , default to ``In [1]`` - - ``continuation_prompt_tokens(self, cli=None, width=None)``, continuation prompt for multi lines (default `...:`) - - ``rewrite_prompt_tokens(self)`` - - ``out_prompt_tokens(self)`` - -Each of these methods should return a list of `(TokenType, Token)` pairs. See documentation of `prompt_toolkit` and/or `Pygments`. - -Here is an example of Prompt class that will insert the current working directory in front of a prompt: - - -.. code-block:: python - - from IPython.terminal.prompts import Prompts, Token - import os - - class MyPrompt(Prompts): - - def in_prompt_tokens(self, cli=None): - return [(Token, os.getcwd()), - (Token.Prompt, ' >>>')] - -To set the new prompt, assign it to the `prompts` attribute of the IPython shell: - -.. code-block:: python - - In[2]: ip = get_ipython() - ...: ip.prompts = MyPrompt(ip) - - ~/ >>> # it works - - -See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an -extensions that customise prompts. - - -Read more about the :ref:`configuration system ` for details -on how to find ``ipython_config.py``. .. _string_lists: From 1193160ed46bf0c9d103b2af1f1dca122517b157 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 13 Jul 2016 21:41:31 +0100 Subject: [PATCH 0544/4859] Fix keyword argument to warn() Closes gh-9755 --- IPython/core/interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 1cb0bc306fc..5c30a202efc 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2874,7 +2874,7 @@ def run_code(self, code_obj, result=None): if result is not None: result.error_in_exec = e self.showtraceback(exception_only=True) - warn("To exit: use 'exit', 'quit', or Ctrl-D.", level=1) + warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1) except self.custom_exceptions: etype, value, tb = sys.exc_info() if result is not None: From 7cda39691852c19d516f30c4e59e161be05a7b33 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 15 Jul 2016 14:10:11 +0100 Subject: [PATCH 0545/4859] Restore NoOpContext location for ipykernel to import See ipython/ipykernel#157 --- IPython/core/interactiveshell.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 1cb0bc306fc..80635cd1867 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -82,6 +82,10 @@ from logging import error import IPython.core.hooks +# NoOpContext is deprecated, but ipykernel imports it from here. +# See https://github.com/ipython/ipykernel/issues/157 +from IPython.utils.contexts import NoOpContext + try: import docrepr.sphinxify as sphx From cc9405b07a60ce88d4aaba951b7ab21d21ee7cd9 Mon Sep 17 00:00:00 2001 From: dongweiming Date: Sat, 16 Jul 2016 08:27:35 +0800 Subject: [PATCH 0546/4859] fix highlighting_style typo --- docs/source/config/details.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 1dadeed7113..8b268500b4e 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -67,7 +67,7 @@ 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.highlight_style`` determines prompt colours and syntax +``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``. @@ -76,7 +76,7 @@ You can see the Pygments styles available on your system by running:: import pygments list(pygments.styles.get_all_styles()) -Additionally, ``TerminalInteractiveShell.highlight_style_overrides`` can override +Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override specific styles in the highlighting. It should be a dictionary mapping Pygments token types to strings defining the style. See `Pygments' documentation `__ for the language used From 0d8a7856409870b743eb87c5ca401ff555cf79b7 Mon Sep 17 00:00:00 2001 From: Gil Forsyth Date: Sat, 16 Jul 2016 11:46:12 -0400 Subject: [PATCH 0547/4859] preserve margins when using Ctrl-O for newline This should address ipython/ipython#9588. Control-O will insert a new line, preserve the current cursor position and preserve the indentation level on the newline --- IPython/terminal/shortcuts.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py index 9c48fe4729a..e84fd7e2161 100644 --- a/IPython/terminal/shortcuts.py +++ b/IPython/terminal/shortcuts.py @@ -56,6 +56,10 @@ def register_ipython_shortcuts(registry, shell): & cursor_in_leading_ws ))(indent_buffer) + registry.add_binding(Keys.ControlO, + filter=(HasFocus(DEFAULT_BUFFER) + & insert_mode))(newline_with_copy_margin) + if shell.display_completions == 'readlinelike': registry.add_binding(Keys.ControlI, filter=(HasFocus(DEFAULT_BUFFER) @@ -144,6 +148,20 @@ def suspend_to_bg(event): def indent_buffer(event): event.current_buffer.insert_text(' ' * 4) +def newline_with_copy_margin(event): + """ + Preserve margin and cursor position when using + Control-O to insert a newline in EMACS mode + """ + b = event.current_buffer + cursor_start_pos = b.document.cursor_position_col + b.newline(copy_margin=True) + b.cursor_up(count=1) + cursor_end_pos = b.document.cursor_position_col + if cursor_start_pos != cursor_end_pos: + pos_diff = cursor_start_pos - cursor_end_pos + b.cursor_right(count=pos_diff) + From e2c6424486f4d3320a36401966ea3d3397d10677 Mon Sep 17 00:00:00 2001 From: Gil Forsyth Date: Sun, 17 Jul 2016 12:08:59 -0400 Subject: [PATCH 0548/4859] filter ControlO insertion on EmacsInsertMode --- IPython/terminal/shortcuts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py index e84fd7e2161..5c32b0843ca 100644 --- a/IPython/terminal/shortcuts.py +++ b/IPython/terminal/shortcuts.py @@ -58,7 +58,7 @@ def register_ipython_shortcuts(registry, shell): registry.add_binding(Keys.ControlO, filter=(HasFocus(DEFAULT_BUFFER) - & insert_mode))(newline_with_copy_margin) + & EmacsInsertMode()))(newline_with_copy_margin) if shell.display_completions == 'readlinelike': registry.add_binding(Keys.ControlI, From 594cb8deb77384576df8cb2b293a96d5ff7e49bd Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jul 2016 14:33:47 +0100 Subject: [PATCH 0549/4859] Be more lenient when bytes are sent to stdout/stderr on Py2+Windows Closes gh-9768 --- IPython/terminal/interactiveshell.py | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 5626a614cd7..462dc4617e4 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -320,14 +320,36 @@ def prompt_for_code(self): pre_run=self.pre_prompt, reset_current_buffer=True) return document.text + def enable_win_unicode_console(self): + import win_unicode_console + + if PY3: + win_unicode_console.enable() + else: + # https://github.com/ipython/ipython/issues/9768 + from win_unicode_console.streams import (TextStreamWrapper, + stdout_text_transcoded, stderr_text_transcoded) + + class LenientStrStreamWrapper(TextStreamWrapper): + def write(self, s): + if isinstance(s, bytes): + s = s.decode(self.encoding, 'replace') + + self.base.write(s) + + stdout_text_str = LenientStrStreamWrapper(stdout_text_transcoded) + stderr_text_str = LenientStrStreamWrapper(stderr_text_transcoded) + + win_unicode_console.enable(stdout=stdout_text_str, + stderr=stderr_text_str) + def init_io(self): if sys.platform not in {'win32', 'cli'}: return - import win_unicode_console - import colorama + self.enable_win_unicode_console() - win_unicode_console.enable() + import colorama colorama.init() # For some reason we make these wrappers around stdout/stderr. From be4e027b27000a1614b0dbc5aa5dd9ed2e41a1ea Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jul 2016 15:25:10 +0100 Subject: [PATCH 0550/4859] Dedent leading lines on %load -r Closes gh-9775 --- IPython/core/magics/code.py | 32 +++++++++++++++++++++++++++++++- IPython/core/tests/test_magic.py | 9 +++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/IPython/core/magics/code.py b/IPython/core/magics/code.py index a865d68db2e..4c1a40f197e 100644 --- a/IPython/core/magics/code.py +++ b/IPython/core/magics/code.py @@ -138,6 +138,36 @@ class A: pass''' return blocks, not_found +def strip_initial_indent(lines): + """For %load, strip indent from lines until finding an unindented line. + + https://github.com/ipython/ipython/issues/9775 + """ + indent_re = re.compile(r'\s+') + + it = iter(lines) + first_line = next(it) + indent_match = indent_re.match(first_line) + + if indent_match: + # First line was indented + indent = indent_match.group() + yield first_line[len(indent):] + + for line in it: + if line.startswith(indent): + yield line[len(indent):] + else: + # Less indented than the first line - stop dedenting + yield line + break + else: + yield first_line + + # Pass the remaining lines through without dedenting + for line in it: + yield line + class InteractivelyDefined(Exception): """Exception for interactively defined variable in magic_edit""" @@ -341,7 +371,7 @@ def load(self, arg_s): lines = contents.split('\n') slices = extract_code_ranges(ranges) contents = [lines[slice(*slc)] for slc in slices] - contents = '\n'.join(chain.from_iterable(contents)) + contents = '\n'.join(strip_initial_indent(chain.from_iterable(contents))) l = len(contents) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 17af507e9d1..4ac7744527b 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -1000,3 +1000,12 @@ def test_ls_magic(): j = json_formatter(lsmagic) nt.assert_equal(sorted(j), ['cell', 'line']) nt.assert_equal(w, []) # no warnings + +def test_strip_initial_indent(): + def sii(s): + lines = s.splitlines() + return '\n'.join(code.strip_initial_indent(lines)) + + nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2") + nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc") + nt.assert_equal(sii("a\n b\n"), "a\n b\n") From bb3df98fa66bab945f4dfce7e4b1abff44054b7c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 19 Jul 2016 18:16:34 +0100 Subject: [PATCH 0551/4859] Fix test for strip_initial_indent --- IPython/core/tests/test_magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/tests/test_magic.py b/IPython/core/tests/test_magic.py index 4ac7744527b..eb40331b71e 100644 --- a/IPython/core/tests/test_magic.py +++ b/IPython/core/tests/test_magic.py @@ -1008,4 +1008,4 @@ def sii(s): nt.assert_equal(sii(" a = 1\nb = 2"), "a = 1\nb = 2") nt.assert_equal(sii(" a\n b\nc"), "a\n b\nc") - nt.assert_equal(sii("a\n b\n"), "a\n b\n") + nt.assert_equal(sii("a\n b"), "a\n b") From c01f0ac4c8d8ddfeb10e6b875c62c4470c15fab3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Wed, 20 Jul 2016 15:22:13 -0700 Subject: [PATCH 0552/4859] Restore completion in debugger. Close #9759 --- IPython/core/magics/execution.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/IPython/core/magics/execution.py b/IPython/core/magics/execution.py index a2bc74e084c..159169d6eb9 100644 --- a/IPython/core/magics/execution.py +++ b/IPython/core/magics/execution.py @@ -28,7 +28,7 @@ except ImportError: profile = pstats = None -from IPython.core import debugger, oinspect +from IPython.core import oinspect from IPython.core import magic_arguments from IPython.core import page from IPython.core.error import UsageError @@ -801,7 +801,11 @@ def _run_with_debugger(self, code, code_ns, filename=None, If the break point given by `bp_line` is not valid. """ - deb = debugger.Pdb() + deb = self.shell.InteractiveTB.pdb + if not deb: + self.shell.InteractiveTB.pdb = self.shell.InteractiveTB.debugger_cls() + deb = self.shell.InteractiveTB.pdb + # reset Breakpoint state, which is moronically kept # in a class bdb.Breakpoint.next = 1 From 3a42b33124d6036dacee85867e484cb25d32a903 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 21 Jul 2016 13:36:33 +0100 Subject: [PATCH 0553/4859] Create a QApplication for inputhook if one doesn't already exist Closes gh-9784 --- IPython/terminal/pt_inputhooks/qt.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/pt_inputhooks/qt.py b/IPython/terminal/pt_inputhooks/qt.py index ebf3a94eaa0..34c9618f6e4 100644 --- a/IPython/terminal/pt_inputhooks/qt.py +++ b/IPython/terminal/pt_inputhooks/qt.py @@ -1,10 +1,15 @@ import sys from IPython.external.qt_for_kernel import QtCore, QtGui +# If we create a QApplication, keep a reference to it so that it doesn't get +# garbage collected. +_appref = None + def inputhook(context): + global _appref app = QtCore.QCoreApplication.instance() if not app: - return + _appref = app = QtGui.QApplication([" "]) event_loop = QtCore.QEventLoop(app) if sys.platform == 'win32': From 65bece91f129a67a1fce169b34092ee675ce8a4d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jul 2016 14:35:12 -0700 Subject: [PATCH 0554/4859] Link to the developer install instruction on readthedocs. Closes #9688 --- README.rst | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 6911d8c933e..f50965a4ae0 100644 --- a/README.rst +++ b/README.rst @@ -43,5 +43,9 @@ by typing at the terminal:: $ python -m IPython -Documentation and installation instructions for older version of IPython can be found on the -`IPython website `_ +Or see the `developement installation 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 `_ From a19a0905514ba656331355a1927106d12debed03 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jul 2016 14:40:20 -0700 Subject: [PATCH 0555/4859] Mark the wiki more-explicitely as being out of date. Closes #9689 --- docs/source/coredev/index.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/coredev/index.rst b/docs/source/coredev/index.rst index d4331a026da..571b3cd20cf 100644 --- a/docs/source/coredev/index.rst +++ b/docs/source/coredev/index.rst @@ -22,6 +22,8 @@ Old Documentation Out of date documentation is still available and have been kept for archival purposes. -Developers working on IPython should also consult the -`developer information `_ -on the IPython GitHub wiki. +.. note:: + + Developers documentation used to be on the IPython wiki, but are now out of + date. The wiki is though still available for historical reasons: `Old IPython + GitHub Wiki. `_ From 39437f0887ec982fdbfaad54c094f2c09b87b437 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 22 Jul 2016 15:19:56 -0700 Subject: [PATCH 0556/4859] Update release process instruction. According to what's in #9718, that should make things a bit more organized. Closes #9718 --- docs/source/coredev/release_process.rst | 28 ++++++++++-- tools/release | 59 +++++++++++++------------ 2 files changed, 54 insertions(+), 33 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index ee5db5d6c83..d32874915d5 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -8,7 +8,15 @@ This document contains the process that is used to create an IPython release. Conveniently, the ``release`` script in the ``tools`` directory of the ``IPython`` repository automates most of the release process. This document serves as a -handy reminder and checklist for the release manager. +handy reminder and checklist for the release manager. + +During the release process, you might need the extra following dependencies: + + - ``keyring`` to access your GitHub authentication tokens + - ``testpath`` to fake some file system operations + - ``graphviz`` to generate some graphs in the documentation + + 1. Set Environment variables ---------------------------- @@ -72,6 +80,9 @@ If a major release: file you just created and remove temporarily the first entry called ``development`` (you'll need to add it back after release). + Make sure that the stats file have a header or it won't be rendered in + the final documentation. + To find duplicates and update `.mailmap`, use:: git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f @@ -174,9 +185,11 @@ Use the following to actually upload the result of the build:: It should posts them to ``archive.ipython.org``. -You will need to use `twine `_ (``twine upload -dist/*``) manually to actually upload on PyPI. Unlike setuptools, twine is able -to upload packages over SSL. +You will need to use `twine `_ ) manually to +actually upload on PyPI. Unlike setuptools, twine is able to upload packages +over SSL. + + twine upload dist/* PyPI/Warehouse will automatically hide previous releases. If you are uploading @@ -216,6 +229,13 @@ The IPython website should document the new release: - update current version and download links - update links on the documentation page (especially if a major release) +12. Update readthedocs +---------------------- + +Make sure to update readthedocs and set the latest tag as stable, as well as +checked that previous release is still building under its own tag. + + 12. Celebrate! -------------- diff --git a/tools/release b/tools/release index 69e51231bc1..10b85956fb4 100755 --- a/tools/release +++ b/tools/release @@ -45,44 +45,45 @@ print() # Perform local backup, go to tools dir to run it. cd(tooldir) -sh('./make_tarball.py') -sh('mv ipython-*.tgz %s' % ipbackupdir) -# Build release files -sh('./build_release %s' % ipdir) +if 'upload' in sys.argv: + cd(distdir) + print( 'Uploading distribution files to GitHub...') -# Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted -cd(ipdir) + for fname in os.listdir('.'): + # TODO: update to GitHub releases API + continue + print('uploading %s to GitHub' % fname) + desc = "IPython %s source distribution" % version + post_download("ipython/ipython", fname, description=desc) -# Upload all files -sh(sdists) + # Make target dir if it doesn't exist + print('Uploading IPython to backup site.') + sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version)) + sh('scp * %s' % release_site) -buildwheels() + print( 'Uploading backup files...') + cd(ipbackupdir) + sh('scp `ls -1tr *tgz | tail -1` %s' % backup_site) -if 'upload' not in sys.argv: - print("`./release upload` to register and release") - sys.exit(0) + print('Done!') + print('Use `twine upload dist/*` to upload the files to PyPI') +else: + sh('./make_tarball.py') + sh('mv ipython-*.tgz %s' % ipbackupdir) + # Build release files + sh('./build_release %s' % ipdir) -print('Will not upload with setuptools as upload connection is insecure. Please use `twine upload dist/*` to upload the files to PyPI') + # Not Registering with PyPI, registering with setup.py is insecure as communication is not encrypted + cd(ipdir) -cd(distdir) -print( 'Uploading distribution files to GitHub...') + # Upload all files + sh(sdists) -for fname in os.listdir('.'): - # TODO: update to GitHub releases API - continue - print('uploading %s to GitHub' % fname) - desc = "IPython %s source distribution" % version - post_download("ipython/ipython", fname, description=desc) + buildwheels() + print("`./release upload` to upload source distribution on github and ipython archive") + sys.exit(0) -# Make target dir if it doesn't exist -print('Uploading IPython to backup site.') -sh('ssh %s "mkdir -p %s/release/%s" ' % (archive_user, archive_dir, version)) -sh('scp * %s' % release_site) -print( 'Uploading backup files...') -cd(ipbackupdir) -sh('scp `ls -1tr *tgz | tail -1` %s' % backup_site) -print('Done!') From 23f7b81b64c29888a3d6dd699456c149a730ef19 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Mon, 25 Jul 2016 12:17:15 +0100 Subject: [PATCH 0557/4859] Don't change terminal title for embedded IPython This seems like a sensible default when we're just part of someone else's program. Closes gh-9722 --- IPython/terminal/embed.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/IPython/terminal/embed.py b/IPython/terminal/embed.py index 1d167111495..892a6afb4bc 100644 --- a/IPython/terminal/embed.py +++ b/IPython/terminal/embed.py @@ -70,6 +70,11 @@ class InteractiveShellEmbed(TerminalInteractiveShell): display_banner = CBool(True) exit_msg = Unicode() + # When embedding, by default we don't change the terminal title + term_title = Bool(False, + help="Automatically set the terminal title" + ).tag(config=True) + _inactive_locations = set() @property From 5bf8cfe3ba27051219a9ef2e8e0baa4053c9c037 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jul 2016 08:30:13 -0700 Subject: [PATCH 0558/4859] Update release_process.rst --- docs/source/coredev/release_process.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/coredev/release_process.rst b/docs/source/coredev/release_process.rst index d32874915d5..feec4f8125a 100644 --- a/docs/source/coredev/release_process.rst +++ b/docs/source/coredev/release_process.rst @@ -13,9 +13,9 @@ handy reminder and checklist for the release manager. During the release process, you might need the extra following dependencies: - ``keyring`` to access your GitHub authentication tokens - - ``testpath`` to fake some file system operations - ``graphviz`` to generate some graphs in the documentation - + +Make sure you have all the required dependencies to run the tests as well. 1. Set Environment variables @@ -80,7 +80,7 @@ If a major release: file you just created and remove temporarily the first entry called ``development`` (you'll need to add it back after release). - Make sure that the stats file have a header or it won't be rendered in + Make sure that the stats file has a header or it won't be rendered in the final documentation. To find duplicates and update `.mailmap`, use:: @@ -233,10 +233,10 @@ The IPython website should document the new release: ---------------------- Make sure to update readthedocs and set the latest tag as stable, as well as -checked that previous release is still building under its own tag. +checking that previous release is still building under its own tag. -12. Celebrate! +13. Celebrate! -------------- Celebrate the release and please thank the contributors for their work. Great From a132e73220e1da44aec39c5c452b8b07f87cdd91 Mon Sep 17 00:00:00 2001 From: michaelpacer Date: Mon, 25 Jul 2016 13:30:36 -0700 Subject: [PATCH 0559/4859] added help line tointeractiveshell.py --- IPython/terminal/interactiveshell.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 5626a614cd7..50f3c524959 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -173,7 +173,12 @@ def _displayhook_class_default(self): help="Automatically set the terminal title" ).tag(config=True) - display_completions = Enum(('column', 'multicolumn','readlinelike'), default_value='multicolumn').tag(config=True) + 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." + ), + default_value='multicolumn').tag(config=True) highlight_matching_brackets = Bool(True, help="Highlight matching brackets .", From 7b12b9f60276a186950d0dfb61667f1a0516448c Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jul 2016 10:37:29 -0700 Subject: [PATCH 0560/4859] Don't use __qualname__ on Python 2, as it does not exists. Closes #9756 --- IPython/core/interactiveshell.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 51ffb10389d..b30b480f03c 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -187,8 +187,12 @@ def raise_error(self): raise self.error_in_exec def __repr__(self): + if sys.version_info > (3,): + name = self.__class__.__qualname__ + else: + name = self.__class__.__name__ return '<%s object at %x, execution_count=%s error_before_exec=%s error_in_exec=%s result=%s>' %\ - (self.__class__.__qualname__, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.result)) + (name, id(self), self.execution_count, self.error_before_exec, self.error_in_exec, repr(self.result)) class InteractiveShell(SingletonConfigurable): From 622b6cfa1e521c0173b77db07a89b55b64751ee6 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jul 2016 12:16:05 -0700 Subject: [PATCH 0561/4859] Add codecov file, its apparently only way ton configure now. --- codecov.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 codecov.yml diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..eb9b9dff30c --- /dev/null +++ b/codecov.yml @@ -0,0 +1,9 @@ +coverage: + status: + project: + default: + target: auto + threshold: 10 + patch: + default: + target: 0% From 21c81f10f8856e718862c734579abc4f7984447e Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jul 2016 15:33:48 -0700 Subject: [PATCH 0562/4859] Make clearer and simpler how to user prompt-toolkit PDB Closes #9781 --- IPython/core/debugger.py | 17 ++++++++++++++--- IPython/terminal/debugger.py | 4 ++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index efc614c8fd1..2ee3aeb7322 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -82,7 +82,10 @@ def BdbQuit_IPython_excepthook(self,et,ev,tb,tb_offset=None): class Tracer(object): - """Class for local debugging, similar to pdb.set_trace. + """ + DEPRECATED + + Class for local debugging, similar to pdb.set_trace. Instances of this class, when called, behave like pdb.set_trace, but providing IPython's enhanced capabilities. @@ -96,7 +99,10 @@ class Tracer(object): @skip_doctest def __init__(self, colors=None): - """Create a local debugger instance. + """ + DEPRECATED + + Create a local debugger instance. Parameters ---------- @@ -197,7 +203,12 @@ def _file_lines(fname): class Pdb(OldPdb, object): - """Modified Pdb class, does not load readline.""" + """Modified Pdb class, does not load readline. + + for a standalone version that uses promtp_toolkit, see + `IPython.terminal.debugger.TerminalPdb` and + `IPython.terminal.debugger.set_trace()` + """ def __init__(self, color_scheme=None, completekey=None, stdin=None, stdout=None, context=5): diff --git a/IPython/terminal/debugger.py b/IPython/terminal/debugger.py index 315c956cb6e..36dda896b88 100644 --- a/IPython/terminal/debugger.py +++ b/IPython/terminal/debugger.py @@ -71,3 +71,7 @@ def cmdloop(self, intro=None): self.postloop() except Exception: raise + +def set_trace(): + TerminalPdb().set_trace() + From 1909d9109282528ef77882d76881a9b27fd2e06a Mon Sep 17 00:00:00 2001 From: michaelpacer Date: Mon, 25 Jul 2016 16:18:22 -0700 Subject: [PATCH 0563/4859] Fixed formatting at end of lines --- IPython/terminal/interactiveshell.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 50f3c524959..21d78f97929 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -174,9 +174,9 @@ def _displayhook_class_default(self): ).tag(config=True) 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." + help= ( "Options for displaying tab completions, 'column', 'multicolumn', and " + "'readlinelike'. These options are for `prompt_toolkit`, see " + "`prompt_toolkit` documentation for more information." ), default_value='multicolumn').tag(config=True) From 4e67b725bb12711c62c5e7a4698efcb98013ee4b Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Mon, 25 Jul 2016 17:11:14 -0700 Subject: [PATCH 0564/4859] Update what's new with 5.1 changes. --- docs/source/whatsnew/pr/truecolor-feature.rst | 9 ------ docs/source/whatsnew/version5.rst | 28 +++++++++++++++++++ 2 files changed, 28 insertions(+), 9 deletions(-) delete mode 100644 docs/source/whatsnew/pr/truecolor-feature.rst diff --git a/docs/source/whatsnew/pr/truecolor-feature.rst b/docs/source/whatsnew/pr/truecolor-feature.rst deleted file mode 100644 index 659205694c0..00000000000 --- a/docs/source/whatsnew/pr/truecolor-feature.rst +++ /dev/null @@ -1,9 +0,0 @@ -prompt_toolkit uses pygments styles for syntax highlighting. By default, the -colors specified in the style are approximated using a standard 256-color -palette. prompt_toolkit also supports 24bit, a.k.a. "true", a.k.a. 16-million -color escape sequences which enable compatible terminals to display the exact -colors specified instead of an approximation. This true_color option exposes -that capability in prompt_toolkit to the IPython shell. - -Here is a good source for the current state of true color support in various -terminal emulators and software projects: https://gist.github.com/XVilka/8346728 diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 921ba55ad66..602ef0529b3 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -2,6 +2,34 @@ 5.x Series ============ +IPython 5.1 +=========== + +* Broken ``%timeit`` on Python2 due to the use of ``__qualname__``. :ghpull:`9804` +* Restore ``%gui qt`` to create and return a ``QApplication`` if necessary. :ghpull:`9789` +* Don't set terminal title by default. :ghpull:`9801` +* Preserve indentation when inserting newlines with ``Ctrl-O``. :ghpull:`9770` +* Restore completion in debugger. :ghpull:`9785` +* Deprecate ``IPtyhon.core.debugger.Tracer()`` in favor of simpler, newer, APIs. :ghpull:`9731` +* Restore ``NoOpContext`` context manager removed by mistake, and add `DeprecationWarning`. :ghpull:`9765` +* Add option allowing ``Prompt_toolkit`` to use 24bits colors. :ghpull:`9736` + + +True Color feature +------------------ + +``prompt_toolkit`` uses pygments styles for syntax highlighting. By default, the +colors specified in the style are approximated using a standard 256-color +palette. ``prompt_toolkit`` also supports 24bit, a.k.a. "true", a.k.a. 16-million +color escape sequences which enable compatible terminals to display the exact +colors specified instead of an approximation. This true_color option exposes +that capability in prompt_toolkit to the IPython shell. + +Here is a good source for the current state of true color support in various +terminal emulators and software projects: https://gist.github.com/XVilka/8346728 + + + IPython 5.0 =========== From 4ad62816be4945325c6a3d8f1d956f79f023ba3c Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 26 Jul 2016 16:46:38 +0100 Subject: [PATCH 0565/4859] Fix typo --- IPython/core/debugger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/debugger.py b/IPython/core/debugger.py index 2ee3aeb7322..591e4c3b8ca 100644 --- a/IPython/core/debugger.py +++ b/IPython/core/debugger.py @@ -205,7 +205,7 @@ def _file_lines(fname): class Pdb(OldPdb, object): """Modified Pdb class, does not load readline. - for a standalone version that uses promtp_toolkit, see + for a standalone version that uses prompt_toolkit, see `IPython.terminal.debugger.TerminalPdb` and `IPython.terminal.debugger.set_trace()` """ From 57522575ad2a69eaa7a931f98221b758d787fd74 Mon Sep 17 00:00:00 2001 From: The-Penultimate-Defenestrator Date: Tue, 26 Jul 2016 16:10:24 -0400 Subject: [PATCH 0566/4859] Support running directories with __main__.py files Note that this does not support running zip files. --- IPython/core/shellapp.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index 3e54d63f57b..ee1842fa1e4 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -100,7 +100,7 @@ class InteractiveShellApp(Configurable): """A Mixin for applications that start InteractiveShell instances. - + Provides configurables for loading extensions and executing files as part of configuring a Shell environment. @@ -126,7 +126,7 @@ class InteractiveShellApp(Configurable): # Extensions that are always loaded (not configurable) default_extensions = List(Unicode(), [u'storemagic']).tag(config=False) - + hide_initial_ns = Bool(True, help="""Should variables loaded at startup (by startup files, exec_lines, etc.) be hidden from tools like %who?""" @@ -166,7 +166,7 @@ class InteractiveShellApp(Configurable): pylab_import_all = Bool(True, help="""If true, IPython will populate the user namespace with numpy, pylab, etc. and an ``import *`` is done from numpy and pylab, when using pylab mode. - + When False, pylab mode should not import any names into the user namespace. """ ).tag(config=True) @@ -174,7 +174,7 @@ class InteractiveShellApp(Configurable): allow_none=True) # whether interact-loop should start interact = Bool(True) - + user_ns = Instance(dict, args=None, allow_none=True) @observe('user_ns') def _user_ns_changed(self, change): @@ -203,10 +203,10 @@ def init_gui_pylab(self): elif self.gui: enable = shell.enable_gui key = self.gui - + if not enable: return - + try: r = enable(key) except ImportError: @@ -217,7 +217,7 @@ def init_gui_pylab(self): self.log.warning("GUI event loop or pylab initialization failed") self.shell.showtraceback() return - + if isinstance(r, tuple): gui, backend = r[:2] self.log.info("Enabling GUI event loop integration, " @@ -263,16 +263,16 @@ def init_code(self): self._run_startup_files() self._run_exec_lines() self._run_exec_files() - + # Hide variables defined here from %who etc. if self.hide_initial_ns: self.shell.user_ns_hidden.update(self.shell.user_ns) - + # command-line execution (ipython -i script.py, ipython -m module) # should *not* be excluded from %whos self._run_cmd_line_code() self._run_module() - + # flush output, so itwon't be attached to the first cell sys.stdout.flush() sys.stderr.flush() @@ -333,7 +333,7 @@ def _run_startup_files(self): """Run files from profile startup directory""" startup_dir = self.profile_dir.startup_dir startup_files = [] - + if self.exec_PYTHONSTARTUP and os.environ.get('PYTHONSTARTUP', False) and \ not (self.file_to_run or self.code_to_run or self.module_to_run): python_startup = os.environ['PYTHONSTARTUP'] @@ -343,12 +343,12 @@ def _run_startup_files(self): except: self.log.warning("Unknown error in handling PYTHONSTARTUP file %s:", python_startup) self.shell.showtraceback() - + startup_files += glob.glob(os.path.join(startup_dir, '*.py')) startup_files += glob.glob(os.path.join(startup_dir, '*.ipy')) if not startup_files: return - + self.log.debug("Running startup files from %s...", startup_dir) try: for fname in sorted(startup_files): @@ -388,6 +388,8 @@ def _run_cmd_line_code(self): # Like Python itself, ignore the second if the first of these is present elif self.file_to_run: fname = self.file_to_run + if os.path.isdir(fname): + fname = os.path.join(fname, "__main__.py") try: self._exec_file(fname, shell_futures=True) except: From ac64b2b32aa6baa775f895a60276dcebb2b9ddaa Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 28 Jul 2016 12:05:48 +0100 Subject: [PATCH 0567/4859] Use builtin_trap in safe_execfile This makes get_ipython() available as a builtin when startup files run. Closes gh-9791 --- IPython/core/interactiveshell.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index b30b480f03c..b2ab5046014 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -2469,7 +2469,7 @@ def safe_execfile(self, fname, *where, **kw): # Python inserts the script's directory into sys.path dname = os.path.dirname(fname) - with prepended_to_syspath(dname): + with prepended_to_syspath(dname), self.builtin_trap: try: glob, loc = (where + (None, ))[:2] py3compat.execfile( From 37863a8bd6c07cecbcca4b244dd80ff4139169fb Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 28 Jul 2016 15:35:16 -0700 Subject: [PATCH 0568/4859] Quit IPython on Ctrl-\ (SIGQUIT) Closes #9810 --- IPython/terminal/shortcuts.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/IPython/terminal/shortcuts.py b/IPython/terminal/shortcuts.py index 5c32b0843ca..456d4e3379e 100644 --- a/IPython/terminal/shortcuts.py +++ b/IPython/terminal/shortcuts.py @@ -26,6 +26,8 @@ def register_ipython_shortcuts(registry, shell): & insert_mode ))(newline_or_execute_outer(shell)) + registry.add_binding(Keys.ControlBackslash)(force_exit) + registry.add_binding(Keys.ControlP, filter=(ViInsertMode() & HasFocus(DEFAULT_BUFFER) ))(previous_history_or_previous_completion) @@ -145,6 +147,12 @@ def reset_search_buffer(event): def suspend_to_bg(event): event.cli.suspend_to_background() +def force_exit(event): + """ + Force exit (with a non-zero return value) + """ + sys.exit("Quit") + def indent_buffer(event): event.current_buffer.insert_text(' ' * 4) From 5634a6a4187cc20c8fda1c9fe253cd2b9aea4350 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Thu, 28 Jul 2016 22:15:04 -0300 Subject: [PATCH 0569/4859] Rewrite tox.ini, including PyPy and CPython 3.5+ --- tox.ini | 56 ++++++++++++++++++++------------------------------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/tox.ini b/tox.ini index 3a197386dbb..465b75d6d74 100644 --- a/tox.ini +++ b/tox.ini @@ -1,44 +1,28 @@ -# Tox (http://tox.testrun.org/) is a tool for running tests -# in multiple virtualenvs. This configuration file will run the -# test suite on all supported python versions. To use it, "pip install tox" -# and then run "tox" from this directory. - -# Building the source distribution requires `invoke` and `lessc` to be on your PATH. -# "pip install invoke" will install invoke. Less can be installed by -# node.js' (http://nodejs.org/) package manager npm: -# "npm install -g less". - -# Javascript tests need additional dependencies that can be installed -# using node.js' package manager npm: -# [*] casperjs: "npm install -g casperjs" -# [*] slimerjs: "npm install -g slimerjs" -# [*] phantomjs: "npm install -g phantomjs" - -# Note: qt4 versions break some tests with tornado versions >=4.0. +; Tox (http://tox.testrun.org/) is a virtualenv manager for running tests in +; multiple environments. This configuration file gets the requirements from +; setup.py like a "pip install ipython[test]". To create the environments, it +; requires every interpreter available/installed. +; -- Commands -- +; pip install tox # Installs tox +; tox # Runs the tests (call from the directory with tox.ini) +; tox -r # Runs rebuilding virtual environments +; tox -e py35,pypy # Runs only in the selected environments +; tox -- --all -j # Runs "iptest --all -j" in every environment [tox] -envlist = py27, py33, py34 +envlist = py{36,35,34,33,27,py} +skip_missing_interpreters = True +toxworkdir = /tmp/tox_ipython [testenv] +; PyPy requires its Numpy fork instead of "pip install numpy" +; Other IPython/testing dependencies should be in setup.py, not here deps = - pyzmq - nose - tornado<4.0 - jinja2 - sphinx - pygments - jsonpointer - jsonschema - mistune + pypy: https://bitbucket.org/pypy/numpy/get/master.zip + py{36,35,34,33,27}: matplotlib + .[test] -# To avoid loading IPython module in the current directory, change -# current directory to ".tox/py*/tmp" before running test. +; It's just to avoid loading IPython module in the current directory changedir = {envtmpdir} -commands = - iptest --all - -[testenv:py27] -deps= - mock - {[testenv]deps} +commands = iptest {posargs} From a9028681dcedb03bf64d263d8f1168545335b0e9 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 29 Jul 2016 14:01:16 +0200 Subject: [PATCH 0570/4859] fix some deprecations various deprecations, especially our own usage of deprecated APIs in this package - remove few remaining references to, uses of io.stdout - suppress deprecation warnings when initializing deprecated `utils.io.std*` - globalipapp.StreamProxy is now totally unused - one missing traitlets 4.2 API in core.formatters - get gui keys from pt_inputhooks instead of deprecated lib.inputhook - stop passing deprecated color_scheme to Pdb - nt.assert_equals in test_latextools --- IPython/core/displayhook.py | 4 ++-- IPython/core/displaypub.py | 2 +- IPython/core/formatters.py | 4 +++- IPython/core/interactiveshell.py | 8 ++++++-- IPython/core/shellapp.py | 4 ++-- IPython/core/tests/test_debugger.py | 19 ++++++------------ IPython/core/ultratb.py | 8 ++++---- IPython/lib/demo.py | 2 +- IPython/lib/tests/test_latextools.py | 16 +++++++-------- IPython/sphinxext/ipython_directive.py | 9 ++++----- IPython/terminal/interactiveshell.py | 11 ++++++++--- IPython/testing/globalipapp.py | 27 +++++++------------------- IPython/utils/io.py | 14 +++++++++---- IPython/utils/warn.py | 2 +- 14 files changed, 63 insertions(+), 67 deletions(-) diff --git a/IPython/core/displayhook.py b/IPython/core/displayhook.py index ad3cc27ba65..07d733e22d2 100644 --- a/IPython/core/displayhook.py +++ b/IPython/core/displayhook.py @@ -109,7 +109,7 @@ def write_output_prompt(self): """Write the output prompt. The default implementation simply writes the prompt to - ``io.stdout``. + ``sys.stdout``. """ # Use write, not print which adds an extra space. sys.stdout.write(self.shell.separate_out) @@ -156,7 +156,7 @@ def write_format_data(self, format_dict, md_dict=None): """Write the format data dict to the frontend. This default version of this method simply writes the plain text - representation of the object to ``io.stdout``. Subclasses should + representation of the object to ``sys.stdout``. Subclasses should override this method to send the entire `format_dict` to the frontends. diff --git a/IPython/core/displaypub.py b/IPython/core/displaypub.py index 0269b7585d6..26996b0fd0c 100644 --- a/IPython/core/displaypub.py +++ b/IPython/core/displaypub.py @@ -91,7 +91,7 @@ def publish(self, data, metadata=None, source=None): Unused. """ - # The default is to simply write the plain text data using io.stdout. + # The default is to simply write the plain text data using sys.stdout. if 'text/plain' in data: print(data['text/plain']) diff --git a/IPython/core/formatters.py b/IPython/core/formatters.py index 998512e9e5b..adef4888001 100644 --- a/IPython/core/formatters.py +++ b/IPython/core/formatters.py @@ -588,7 +588,8 @@ def dtype_pprinter(obj, p, cycle): # setter for float precision, either int or direct format-string float_precision = CUnicode('').tag(config=True) - def _float_precision_changed(self, name, old, new): + @observe('float_precision') + def _float_precision_changed(self, change): """float_precision changed, set float_format accordingly. float_precision can be set by int or str. @@ -602,6 +603,7 @@ def _float_precision_changed(self, name, old, new): This parameter can be set via the '%precision' magic. """ + new = change['new'] if '%' in new: # got explicit format string fmt = new diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index b30b480f03c..57ac49bb549 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -651,8 +651,12 @@ def init_io(self): # override sys.stdout and sys.stderr themselves, you need to do that # *before* instantiating this class, because io holds onto # references to the underlying streams. - io.stdout = io.IOStream(sys.stdout) - io.stderr = io.IOStream(sys.stderr) + # io.std* are deprecated, but don't show our own deprecation warnings + # during initialization of the deprecated API. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) def init_prompts(self): # Set system prompts, so that scripts can decide if they are running diff --git a/IPython/core/shellapp.py b/IPython/core/shellapp.py index ee1842fa1e4..ab8fbe47b8d 100644 --- a/IPython/core/shellapp.py +++ b/IPython/core/shellapp.py @@ -24,13 +24,13 @@ from traitlets import ( Unicode, Instance, List, Bool, CaselessStrEnum, observe, ) -from IPython.lib.inputhook import guis +from IPython.terminal import pt_inputhooks #----------------------------------------------------------------------------- # Aliases and Flags #----------------------------------------------------------------------------- -gui_keys = tuple(sorted([ key for key in guis if key is not None ])) +gui_keys = tuple(sorted(pt_inputhooks.backends) + sorted(pt_inputhooks.aliases)) backend_keys = sorted(pylabtools.backends.keys()) backend_keys.insert(0, 'auto') diff --git a/IPython/core/tests/test_debugger.py b/IPython/core/tests/test_debugger.py index 5db9a7ce086..d118638fffc 100644 --- a/IPython/core/tests/test_debugger.py +++ b/IPython/core/tests/test_debugger.py @@ -1,24 +1,15 @@ """Tests for debugging machinery. """ from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (c) 2012, The IPython Development Team. -# -# Distributed under the terms of the Modified BSD License. -# -# The full license is in the file COPYING.txt, distributed with this software. -#----------------------------------------------------------------------------- -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. import sys +import warnings -# third-party import nose.tools as nt -# Our own from IPython.core import debugger #----------------------------------------------------------------------------- @@ -69,7 +60,9 @@ def test_longer_repr(): nt.assert_equal(trepr(a), a_trunc) # The creation of our tracer modifies the repr module's repr function # in-place, since that global is used directly by the stdlib's pdb module. - debugger.Tracer() + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + debugger.Tracer() nt.assert_equal(trepr(a), ar) def test_ipdb_magics(): diff --git a/IPython/core/ultratb.py b/IPython/core/ultratb.py index 7fc7c72d48d..2e4268f8955 100644 --- a/IPython/core/ultratb.py +++ b/IPython/core/ultratb.py @@ -495,8 +495,8 @@ def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent= # Output stream to write to. Note that we store the original value in # a private attribute and then make the public ostream a property, so - # that we can delay accessing io.stdout until runtime. The way - # things are written now, the io.stdout object is dynamically managed + # that we can delay accessing sys.stdout until runtime. The way + # things are written now, the sys.stdout object is dynamically managed # so a reference to it should NEVER be stored statically. This # property approach confines this detail to a single location, and all # subclasses can simply access self.ostream for writing. @@ -509,7 +509,7 @@ def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent= self.old_scheme = color_scheme # save initial value for toggles if call_pdb: - self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name) + self.pdb = debugger.Pdb() else: self.pdb = None @@ -519,7 +519,7 @@ def _get_ostream(self): Valid values are: - None: the default, which means that IPython will dynamically resolve - to io.stdout. This ensures compatibility with most tools, including + to sys.stdout. This ensures compatibility with most tools, including Windows (where plain stdout doesn't recognize ANSI escapes). - Any object with 'write' and 'flush' attributes. diff --git a/IPython/lib/demo.py b/IPython/lib/demo.py index 3066722670c..4db31aab358 100644 --- a/IPython/lib/demo.py +++ b/IPython/lib/demo.py @@ -470,7 +470,7 @@ def __call__(self,index=None): if self.block_index == self.nblocks: mq1 = self.marquee('END OF DEMO') if mq1: - # avoid spurious print >>io.stdout,s if empty marquees are used + # avoid spurious print if empty marquees are used print() print(mq1) print(self.marquee('Use .reset() if you want to rerun it.')) diff --git a/IPython/lib/tests/test_latextools.py b/IPython/lib/tests/test_latextools.py index 418af98d913..6d0d1a19ee7 100644 --- a/IPython/lib/tests/test_latextools.py +++ b/IPython/lib/tests/test_latextools.py @@ -30,7 +30,7 @@ def mock_find_cmd(arg): raise FindCmdError with patch.object(latextools, "find_cmd", mock_find_cmd): - nt.assert_equals(latextools.latex_to_png_dvipng("whatever", True), + nt.assert_equal(latextools.latex_to_png_dvipng("whatever", True), None) @@ -40,7 +40,7 @@ def test_latex_to_png_dvipng_runs(): Test that latex_to_png_dvipng just runs without error. """ def mock_kpsewhich(filename): - nt.assert_equals(filename, "breqn.sty") + nt.assert_equal(filename, "breqn.sty") return None for (s, wrap) in [(u"$$x^2$$", False), (u"x^2", True)]: @@ -55,7 +55,7 @@ def test_latex_to_png_mpl_runs(): Test that latex_to_png_mpl just runs without error. """ def mock_kpsewhich(filename): - nt.assert_equals(filename, "breqn.sty") + nt.assert_equal(filename, "breqn.sty") return None for (s, wrap) in [("$x^2$", False), ("x^2", True)]: @@ -79,7 +79,7 @@ def mock_kpsewhich(filename): "(called with {0})".format(filename)) with patch.object(latextools, "kpsewhich", mock_kpsewhich): - nt.assert_equals( + nt.assert_equal( '\n'.join(latextools.genelatex("body text", False)), r'''\documentclass{article} \usepackage{amsmath} @@ -97,11 +97,11 @@ def test_genelatex_wrap_with_breqn(): Test genelatex with wrap=True for the case breqn.sty is installed. """ def mock_kpsewhich(filename): - nt.assert_equals(filename, "breqn.sty") + nt.assert_equal(filename, "breqn.sty") return "path/to/breqn.sty" with patch.object(latextools, "kpsewhich", mock_kpsewhich): - nt.assert_equals( + nt.assert_equal( '\n'.join(latextools.genelatex("x^2", True)), r'''\documentclass{article} \usepackage{amsmath} @@ -122,11 +122,11 @@ def test_genelatex_wrap_without_breqn(): Test genelatex with wrap=True for the case breqn.sty is not installed. """ def mock_kpsewhich(filename): - nt.assert_equals(filename, "breqn.sty") + nt.assert_equal(filename, "breqn.sty") return None with patch.object(latextools, "kpsewhich", mock_kpsewhich): - nt.assert_equals( + nt.assert_equal( '\n'.join(latextools.genelatex("x^2", True)), r'''\documentclass{article} \usepackage{amsmath} diff --git a/IPython/sphinxext/ipython_directive.py b/IPython/sphinxext/ipython_directive.py index 7c13cd47f17..75c9e70d995 100644 --- a/IPython/sphinxext/ipython_directive.py +++ b/IPython/sphinxext/ipython_directive.py @@ -294,14 +294,13 @@ def __init__(self, exec_lines=None): IP = InteractiveShell.instance(config=config, profile_dir=profile) atexit.register(self.cleanup) - # io.stdout redirect must be done after instantiating InteractiveShell - io.stdout = self.cout - io.stderr = self.cout + sys.stdout = self.cout + sys.stderr = self.cout # For debugging, so we can see normal output, use this: #from IPython.utils.io import Tee - #io.stdout = Tee(self.cout, channel='stdout') # dbg - #io.stderr = Tee(self.cout, channel='stderr') # dbg + #sys.stdout = Tee(self.cout, channel='stdout') # dbg + #sys.stderr = Tee(self.cout, channel='stderr') # dbg # Store a few parts of IPython we'll need. self.IP = IP diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 8084ca34d4b..6ce7709ab94 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -3,9 +3,11 @@ import os import sys +import warnings from warnings import warn 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.terminal import toggle_set_term_title, set_term_title from IPython.utils.process import abbrev_cwd @@ -360,9 +362,12 @@ def init_io(self): # For some reason we make these wrappers around stdout/stderr. # For now, we need to reset them so all output gets coloured. # https://github.com/ipython/ipython/issues/8669 - from IPython.utils import io - io.stdout = io.IOStream(sys.stdout) - io.stderr = io.IOStream(sys.stderr) + # io.std* are deprecated, but don't show our own deprecation warnings + # during initialization of the deprecated API. + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + io.stdout = io.IOStream(sys.stdout) + io.stderr = io.IOStream(sys.stderr) def init_magics(self): super(TerminalInteractiveShell, self).init_magics() diff --git a/IPython/testing/globalipapp.py b/IPython/testing/globalipapp.py index 7e6582449a0..3983393112c 100644 --- a/IPython/testing/globalipapp.py +++ b/IPython/testing/globalipapp.py @@ -8,21 +8,12 @@ from __future__ import absolute_import from __future__ import print_function -#----------------------------------------------------------------------------- -# Copyright (C) 2009-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. -#----------------------------------------------------------------------------- - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# stdlib +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + import sys +import warnings -# our own from . import tools from IPython.core import page @@ -31,9 +22,6 @@ from IPython.utils.py3compat import builtin_mod from IPython.terminal.interactiveshell import TerminalInteractiveShell -#----------------------------------------------------------------------------- -# Functions -#----------------------------------------------------------------------------- class StreamProxy(io.IOStream): """Proxy for sys.stdout/err. This will request the stream *at call time* @@ -46,6 +34,9 @@ class StreamProxy(io.IOStream): """ def __init__(self, name): + warnings.warn("StreamProxy is deprecated and unused as of IPython 5", DeprecationWarning, + stacklevel=2, + ) self.name=name @property @@ -135,10 +126,6 @@ def start_ipython(): builtin_mod._ip = _ip builtin_mod.get_ipython = get_ipython - # To avoid extra IPython messages during testing, suppress io.stdout/stderr - io.stdout = StreamProxy('stdout') - io.stderr = StreamProxy('stderr') - # Override paging, so we don't require user interaction during the tests. def nopage(strng, start=0, screen_lines=0, pager_cmd=None): if isinstance(strng, dict): diff --git a/IPython/utils/io.py b/IPython/utils/io.py index bab42265b7d..3eaa6806d18 100644 --- a/IPython/utils/io.py +++ b/IPython/utils/io.py @@ -14,6 +14,7 @@ import os import sys import tempfile +import warnings from warnings import warn from IPython.utils.decorators import undoc @@ -81,11 +82,16 @@ def close(self): pass # setup stdin/stdout/stderr to sys.stdin/sys.stdout/sys.stderr -devnull = open(os.devnull, 'w') +devnull = open(os.devnull, 'w') atexit.register(devnull.close) -stdin = IOStream(sys.stdin, fallback=devnull) -stdout = IOStream(sys.stdout, fallback=devnull) -stderr = IOStream(sys.stderr, fallback=devnull) + +# io.std* are deprecated, but don't show our own deprecation warnings +# during initialization of the deprecated API. +with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + stdin = IOStream(sys.stdin, fallback=devnull) + stdout = IOStream(sys.stdout, fallback=devnull) + stderr = IOStream(sys.stderr, fallback=devnull) class Tee(object): """A class to duplicate an output stream to stdout/err. diff --git a/IPython/utils/warn.py b/IPython/utils/warn.py index cfbf3b757da..dd4852227ba 100644 --- a/IPython/utils/warn.py +++ b/IPython/utils/warn.py @@ -18,7 +18,7 @@ def warn(msg,level=2,exit_val=1): Standard warning printer. Gives formatting consistency. - Output is sent to io.stderr (sys.stderr by default). + Output is sent to sys.stderr. Options: From 3e84f5a2a05e57c7b8a186ccc36fd8d47093df2d Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Fri, 29 Jul 2016 17:10:02 +0100 Subject: [PATCH 0571/4859] Switch tkinter import based on Python version Rather than try/except, which can cause issues if python-future is installed. Closes gh-9822 --- IPython/terminal/pt_inputhooks/tk.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/terminal/pt_inputhooks/tk.py b/IPython/terminal/pt_inputhooks/tk.py index 24313a8396a..db205b0d2c1 100644 --- a/IPython/terminal/pt_inputhooks/tk.py +++ b/IPython/terminal/pt_inputhooks/tk.py @@ -40,10 +40,12 @@ """ import time +from IPython.utils.py3compat import PY3 + import _tkinter -try: +if PY3: import tkinter -except ImportError: +else: import Tkinter as tkinter # Python 2 def inputhook(inputhook_context): From af4f9b0fec39cfb612fc988e86581daf40078660 Mon Sep 17 00:00:00 2001 From: tmr232 Date: Sat, 30 Jul 2016 00:40:21 +0300 Subject: [PATCH 0572/4859] Improved Windows path completion. Removed `\` and `:` from the delimiter list for Windows, and stopped deleting `\` chars from paths on Windows. --- IPython/core/completer.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/IPython/core/completer.py b/IPython/core/completer.py index 07bbbaa17ca..87b13b1c5d8 100644 --- a/IPython/core/completer.py +++ b/IPython/core/completer.py @@ -216,7 +216,11 @@ def completions_sorting_key(word): class Bunch(object): pass -DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' +if sys.platform == 'win32': + DELIMS = ' \t\n`!@#$^&*()=+[{]}|;\'",<>?' +else: + DELIMS = ' \t\n`!@#$^&*()=+[{]}\\|;:\'",<>?' + GREEDY_DELIMS = ' =\r\n' @@ -729,7 +733,10 @@ def file_matches(self, text): return [text_prefix + cast_unicode_py2(protect_filename(f)) for f in self.glob("*")] # Compute the matches from the filesystem - m0 = self.clean_glob(text.replace('\\','')) + if sys.platform == 'win32': + m0 = self.clean_glob(text) + else: + m0 = self.clean_glob(text.replace('\\', '')) if has_protectables: # If we had protectables, we need to revert our changes to the From 831c038f09034baa9f5830a7752a53ed2d2cb2a3 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Thu, 28 Jul 2016 22:22:13 -0300 Subject: [PATCH 0573/4859] Add PyPy testing to Travis CI --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b7e3d121138..77c2e22de9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,12 +6,14 @@ python: - 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" + - if [ $TRAVIS_PYTHON_VERSION == pypy ] ; then pip install https://bitbucket.org/pypy/numpy/get/pypy-4.0.1.zip ; fi - pip install -f travis-wheels/wheelhouse -e file://$PWD#egg=ipython[test] - pip install codecov script: @@ -23,4 +25,5 @@ after_success: matrix: allow_failures: - python: nightly + - python: nightly + - python: pypy From ca9e56dd0158cd7dd732c656ded88e1449342ad1 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Thu, 28 Jul 2016 22:26:15 -0300 Subject: [PATCH 0574/4859] Fix dict pretty printer in PyPy #9776 +3 tests passing --- IPython/lib/pretty.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 49ee2cef377..8cb51aa0ff5 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -753,7 +753,10 @@ def _exception_pprint(obj, p, cycle): } try: - _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('') + # In PyPy, types.DictProxyType is dict, setting the dictproxy printer + # using dict.setdefault avoids overwritting the dict printer + _type_pprinters.setdefault(types.DictProxyType, + _dict_pprinter_factory('')) _type_pprinters[types.ClassType] = _type_pprint _type_pprinters[types.SliceType] = _repr_pprint except AttributeError: # Python 3 From e9d44372cb5fcfe69cab56aa94c77699ed58a65f Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 01:58:00 -0300 Subject: [PATCH 0575/4859] Add a types.MappingProxyType pretty printer #9821 Also fixed the _dict_pprinter_factory indentation step --- IPython/lib/pretty.py | 7 +++-- IPython/lib/tests/test_pretty.py | 48 +++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 8cb51aa0ff5..ec0bc253b04 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -605,7 +605,8 @@ def inner(obj, p, cycle): if cycle: return p.text('{...}') - p.begin_group(1, start) + step = len(start) + p.begin_group(step, start) keys = obj.keys() # if dict isn't large enough to be truncated, sort keys before displaying if not (p.max_seq_length and len(obj) >= p.max_seq_length): @@ -621,7 +622,7 @@ def inner(obj, p, cycle): p.pretty(key) p.text(': ') p.pretty(obj[key]) - p.end_group(1, end) + p.end_group(step, end) return inner @@ -760,6 +761,8 @@ def _exception_pprint(obj, p, cycle): _type_pprinters[types.ClassType] = _type_pprint _type_pprinters[types.SliceType] = _repr_pprint except AttributeError: # Python 3 + _type_pprinters[types.MappingProxyType] = \ + _dict_pprinter_factory('mappingproxy({', '})') _type_pprinters[slice] = _repr_pprint try: diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index 69954956359..4adb0ce404d 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -7,11 +7,12 @@ from __future__ import print_function from collections import Counter, defaultdict, deque, OrderedDict +import types, string import nose.tools as nt from IPython.lib import pretty -from IPython.testing.decorators import skip_without, py2_only +from IPython.testing.decorators import skip_without, py2_only, py3_only from IPython.utils.py3compat import PY3, unicode_to_str if PY3: @@ -436,3 +437,48 @@ class MyCounter(Counter): ] for obj, expected in cases: nt.assert_equal(pretty.pretty(obj), expected) + +@py3_only +def test_mappingproxy(): + MP = types.MappingProxyType + underlying_dict = {} + mp_recursive = MP(underlying_dict) + underlying_dict[2] = mp_recursive + underlying_dict[3] = underlying_dict + + cases = [ + (MP({}), "mappingproxy({})"), + (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"), + (MP({k: k.upper() for k in string.ascii_lowercase}), + "mappingproxy({'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, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"), + (underlying_dict, + "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"), + ] + for obj, expected in cases: + nt.assert_equal(pretty.pretty(obj), expected) From fce2225fda05f7d2f2cc2edf5d405cd846b35777 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 05:26:30 -0300 Subject: [PATCH 0576/4859] Pretty print dict_proxy as prefixed in CPython 2.7 - Add tests for dict proxies (instances of types.DictProxyType) - Uses the "dict_proxy({...})" pattern for representation, as happens in CPython 2.7 with types.DictProxyType.__repr__ - Used ctypes.pythonapi.PyDictProxy_New to instantiate dict proxies inside the tests - Only for CPython 2.7: in PyPy the types.DictProxyType is dict, and in CPython 3 there's no such type, just the new types.MappingProxyType in CPython 3.3+ --- IPython/lib/pretty.py | 2 +- IPython/lib/tests/test_pretty.py | 51 +++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index ec0bc253b04..9e0d9b0e936 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -757,7 +757,7 @@ def _exception_pprint(obj, p, cycle): # In PyPy, types.DictProxyType is dict, setting the dictproxy printer # using dict.setdefault avoids overwritting the dict printer _type_pprinters.setdefault(types.DictProxyType, - _dict_pprinter_factory('')) + _dict_pprinter_factory('dict_proxy({', '})')) _type_pprinters[types.ClassType] = _type_pprint _type_pprinters[types.SliceType] = _repr_pprint except AttributeError: # Python 3 diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index 4adb0ce404d..ebfcac7b4db 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -7,7 +7,7 @@ from __future__ import print_function from collections import Counter, defaultdict, deque, OrderedDict -import types, string +import types, string, ctypes import nose.tools as nt @@ -482,3 +482,52 @@ def test_mappingproxy(): ] for obj, expected in cases: nt.assert_equal(pretty.pretty(obj), expected) + +@py2_only +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: {...}})}") From 4518b9af3aa1f8d605609d70731d8542a62091a5 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 06:09:08 -0300 Subject: [PATCH 0577/4859] Add cpython2_only decorator The test_pretty.test_dictproxy now is properly skipped on PyPy --- IPython/lib/tests/test_pretty.py | 5 +++-- IPython/testing/decorators.py | 3 ++- IPython/utils/py3compat.py | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index ebfcac7b4db..49c835dc5ac 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -12,7 +12,8 @@ import nose.tools as nt from IPython.lib import pretty -from IPython.testing.decorators import skip_without, py2_only, py3_only +from IPython.testing.decorators import (skip_without, py2_only, py3_only, + cpython2_only) from IPython.utils.py3compat import PY3, unicode_to_str if PY3: @@ -483,7 +484,7 @@ def test_mappingproxy(): for obj, expected in cases: nt.assert_equal(pretty.pretty(obj), expected) -@py2_only +@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 diff --git a/IPython/testing/decorators.py b/IPython/testing/decorators.py index a337254ca23..087555d46bc 100644 --- a/IPython/testing/decorators.py +++ b/IPython/testing/decorators.py @@ -48,7 +48,7 @@ from IPython.external.decorators import * # For onlyif_cmd_exists decorator -from IPython.utils.py3compat import string_types, which, PY2, PY3 +from IPython.utils.py3compat import string_types, which, PY2, PY3, PYPY #----------------------------------------------------------------------------- # Classes and functions @@ -336,6 +336,7 @@ 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.") diff --git a/IPython/utils/py3compat.py b/IPython/utils/py3compat.py index f42f55c959b..2e7f5bbb8ce 100644 --- a/IPython/utils/py3compat.py +++ b/IPython/utils/py3compat.py @@ -292,6 +292,7 @@ def execfile(fname, glob=None, loc=None, compiler=None): PY2 = not PY3 +PYPY = any(k.startswith("pypy") for k in dir(sys)) def annotate(**kwargs): From b6a880d39ff8afe4af7960a86349b62670a87c56 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 07:29:59 -0300 Subject: [PATCH 0578/4859] Fix "super" objects pretty printing in PyPy In PyPy there's no __self__ attribute for super(.) objects. As objects always have a __repr__, the found alternative was to use its curried argument. Previously, only the class name was verified as part of the result, now the tests include a regex. --- IPython/lib/pretty.py | 8 ++++++-- IPython/lib/tests/test_pretty.py | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 9e0d9b0e936..0393121292c 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -85,7 +85,7 @@ def _repr_pretty_(self, p, cycle): import datetime from collections import deque -from IPython.utils.py3compat import PY3, cast_unicode, string_types +from IPython.utils.py3compat import PY3, PYPY, cast_unicode, string_types from IPython.utils.encoding import get_stream_enc from io import StringIO @@ -632,7 +632,11 @@ def _super_pprint(obj, p, cycle): p.pretty(obj.__thisclass__) p.text(',') p.breakable() - p.pretty(obj.__self__) + if PYPY: # In PyPy, super() objects doesn't have __self__ attributes + dself = obj.__repr__.__self__ + p.pretty(None if dself is obj else dself) + else: + p.pretty(obj.__self__) p.end_group(8, '>') diff --git a/IPython/lib/tests/test_pretty.py b/IPython/lib/tests/test_pretty.py index 49c835dc5ac..6f11e99cb07 100644 --- a/IPython/lib/tests/test_pretty.py +++ b/IPython/lib/tests/test_pretty.py @@ -188,12 +188,14 @@ class SB(SA): pass def test_super_repr(): + # "" output = pretty.pretty(super(SA)) - nt.assert_in("SA", output) + nt.assert_regexp_matches(output, r"") + # ">" sb = SB() output = pretty.pretty(super(SA, sb)) - nt.assert_in("SA", output) + nt.assert_regexp_matches(output, r">") def test_long_list(): From 6142c8e633d4eb3d575c2333afdbe31796dcc61b Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 10:44:22 -0300 Subject: [PATCH 0579/4859] Consistent pretty(a_class) on bogus qualname/name +1 test passing in PyPy --- IPython/lib/pretty.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 0393121292c..057d1eee0c9 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -670,8 +670,10 @@ def _type_pprint(obj, p, cycle): # Heap allocated types might not have the module attribute, # and others may set it to None. - # Checks for a __repr__ override in the metaclass - if type(obj).__repr__ is not type.__repr__: + # Checks for a __repr__ override in the metaclass. Can't compare the + # type(obj).__repr__ directly because in PyPy the representation function + # inherited from type isn't the same type.__repr__ + if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]: _repr_pprint(obj, p, cycle) return From 7b0b09ba5bc6cf481684f5855dfcb8ad8e55afda Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Fri, 29 Jul 2016 19:20:32 -0300 Subject: [PATCH 0580/4859] Force Travis CI to install PyPy 5.3.1 --- .travis.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 77c2e22de9f..47d42d6fd75 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,22 @@ before_install: - 'if [[ $GROUP != js* ]]; then COVERAGE=""; fi' install: - pip install "setuptools>=18.5" - - if [ $TRAVIS_PYTHON_VERSION == pypy ] ; then pip install https://bitbucket.org/pypy/numpy/get/pypy-4.0.1.zip ; fi + # 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: From eb42678a5d2e36e64e72e2b8aba2d1cac4030c57 Mon Sep 17 00:00:00 2001 From: "Danilo J. S. Bellini" Date: Tue, 2 Aug 2016 04:59:58 -0300 Subject: [PATCH 0581/4859] Cleaner PYPY flag (platform module); Comment fixes --- IPython/lib/pretty.py | 2 +- IPython/utils/py3compat.py | 3 ++- tox.ini | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/IPython/lib/pretty.py b/IPython/lib/pretty.py index 057d1eee0c9..97529f19352 100644 --- a/IPython/lib/pretty.py +++ b/IPython/lib/pretty.py @@ -632,7 +632,7 @@ def _super_pprint(obj, p, cycle): p.pretty(obj.__thisclass__) p.text(',') p.breakable() - if PYPY: # In PyPy, super() objects doesn't have __self__ attributes + if PYPY: # In PyPy, super() objects don't have __self__ attributes dself = obj.__repr__.__self__ p.pretty(None if dself is obj else dself) else: diff --git a/IPython/utils/py3compat.py b/IPython/utils/py3compat.py index 2e7f5bbb8ce..88602e5342d 100644 --- a/IPython/utils/py3compat.py +++ b/IPython/utils/py3compat.py @@ -6,6 +6,7 @@ import re import shutil import types +import platform from .encoding import DEFAULT_ENCODING @@ -292,7 +293,7 @@ def execfile(fname, glob=None, loc=None, compiler=None): PY2 = not PY3 -PYPY = any(k.startswith("pypy") for k in dir(sys)) +PYPY = platform.python_implementation() == "PyPy" def annotate(**kwargs): diff --git a/tox.ini b/tox.ini index 465b75d6d74..1668ce6f3ed 100644 --- a/tox.ini +++ b/tox.ini @@ -5,7 +5,7 @@ ; -- Commands -- ; pip install tox # Installs tox ; tox # Runs the tests (call from the directory with tox.ini) -; tox -r # Runs rebuilding virtual environments +; tox -r # Ditto, but forcing the virtual environments to be rebuilt ; tox -e py35,pypy # Runs only in the selected environments ; tox -- --all -j # Runs "iptest --all -j" in every environment @@ -22,7 +22,7 @@ deps = py{36,35,34,33,27}: matplotlib .[test] -; It's just to avoid loading IPython module in the current directory +; It's just to avoid loading the IPython package in the current directory changedir = {envtmpdir} commands = iptest {posargs} From 3e16cbc4bf3305f26ec7a7db53931d6c87ea2213 Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 3 Aug 2016 11:35:55 +0200 Subject: [PATCH 0582/4859] safer check for isatty if no isatty method is defined, it's probably not a tty --- IPython/terminal/interactiveshell.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 6ce7709ab94..077d92c9c42 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -74,11 +74,17 @@ def get_default_editor(): else: return 'notepad' # same in Windows! - -if sys.stdin and sys.stdout and sys.stderr: - _is_tty = (sys.stdin.isatty()) and (sys.stdout.isatty()) and (sys.stderr.isatty()) +# conservatively check for tty +# overridden streams can result in things like: +# - sys.stdin = None +# - no isatty method +for _name in ('stdin', 'stdout', 'stderr'): + _stream = getattr(sys, _name) + if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty(): + _is_tty = False + break else: - _is_tty = False + _is_tty = True _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) From 7b7d560822d4e9b6ab486393e22e305c502ff6d1 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 4 Aug 2016 15:24:20 +0100 Subject: [PATCH 0583/4859] Use 'Linux' (dark bg) colours for Windows This puts the colours in inspect output and tracebacks back to what they were in IPython 4.x, but leaves the prompt colouring as in 5.0. I tried changing the colour scheme to 'Linux' entirely for Windows, but that selects Monokai as the theme for prompt_toolkit, which looks pretty horrible in 16 colours (at least to my eyes). This is admittedly a hack, but hopefully our legacy colour system is on the way out anyway. Closes gh-9723 --- IPython/utils/PyColorize.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/IPython/utils/PyColorize.py b/IPython/utils/PyColorize.py index 1dda22f9a52..124eb2d4e3c 100644 --- a/IPython/utils/PyColorize.py +++ b/IPython/utils/PyColorize.py @@ -146,7 +146,15 @@ 'normal' : Colors.Normal # color off (usu. Colors.Normal) } ) - +# Hack: the 'neutral' colours are not very visible on a dark background on +# Windows. Since Windows command prompts have a dark background by default, and +# relatively few users are likely to alter that, we will use the 'Linux' colours, +# designed for a dark background, as the default on Windows. Changing it here +# avoids affecting the prompt colours rendered by prompt_toolkit, where the +# neutral defaults do work OK. + +if os.name == 'nt': + NeutralColors = LinuxColors.copy(name='Neutral') LightBGColors = ColorScheme( 'LightBG',{ From c7baf6184b487ce7dfbbbe369cb48e1defc3df04 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Thu, 4 Aug 2016 17:05:33 +0100 Subject: [PATCH 0584/4859] Skip some failing tests on Windows The failures are not important, and we need to rewrite the completion machinery anyway. Closes gh-9839 --- IPython/core/tests/test_completer.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/IPython/core/tests/test_completer.py b/IPython/core/tests/test_completer.py index 8211dd0b9cc..8679780d9a3 100644 --- a/IPython/core/tests/test_completer.py +++ b/IPython/core/tests/test_completer.py @@ -183,6 +183,7 @@ def test_forward_unicode_completion(): nt.assert_equal(matches[0], 'Ⅴ') @dec.onlyif(sys.version_info[0] >= 3, 'This test only apply on python3') +@dec.knownfailureif(sys.platform == 'win32', 'Fails if there is a C:\\j... path') def test_no_ascii_back_completion(): ip = get_ipython() with TemporaryWorkingDirectory(): # Avoid any filename completions @@ -644,8 +645,10 @@ def test_dict_key_completion_unicode_py2(): nt.assert_in("a\\u05d0b", matches) # query using escape - _, matches = complete(line_buffer=u"d[u'a\\u05d0") - nt.assert_in("u05d0b", matches) # tokenized after \\ + if sys.platform != 'win32': + # Known failure on Windows + _, matches = complete(line_buffer=u"d[u'a\\u05d0") + nt.assert_in("u05d0b", matches) # tokenized after \\ # query using character _, matches = complete(line_buffer=u"d[u'a\u05d0") @@ -686,8 +689,10 @@ def test_dict_key_completion_unicode_py3(): ip.user_ns['d'] = {u'a\u05d0': None} # query using escape - _, matches = complete(line_buffer="d['a\\u05d0") - nt.assert_in("u05d0", matches) # tokenized after \\ + if sys.platform != 'win32': + # Known failure on Windows + _, matches = complete(line_buffer="d['a\\u05d0") + nt.assert_in("u05d0", matches) # tokenized after \\ # query using character _, matches = complete(line_buffer="d['a\u05d0") From 53320003433f3d9fdc47cd9eaedd2b9444ab86de Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 5 Aug 2016 10:10:56 +0200 Subject: [PATCH 0585/4859] Allow starting TerminalInteractiveShell more than once 1. always start with keep_running=True in `interact()` 2. don't close eventloop at end of mainloop (not sure this is the right thing to do) --- IPython/terminal/interactiveshell.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index 077d92c9c42..ef8cd3fb91a 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -415,6 +415,7 @@ def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED): if display_banner is not DISPLAY_BANNER_DEPRECATED: warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) + self.keep_running = True while self.keep_running: print(self.separate_in, end='') @@ -440,9 +441,6 @@ def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED): break except KeyboardInterrupt: print("\nKeyboardInterrupt escaped interact()\n") - - if hasattr(self, '_eventloop'): - self._eventloop.close() _inputhook = None def inputhook(self, context): From 497963c9e69824ff62fb3a3b0eb172d462b51442 Mon Sep 17 00:00:00 2001 From: Min RK Date: Fri, 5 Aug 2016 15:47:13 +0200 Subject: [PATCH 0586/4859] give PTCompleter InteractiveShell, not Completer it is possible for the completer to get reloaded/replaced, at which point the prompt-toolkit completions will not be those of ip.Completer, but whatever ip.Completer was originally. --- IPython/terminal/interactiveshell.py | 2 +- IPython/terminal/ptutils.py | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index ef8cd3fb91a..f1f44446a9e 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -238,7 +238,7 @@ def prompt(): editing_mode=editing_mode, key_bindings_registry=kbmanager.registry, history=history, - completer=IPythonPTCompleter(self.Completer), + completer=IPythonPTCompleter(self), enable_history_search=True, style=style, mouse_support=self.mouse_support, diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 092373e4f61..1dd4b727a50 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -12,8 +12,12 @@ class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" - def __init__(self, ipy_completer): - self.ipy_completer = ipy_completer + def __init__(self, shell): + self.shell = shell + + @property + def ipy_completer(self): + return self.shell.Completer def get_completions(self, document, complete_event): if not document.current_line.strip(): From 8e65bf09c3be5e6b7d43e4145f129c7f66f6af2f Mon Sep 17 00:00:00 2001 From: memeplex Date: Sun, 7 Aug 2016 14:26:46 -0300 Subject: [PATCH 0587/4859] 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 e96f4e58e4b5f24bc2f5badb5870ca822a41924e Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 8 Aug 2016 11:55:48 +0200 Subject: [PATCH 0588/4859] explicit TypeError when IPCompleter passed to PTCompleter --- IPython/terminal/ptutils.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 1dd4b727a50..156181e53b3 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -3,6 +3,7 @@ from IPython.utils.py3compat import PY3 +from IPython.core.completer import IPCompleter from prompt_toolkit.completion import Completer, Completion from prompt_toolkit.layout.lexers import Lexer from prompt_toolkit.layout.lexers import PygmentsLexer @@ -13,8 +14,11 @@ class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" def __init__(self, shell): + if isinstance(shell, IPCompleter): + raise TypeError("IPythonPTCompleter expects an InteractiveShell" + " instance in IPython 5.1, not a Completer") self.shell = shell - + @property def ipy_completer(self): return self.shell.Completer From c275249c5dfb3be8269b149ff22e770a58e48ef8 Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 8 Aug 2016 12:02:09 +0200 Subject: [PATCH 0589/4859] Make IPythonPTCompleter(shell) backward-compatible and declare that ptutils only contains private APIs --- IPython/terminal/interactiveshell.py | 2 +- IPython/terminal/ptutils.py | 22 +++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/IPython/terminal/interactiveshell.py b/IPython/terminal/interactiveshell.py index f1f44446a9e..738782223cf 100644 --- a/IPython/terminal/interactiveshell.py +++ b/IPython/terminal/interactiveshell.py @@ -238,7 +238,7 @@ def prompt(): editing_mode=editing_mode, key_bindings_registry=kbmanager.registry, history=history, - completer=IPythonPTCompleter(self), + completer=IPythonPTCompleter(shell=self), enable_history_search=True, style=style, mouse_support=self.mouse_support, diff --git a/IPython/terminal/ptutils.py b/IPython/terminal/ptutils.py index 156181e53b3..84515e191ec 100644 --- a/IPython/terminal/ptutils.py +++ b/IPython/terminal/ptutils.py @@ -1,3 +1,12 @@ +"""prompt-toolkit utilities + +Everything in this module is a private API, +not to be used outside IPython. +""" + +# Copyright (c) IPython Development Team. +# Distributed under the terms of the Modified BSD License. + import unicodedata from wcwidth import wcwidth @@ -13,15 +22,18 @@ class IPythonPTCompleter(Completer): """Adaptor to provide IPython completions to prompt_toolkit""" - def __init__(self, shell): - if isinstance(shell, IPCompleter): - raise TypeError("IPythonPTCompleter expects an InteractiveShell" - " instance in IPython 5.1, not a Completer") + def __init__(self, ipy_completer=None, shell=None): + if shell is None and ipy_completer is None: + raise TypeError("Please pass shell=an InteractiveShell instance.") + self._ipy_completer = ipy_completer self.shell = shell @property def ipy_completer(self): - return self.shell.Completer + if self._ipy_completer: + return self._ipy_completer + else: + return self.shell.Completer def get_completions(self, document, complete_event): if not document.current_line.strip(): From c17ff28cb1220a91d94fc0dc4b85ccee561fb68f Mon Sep 17 00:00:00 2001 From: Min RK Date: Mon, 8 Aug 2016 17:17:14 +0200 Subject: [PATCH 0590/4859] undocument terminal.ptutils --- docs/autogen_api.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/autogen_api.py b/docs/autogen_api.py index f1064a0fdf5..46a806ca95f 100755 --- a/docs/autogen_api.py +++ b/docs/autogen_api.py @@ -56,6 +56,8 @@ r'\.qt', # this is deprecated. r'\.utils\.warn', + # Private APIs (there should be a lot more here) + r'\.terminal\.ptutils', ] # main API is in the inputhook module, which is documented. From 54f7e5cd8bb98b15d4bb9ea8515f657253223c08 Mon Sep 17 00:00:00 2001 From: Julian Kuhlmann Date: Tue, 9 Aug 2016 10:26:58 +0200 Subject: [PATCH 0591/4859] Fix typo. --- docs/source/interactive/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/interactive/index.rst b/docs/source/interactive/index.rst index 9852e566122..1a6298deb72 100644 --- a/docs/source/interactive/index.rst +++ b/docs/source/interactive/index.rst @@ -10,7 +10,7 @@ done some work in the REPL. .. note:: Some part of this documentation are more than a decade old so might be out - of date, we welcome any report of inacuracy, and Pull Requests that make + of date, we welcome any report of inaccuracy, and Pull Requests that make that up to date. .. toctree:: From e8beebb967e46fb00e8eb3449c009e9aea5ec455 Mon Sep 17 00:00:00 2001 From: Min RK Date: Tue, 9 Aug 2016 13:02:22 +0200 Subject: [PATCH 0592/4859] fix circular matplotlib imports on ipykernel 4.4 + python 2 - use matplotlib instead of rcParams - remove unused backend_inline import --- IPython/core/pylabtools.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/IPython/core/pylabtools.py b/IPython/core/pylabtools.py index e7327e58e8c..815b8d7c7aa 100644 --- a/IPython/core/pylabtools.py +++ b/IPython/core/pylabtools.py @@ -199,7 +199,6 @@ def select_figure_formats(shell, formats, **kwargs): """ import matplotlib from matplotlib.figure import Figure - from ipykernel.pylab import backend_inline svg_formatter = shell.display_formatter.formatters['image/svg+xml'] png_formatter = shell.display_formatter.formatters['image/png'] @@ -358,7 +357,7 @@ def configure_inline_support(shell, backend): from ipykernel.pylab.backend_inline import InlineBackend except ImportError: return - from matplotlib import pyplot + import matplotlib cfg = InlineBackend.instance(parent=shell) cfg.shell = shell @@ -372,9 +371,9 @@ def configure_inline_support(shell, backend): # Save rcParams that will be overwrittern shell._saved_rcParams = dict() for k in cfg.rc: - shell._saved_rcParams[k] = pyplot.rcParams[k] + shell._saved_rcParams[k] = matplotlib.rcParams[k] # load inline_rc - pyplot.rcParams.update(cfg.rc) + matplotlib.rcParams.update(cfg.rc) new_backend_name = "inline" else: from ipykernel.pylab.backend_inline import flush_figures @@ -383,7 +382,7 @@ def configure_inline_support(shell, backend): except ValueError: pass if hasattr(shell, '_saved_rcParams'): - pyplot.rcParams.update(shell._saved_rcParams) + matplotlib.rcParams.update(shell._saved_rcParams) del shell._saved_rcParams new_backend_name = "other" From c5bee47512792b84b2a9e973a63a248ce44f9d69 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Tue, 9 Aug 2016 14:11:24 +0100 Subject: [PATCH 0593/4859] 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 e975cd7294c909e33b4ae154a49895e7c9f7d29a Mon Sep 17 00:00:00 2001 From: Min RK Date: Wed, 10 Aug 2016 13:31:33 +0200 Subject: [PATCH 0594/4859] run CFRunLoopRun if NSApp:run finishes on its own this seems to happen when the last Window is closed, but the eventloop needs to run a little longer in order to finish closing the Window --- IPython/terminal/pt_inputhooks/osx.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/IPython/terminal/pt_inputhooks/osx.py b/IPython/terminal/pt_inputhooks/osx.py index 9f41c3f4a36..efa8854b5eb 100644 --- a/IPython/terminal/pt_inputhooks/osx.py +++ b/IPython/terminal/pt_inputhooks/osx.py @@ -7,6 +7,7 @@ import ctypes import ctypes.util +from threading import Event objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('objc')) @@ -97,8 +98,11 @@ def _wake(NSApp): msg(NSApp, n('postEvent:atStart:'), void_p(event), True) +_triggered = Event() + def _input_callback(fdref, flags, info): """Callback to fire when there's input to be read""" + _triggered.set() CFFileDescriptorInvalidate(fdref) CFRelease(fdref) NSApp = _NSApp() @@ -111,6 +115,7 @@ def _input_callback(fdref, flags, info): def _stop_on_read(fd): """Register callback to stop eventloop when there's data on fd""" + _triggered.clear() fdref = CFFileDescriptorCreate(None, fd, False, _c_input_callback, None) CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack) source = CFFileDescriptorCreateRunLoopSource(None, fdref, 0) @@ -130,4 +135,9 @@ def inputhook(context): return _stop_on_read(context.fileno()) msg(NSApp, n('run')) - + if not _triggered.is_set(): + # app closed without firing callback, + # probably due to last window being closed. + # Run the loop manually in this case, + # since there may be events still to process (#9734) + CoreFoundation.CFRunLoopRun() From 4351964f7156a5dd0974c85e856df067609cae16 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 10 Aug 2016 16:02:43 +0100 Subject: [PATCH 0595/4859] Document colours and escapes in prompts Closes gh-8724 --- docs/source/config/details.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/config/details.rst b/docs/source/config/details.rst index 6bed3c68c91..d1392962440 100644 --- a/docs/source/config/details.rst +++ b/docs/source/config/details.rst @@ -77,6 +77,14 @@ by setting ``get_ipython().prompts`` to an *instance* of the class. In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to either the class object, or a string of its full importable name. +To include invisible terminal control sequences in a prompt, use +``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored +when calculating the width. + +Colours in the prompt are determined by the token types and the highlighting +style; see below for more details. The tokens used in the default prompts are +``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``. + .. _termcolour: Terminal Colors From 8489339b3ce0b7b8d15d0d2906018ecef36b46cc Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 10 Aug 2016 17:28:45 +0100 Subject: [PATCH 0596/4859] More whatsnew entries for 5.1 I've tried to stick to user-visible changes, so I haven't listed every PR. --- docs/source/whatsnew/version5.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 602ef0529b3..776c36959c0 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -13,6 +13,18 @@ IPython 5.1 * Deprecate ``IPtyhon.core.debugger.Tracer()`` in favor of simpler, newer, APIs. :ghpull:`9731` * Restore ``NoOpContext`` context manager removed by mistake, and add `DeprecationWarning`. :ghpull:`9765` * Add option allowing ``Prompt_toolkit`` to use 24bits colors. :ghpull:`9736` +* Fix for closing interactive matplotlib windows on OS X. :ghpull:`9854` +* An embedded interactive shell instance can be used more than once. :ghpull:`9843` +* More robust check for whether IPython is in a terminal. :ghpull:`9833` +* Better pretty-printing of dicts on PyPy. :ghpull:`9827` +* Some coloured output now looks better on dark background command prompts in Windows. + :ghpull:`9838` +* Improved tab completion of paths on Windows . :ghpull:`9826` +* Fix tkinter event loop integration on Python 2 with ``future`` installed. :ghpull:`9824` +* Restore ``Ctrl-\`` as a shortcut to quit IPython. +* Make ``get_ipython()`` accessible when modules are imported by startup files. :ghpull:`9818` +* Add support for running directories containing a ``__main__.py`` file with the + ``ipython`` command. :ghpull:`9813` True Color feature From 95d027469e8a48507f281cf1f766ab42ff7ed41b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Wed, 10 Aug 2016 17:54:16 +0100 Subject: [PATCH 0597/4859] Typo fix --- docs/source/whatsnew/version5.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/whatsnew/version5.rst b/docs/source/whatsnew/version5.rst index 776c36959c0..9cad5b11d6e 100644 --- a/docs/source/whatsnew/version5.rst +++ b/docs/source/whatsnew/version5.rst @@ -10,7 +10,7 @@ IPython 5.1 * Don't set terminal title by default. :ghpull:`9801` * Preserve indentation when inserting newlines with ``Ctrl-O``. :ghpull:`9770` * Restore completion in debugger. :ghpull:`9785` -* Deprecate ``IPtyhon.core.debugger.Tracer()`` in favor of simpler, newer, APIs. :ghpull:`9731` +* Deprecate ``IPython.core.debugger.Tracer()`` in favor of simpler, newer, APIs. :ghpull:`9731` * Restore ``NoOpContext`` context manager removed by mistake, and add `DeprecationWarning`. :ghpull:`9765` * Add option allowing ``Prompt_toolkit`` to use 24bits colors. :ghpull:`9736` * Fix for closing interactive matplotlib windows on OS X. :ghpull:`9854` From 0508cde1ec1078604d6c54e9b75c9d651875bdc3 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 11 Aug 2016 13:00:41 -0700 Subject: [PATCH 0598/4859] Handle all OTP authentication methods. Closes #9860 --- tools/gh_api.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/gh_api.py b/tools/gh_api.py index cac949c011c..a21506bdd97 100644 --- a/tools/gh_api.py +++ b/tools/gh_api.py @@ -66,13 +66,13 @@ def get_auth_token(): response = requests.post('https://api.github.com/authorizations', auth=(user, pw), data=json.dumps(auth_request)) if response.status_code == 401 and \ - response.headers.get('X-GitHub-OTP') == 'required; sms': - print("Your login API resquest a SMS one time password", file=sys.stderr) - sms_pw = getpass.getpass("SMS password: ", stream=sys.stderr) + 'required;' in response.headers.get('X-GitHub-OTP', ''): + print("Your login API requested a one time password", file=sys.stderr) + otp = getpass.getpass("One Time Password: ", stream=sys.stderr) response = requests.post('https://api.github.com/authorizations', auth=(user, pw), data=json.dumps(auth_request), - headers={'X-GitHub-OTP':sms_pw}) + headers={'X-GitHub-OTP':otp}) response.raise_for_status() token = json.loads(response.text)['token'] keyring.set_password('github', fake_username, token) From 19e942b48009bec7231a9ecddbe59c33600bdc27 Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Thu, 11 Aug 2016 15:48:42 -0700 Subject: [PATCH 0599/4859] Clean documentation process We don't push on ghpages anymore. --- docs/Makefile | 20 ------- docs/gh-pages.py | 135 ----------------------------------------------- 2 files changed, 155 deletions(-) delete mode 100755 docs/gh-pages.py diff --git a/docs/Makefile b/docs/Makefile index 46add14d882..a6546d08e19 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -29,7 +29,6 @@ help: @echo " info Texinfo files and run them through makeinfo" @echo " changes an overview over all changed/added/deprecated items" @echo " linkcheck check all external links for integrity (takes a long time)" - @echo " gh-pages clone IPython docs in ./gh-pages/ , build doc, autocommit" @echo @echo "Compound utility targets:" @echo "pdf latex and then runs the PDF generation" @@ -108,16 +107,6 @@ htmlhelp: @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in build/htmlhelp." -qthelp: - mkdir -p build/qthelp - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/IPython.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/IPython.qhc" - latex: api autoconfig mkdir -p build/latex build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex @@ -139,15 +128,6 @@ linkcheck: @echo "Link check complete; look for any errors in the above output " \ "or in build/linkcheck/output.rst." -nightly: dist - rsync -avH --delete dist/ ipython:www/doc/nightly - -gh-pages: clean html - # if VERSION is unspecified, it will be dev - # For releases, VERSION should be just the major version, - # e.g. VERSION=2 make gh-pages - $(PYTHON) gh-pages.py $(VERSION) - texinfo: mkdir -p $(BUILDDIR)/texinfo $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo diff --git a/docs/gh-pages.py b/docs/gh-pages.py deleted file mode 100755 index 2db0d3153c6..00000000000 --- a/docs/gh-pages.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python -"""Script to commit the doc build outputs into the github-pages repo. - -Use: - - gh-pages.py [tag] - -If no tag is given, the current output of 'git describe' is used. If given, -that is how the resulting directory will be named. - -In practice, you should use either actual clean tags from a current build or -something like 'current' as a stable URL for the most current version of the """ - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- -from __future__ import print_function - -import os -import shutil -import sys -from os import chdir as cd -from os.path import join as pjoin - -from subprocess import Popen, PIPE, CalledProcessError, check_call - -#----------------------------------------------------------------------------- -# Globals -#----------------------------------------------------------------------------- - -pages_dir = 'gh-pages' -html_dir = 'build/html' -pdf_dir = 'build/latex' -pages_repo = 'git@github.com:ipython/ipython-doc.git' - -#----------------------------------------------------------------------------- -# Functions -#----------------------------------------------------------------------------- -def sh(cmd): - """Execute command in a subshell, return status code.""" - return check_call(cmd, shell=True) - - -def sh2(cmd): - """Execute command in a subshell, return stdout. - - Stderr is unbuffered from the subshell.x""" - p = Popen(cmd, stdout=PIPE, shell=True) - out = p.communicate()[0] - retcode = p.returncode - if retcode: - raise CalledProcessError(retcode, cmd) - else: - return out.rstrip() - - -def sh3(cmd): - """Execute command in a subshell, return stdout, stderr - - If anything appears in stderr, print it out to sys.stderr""" - p = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True) - out, err = p.communicate() - retcode = p.returncode - if retcode: - raise CalledProcessError(retcode, cmd) - else: - return out.rstrip(), err.rstrip() - - -def init_repo(path): - """clone the gh-pages repo if we haven't already.""" - sh("git clone %s %s"%(pages_repo, path)) - here = os.getcwdu() - cd(path) - sh('git checkout gh-pages') - cd(here) - -#----------------------------------------------------------------------------- -# Script starts -#----------------------------------------------------------------------------- -if __name__ == '__main__': - # The tag can be given as a positional argument - try: - tag = sys.argv[1] - except IndexError: - tag = "dev" - - startdir = os.getcwdu() - if not os.path.exists(pages_dir): - # init the repo - init_repo(pages_dir) - else: - # ensure up-to-date before operating - cd(pages_dir) - sh('git checkout gh-pages') - sh('git pull') - cd(startdir) - - dest = pjoin(pages_dir, tag) - - # don't `make html` here, because gh-pages already depends on html in Makefile - # sh('make html') - if tag != 'dev': - # only build pdf for non-dev targets - #sh2('make pdf') - pass - - # This is pretty unforgiving: we unconditionally nuke the destination - # directory, and then copy the html tree in there - shutil.rmtree(dest, ignore_errors=True) - shutil.copytree(html_dir, dest) - if tag != 'dev': - #shutil.copy(pjoin(pdf_dir, 'ipython.pdf'), pjoin(dest, 'ipython.pdf')) - pass - - try: - cd(pages_dir) - branch = sh2('git rev-parse --abbrev-ref HEAD').strip() - if branch != 'gh-pages': - e = 'On %r, git branch is %r, MUST be "gh-pages"' % (pages_dir, - branch) - raise RuntimeError(e) - - sh('git add -A %s' % tag) - sh('git commit -m"Updated doc release: %s"' % tag) - print() - print('Most recent 3 commits:') - sys.stdout.flush() - sh('git --no-pager log --oneline HEAD~3..') - finally: - cd(startdir) - - print() - print('Now verify the build in: %r' % dest) - print("If everything looks good, 'git push'") From 4ad1eea41d602ec8546eca6f9beeec21f9f884da Mon Sep 17 00:00:00 2001 From: anantkaushik89 Date: Fri, 12 Aug 2016 11:42:41 +0530 Subject: [PATCH 0600/4859] 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 cc0d587c1f09bdaded208ec22432afb3e5555e5d Mon Sep 17 00:00:00 2001 From: Matthias Bussonnier Date: Fri, 12 Aug 2016 13:03:02 -0700 Subject: [PATCH 0601/4859] Remove most of the ipyparallel info in the documentation. --- docs/source/config/integrating.rst | 10 ++++--- docs/source/development/config.rst | 13 ++++----- docs/source/overview.rst | 45 ++---------------------------- 3 files changed, 13 insertions(+), 55 deletions(-) diff --git a/docs/source/config/integrating.rst b/docs/source/config/integrating.rst index 3630ae80da3..d1ae9d39c94 100644 --- a/docs/source/config/integrating.rst +++ b/docs/source/config/integrating.rst @@ -43,10 +43,12 @@ For example:: Custom exception tracebacks =========================== -Rarely, you might want to display a different traceback with an exception - -IPython's own parallel computing framework does this to display errors from the -engines. To do this, define a ``_render_traceback_(self)`` method which returns -a list of strings, each containing one line of the traceback. +Rarely, you might want to display a custom traceback when reporting an +exception. To do this, define the custom traceback using +`_render_traceback_(self)` method which returns a list of strings, one string +for each line of the traceback. For example, the `ipyparallel +`__ a parallel computing framework for +IPython, does this to display errors from multiple engines. Please be conservative in using this feature; by replacing the default traceback you may hide important information from the user. diff --git a/docs/source/development/config.rst b/docs/source/development/config.rst index c460e8d9b1d..32c341e1092 100644 --- a/docs/source/development/config.rst +++ b/docs/source/development/config.rst @@ -41,20 +41,17 @@ The next thing you need to know is what to call your configuration file. The basic idea is that each application has its own default configuration filename. The default named used by the :command:`ipython` command line program is :file:`ipython_config.py`, and *all* IPython applications will use this file. -Other applications, such as the parallel :command:`ipcluster` scripts or the -QtConsole will load their own config files *after* :file:`ipython_config.py`. To -load a particular configuration file instead of the default, the name can be -overridden by the ``config_file`` command line flag. +The IPython kernel will load its own config file *after* +:file:`ipython_config.py`. To load a particular configuration file instead of +the default, the name can be overridden by the ``config_file`` command line +flag. To generate the default configuration files, do:: $ ipython profile create and you will have a default :file:`ipython_config.py` in your IPython directory -under :file:`profile_default`. If you want the default config files for the -:mod:`IPython.parallel` applications, add ``--parallel`` to the end of the -command-line args. - +under :file:`profile_default`. .. note:: IPython configuration options are case sensitive, and IPython cannot diff --git a/docs/source/overview.rst b/docs/source/overview.rst index 55c54ee7736..ff39e169976 100644 --- a/docs/source/overview.rst +++ b/docs/source/overview.rst @@ -232,50 +232,9 @@ and clients. Interactive parallel computing ============================== -.. note:: - This functionality is optional and now part of the `ipyparallel - `_ project. - -Increasingly, parallel computer hardware, such as multicore CPUs, clusters and -supercomputers, is becoming ubiquitous. Over the last several years, we have -developed an architecture within IPython that allows such hardware to be used -quickly and easily from Python. Moreover, this architecture is designed to -support interactive and collaborative parallel computing. - -The main features of this system are: - -* Quickly parallelize Python code from an interactive Python/IPython session. - -* A flexible and dynamic process model that be deployed on anything from - multicore workstations to supercomputers. - -* An architecture that supports many different styles of parallelism, from - message passing to task farming. And all of these styles can be handled - interactively. - -* Both blocking and fully asynchronous interfaces. - -* High level APIs that enable many things to be parallelized in a few lines - of code. - -* Write parallel code that will run unchanged on everything from multicore - workstations to supercomputers. - -* Full integration with Message Passing libraries (MPI). - -* Capabilities based security model with full encryption of network connections. - -* Share live parallel jobs with other users securely. We call this - collaborative parallel computing. - -* Dynamically load balanced task farming system. - -* Robust error handling. Python exceptions raised in parallel execution are - gathered and presented to the top-level code. - -For more information, see our :ref:`overview ` of using IPython -for parallel computing. +This functionality is optional and now part of the `ipyparallel +`_ project. Portability and Python requirements ----------------------------------- From c6bcb2b93f1bea2349088b31b570fdfb78bf219f Mon Sep 17 00:00:00 2001 From: Hassan Kibirige Date: Fri, 12 Aug 2016 18:58:53 -0500 Subject: [PATCH 0602/4859] 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 49a2b8e7c1d84684b959d75896b3d76858a6bc90 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 13 Aug 2016 13:32:37 +0100 Subject: [PATCH 0603/4859] Don't use universal wheels Closes gh-9869 --- setup.cfg | 2 -- tools/toollib.py | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 setup.cfg diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 3c6e79cf31d..00000000000 --- a/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[bdist_wheel] -universal=1 diff --git a/tools/toollib.py b/tools/toollib.py index aeb0223cf35..ad71bd063a3 100644 --- a/tools/toollib.py +++ b/tools/toollib.py @@ -21,7 +21,8 @@ sdists = './setup.py sdist --formats=gztar,zip' # Binary dists def buildwheels(): - sh('python setupegg.py bdist_wheel') + for py in ('2', '3'): + sh('python%s setupegg.py bdist_wheel' % py) # Utility functions def sh(cmd): From 89a594350bb034b02ce19617124c1cc75c0de01b Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 13 Aug 2016 13:50:23 +0100 Subject: [PATCH 0604/4859] Add Github stats for 5.1 --- docs/source/whatsnew/github-stats-5.rst | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/source/whatsnew/github-stats-5.rst b/docs/source/whatsnew/github-stats-5.rst index 217bac540f6..fbd9b2860bd 100644 --- a/docs/source/whatsnew/github-stats-5.rst +++ b/docs/source/whatsnew/github-stats-5.rst @@ -3,6 +3,36 @@ Issues closed in the 5.x development cycle ========================================== +Issues closed in 5.1 +-------------------- + +GitHub stats for 2016/07/08 - 2016/08/13 (tag: 5.0.0) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 33 issues and merged 43 pull requests. +The full list can be seen `on GitHub `__ + +The following 17 authors contributed 129 commits. + +* Antony Lee +* Benjamin Ragan-Kelley +* Carol Willing +* Danilo J. S. Bellini +* 小明 (`dongweiming `__) +* Fernando Perez +* Gavin Cooper +* Gil Forsyth +* Jacob Niehus +* Julian Kuhlmann +* Matthias Bussonnier +* Michael Pacer +* Nik Nyby +* Pavol Juhas +* Luke Deen Taylor +* Thomas Kluyver +* Tamir Bahar + Issues closed in 5.0 -------------------- From 5c9c918bc0a11057184ec143da13b68994f59666 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 13 Aug 2016 13:54:18 +0100 Subject: [PATCH 0605/4859] Release 5.1.0 --- IPython/core/release.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IPython/core/release.py b/IPython/core/release.py index 9df73c235c6..a9beed34e09 100644 --- a/IPython/core/release.py +++ b/IPython/core/release.py @@ -24,7 +24,7 @@ _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 de84d5a44feb7cddfada8b1c5b5003d6453695f6 Mon Sep 17 00:00:00 2001 From: Thomas Kluyver Date: Sat, 13 Aug 2016 13:55:40 +0100 Subject: [PATCH 0606/4859] 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 0607/4859] 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 0608/4859] 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 0609/4859] 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 0610/4859] 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 0611/4859] 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 0612/4859] 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 0613/4859] 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 0614/4859] 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 0615/4859] 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 0616/4859] 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 0617/4859] 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 0618/4859] 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 0619/4859] 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 0620/4859] 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 0621/4859] 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 0622/4859] 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 0623/4859] 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 0624/4859] 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 0625/4859] 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 0626/4859] 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 0627/4859] 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 0628/4859] 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 0629/4859] 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 0630/4859] 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 0631/4859] 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 0632/4859] 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 0633/4859] 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 0634/4859] 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 0635/4859] 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 0636/4859] 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 0637/4859] 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 0638/4859] 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 0639/4859] 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 0640/4859] 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 0641/4859] 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 0642/4859] 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 0643/4859] 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 0644/4859] -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 0645/4859] 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 0646/4859] 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 0647/4859] 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 0648/4859] 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 0649/4859] 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 0650/4859] 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 0651/4859] 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 0652/4859] 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 0653/4859] 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 0654/4859] 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 0655/4859] 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 0656/4859] 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 0657/4859] 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 0658/4859] 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 0659/4859] 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 0660/4859] 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 0661/4859] 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 0662/4859] 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 0663/4859] 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 0664/4859] 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 0665/4859] 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 0666/4859] 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 0667/4859] 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 0668/4859] 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 0669/4859] 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 0670/4859] 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 0671/4859] 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 0672/4859] 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 0673/4859] 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 0674/4859] 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 0675/4859] 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 0676/4859] 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 0677/4859] 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 0678/4859] 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 0679/4859] 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 0680/4859] 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 0681/4859] 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 0682/4859] 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 0683/4859] 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 0684/4859] 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 0685/4859] 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 0686/4859] 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 0687/4859] 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 0688/4859] 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 0689/4859] 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 0690/4859] 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 0691/4859] 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 0692/4859] 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 = """