Show More
@@ -71,11 +71,10 b' from IPython.core.error import TryNext' | |||
|
71 | 71 | from IPython.core.inputsplitter import ESC_MAGIC |
|
72 | 72 | from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol |
|
73 | 73 | from IPython.utils import generics |
|
74 | from IPython.utils import io | |
|
75 | 74 | from IPython.utils.decorators import undoc |
|
76 | 75 | from IPython.utils.dir2 import dir2, get_real_method |
|
77 | 76 | from IPython.utils.process import arg_split |
|
78 | from IPython.utils.py3compat import builtin_mod, string_types, PY3 | |
|
77 | from IPython.utils.py3compat import builtin_mod, string_types, PY3, cast_unicode_py2 | |
|
79 | 78 | from traitlets import CBool, Enum |
|
80 | 79 | |
|
81 | 80 | try: |
@@ -201,6 +200,9 b' def completions_sorting_key(word):' | |||
|
201 | 200 | elif word.startswith('_'): |
|
202 | 201 | prio1 = 1 |
|
203 | 202 | |
|
203 | if word.endswith('='): | |
|
204 | prio1 = -1 | |
|
205 | ||
|
204 | 206 | if word.startswith('%%'): |
|
205 | 207 | # If there's another % in there, this is something else, so leave it alone |
|
206 | 208 | if not "%" in word[2:]: |
@@ -358,7 +360,7 b' class Completer(Configurable):' | |||
|
358 | 360 | for word in lst: |
|
359 | 361 | if word[:n] == text and word != "__builtins__": |
|
360 | 362 | match_append(word) |
|
361 | return matches | |
|
363 | return [cast_unicode_py2(m) for m in matches] | |
|
362 | 364 | |
|
363 | 365 | def attr_matches(self, text): |
|
364 | 366 | """Compute matches when text contains a dot. |
@@ -410,8 +412,7 b' class Completer(Configurable):' | |||
|
410 | 412 | pass |
|
411 | 413 | # Build match list to return |
|
412 | 414 | n = len(attr) |
|
413 |
re |
|
|
414 | return res | |
|
415 | return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ] | |
|
415 | 416 | |
|
416 | 417 | |
|
417 | 418 | def get__all__entries(obj): |
@@ -421,7 +422,7 b' def get__all__entries(obj):' | |||
|
421 | 422 | except: |
|
422 | 423 | return [] |
|
423 | 424 | |
|
424 | return [w for w in words if isinstance(w, string_types)] | |
|
425 | return [cast_unicode_py2(w) for w in words if isinstance(w, string_types)] | |
|
425 | 426 | |
|
426 | 427 | |
|
427 | 428 | def match_dict_keys(keys, prefix, delims): |
@@ -695,9 +696,9 b' class IPCompleter(Completer):' | |||
|
695 | 696 | # when escaped with backslash |
|
696 | 697 | if text.startswith('!'): |
|
697 | 698 | text = text[1:] |
|
698 | text_prefix = '!' | |
|
699 | text_prefix = u'!' | |
|
699 | 700 | else: |
|
700 | text_prefix = '' | |
|
701 | text_prefix = u'' | |
|
701 | 702 | |
|
702 | 703 | text_until_cursor = self.text_until_cursor |
|
703 | 704 | # track strings with open quotes |
@@ -728,7 +729,7 b' class IPCompleter(Completer):' | |||
|
728 | 729 | text = os.path.expanduser(text) |
|
729 | 730 | |
|
730 | 731 | if text == "": |
|
731 | return [text_prefix + protect_filename(f) for f in self.glob("*")] | |
|
732 | return [text_prefix + cast_unicode_py2(protect_filename(f)) for f in self.glob("*")] | |
|
732 | 733 | |
|
733 | 734 | # Compute the matches from the filesystem |
|
734 | 735 | m0 = self.clean_glob(text.replace('\\','')) |
@@ -751,8 +752,7 b' class IPCompleter(Completer):' | |||
|
751 | 752 | protect_filename(f) for f in m0] |
|
752 | 753 | |
|
753 | 754 | # Mark directories in input list by appending '/' to their names. |
|
754 |
|
|
|
755 | return matches | |
|
755 | return [cast_unicode_py2(x+'/') if os.path.isdir(x) else x for x in matches] | |
|
756 | 756 | |
|
757 | 757 | def magic_matches(self, text): |
|
758 | 758 | """Match magics""" |
@@ -773,7 +773,7 b' class IPCompleter(Completer):' | |||
|
773 | 773 | comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] |
|
774 | 774 | if not text.startswith(pre2): |
|
775 | 775 | comp += [ pre+m for m in line_magics if m.startswith(bare_text)] |
|
776 | return comp | |
|
776 | return [cast_unicode_py2(c) for c in comp] | |
|
777 | 777 | |
|
778 | 778 | def python_jedi_matches(self, text, line_buffer, cursor_pos): |
|
779 | 779 | """Match attributes or global Python names using Jedi.""" |
@@ -849,7 +849,6 b' class IPCompleter(Completer):' | |||
|
849 | 849 | matches = [] |
|
850 | 850 | else: |
|
851 | 851 | matches = self.global_matches(text) |
|
852 | ||
|
853 | 852 | return matches |
|
854 | 853 | |
|
855 | 854 | def _default_arguments_from_docstring(self, doc): |
@@ -978,7 +977,7 b' class IPCompleter(Completer):' | |||
|
978 | 977 | |
|
979 | 978 | for namedArg in namedArgs: |
|
980 | 979 | if namedArg.startswith(text): |
|
981 | argMatches.append("%s=" %namedArg) | |
|
980 | argMatches.append(u"%s=" %namedArg) | |
|
982 | 981 | return argMatches |
|
983 | 982 | |
|
984 | 983 | def dict_key_matches(self, text): |
@@ -1164,12 +1163,12 b' class IPCompleter(Completer):' | |||
|
1164 | 1163 | res = c(event) |
|
1165 | 1164 | if res: |
|
1166 | 1165 | # first, try case sensitive match |
|
1167 | withcase = [r for r in res if r.startswith(text)] | |
|
1166 | withcase = [cast_unicode_py2(r) for r in res if r.startswith(text)] | |
|
1168 | 1167 | if withcase: |
|
1169 | 1168 | return withcase |
|
1170 | 1169 | # if none, then case insensitive ones are ok too |
|
1171 | 1170 | text_low = text.lower() |
|
1172 | return [r for r in res if r.lower().startswith(text_low)] | |
|
1171 | return [cast_unicode_py2(r) for r in res if r.lower().startswith(text_low)] | |
|
1173 | 1172 | except TryNext: |
|
1174 | 1173 | pass |
|
1175 | 1174 |
@@ -944,7 +944,7 b' def format_display_data(obj, include=None, exclude=None):' | |||
|
944 | 944 | """ |
|
945 | 945 | from IPython.core.interactiveshell import InteractiveShell |
|
946 | 946 | |
|
947 | InteractiveShell.instance().display_formatter.format( | |
|
947 | return InteractiveShell.instance().display_formatter.format( | |
|
948 | 948 | obj, |
|
949 | 949 | include, |
|
950 | 950 | exclude |
@@ -1,18 +1,10 b'' | |||
|
1 | 1 | """ History related magics and functionality """ |
|
2 | #----------------------------------------------------------------------------- | |
|
3 | # Copyright (C) 2010-2011 The IPython Development Team. | |
|
4 | # | |
|
5 | # Distributed under the terms of the BSD License. | |
|
6 | # | |
|
7 | # The full license is in the file COPYING.txt, distributed with this software. | |
|
8 | #----------------------------------------------------------------------------- | |
|
9 | 2 | |
|
10 | #----------------------------------------------------------------------------- | |
|
11 | # Imports | |
|
12 | #----------------------------------------------------------------------------- | |
|
3 | # Copyright (c) IPython Development Team. | |
|
4 | # Distributed under the terms of the Modified BSD License. | |
|
5 | ||
|
13 | 6 | from __future__ import print_function |
|
14 | 7 | |
|
15 | # Stdlib imports | |
|
16 | 8 | import atexit |
|
17 | 9 | import datetime |
|
18 | 10 | import os |
@@ -26,7 +18,6 b' except ImportError:' | |||
|
26 | 18 | sqlite3 = None |
|
27 | 19 | import threading |
|
28 | 20 | |
|
29 | # Our own packages | |
|
30 | 21 | from traitlets.config.configurable import LoggingConfigurable |
|
31 | 22 | from decorator import decorator |
|
32 | 23 | from IPython.utils.decorators import undoc |
@@ -80,27 +71,52 b' else:' | |||
|
80 | 71 | class OperationalError(Exception): |
|
81 | 72 | "Dummy exception when sqlite could not be imported. Should never occur." |
|
82 | 73 | |
|
74 | # use 16kB as threshold for whether a corrupt history db should be saved | |
|
75 | # that should be at least 100 entries or so | |
|
76 | _SAVE_DB_SIZE = 16384 | |
|
77 | ||
|
83 | 78 | @decorator |
|
84 | 79 | def catch_corrupt_db(f, self, *a, **kw): |
|
85 | 80 | """A decorator which wraps HistoryAccessor method calls to catch errors from |
|
86 | 81 | a corrupt SQLite database, move the old database out of the way, and create |
|
87 | 82 | a new one. |
|
83 | ||
|
84 | We avoid clobbering larger databases because this may be triggered due to filesystem issues, | |
|
85 | not just a corrupt file. | |
|
88 | 86 | """ |
|
89 | 87 | try: |
|
90 | 88 | return f(self, *a, **kw) |
|
91 | except (DatabaseError, OperationalError): | |
|
92 | if os.path.isfile(self.hist_file): | |
|
93 | # Try to move the file out of the way | |
|
94 | base,ext = os.path.splitext(self.hist_file) | |
|
95 | newpath = base + '-corrupt' + ext | |
|
96 |
|
|
|
89 | except (DatabaseError, OperationalError) as e: | |
|
90 | self._corrupt_db_counter += 1 | |
|
91 | self.log.error("Failed to open SQLite history %s (%s).", self.hist_file, e) | |
|
92 | if self.hist_file != ':memory:': | |
|
93 | if self._corrupt_db_counter > self._corrupt_db_limit: | |
|
94 | self.hist_file = ':memory:' | |
|
95 | self.log.error("Failed to load history too many times, history will not be saved.") | |
|
96 | elif os.path.isfile(self.hist_file): | |
|
97 | # move the file out of the way | |
|
98 | base, ext = os.path.splitext(self.hist_file) | |
|
99 | size = os.stat(self.hist_file).st_size | |
|
100 | if size >= _SAVE_DB_SIZE: | |
|
101 | # if there's significant content, avoid clobbering | |
|
102 | now = datetime.datetime.now().isoformat().replace(':', '.') | |
|
103 | newpath = base + '-corrupt-' + now + ext | |
|
104 | # don't clobber previous corrupt backups | |
|
105 | for i in range(100): | |
|
106 | if not os.path.isfile(newpath): | |
|
107 | break | |
|
108 | else: | |
|
109 | newpath = base + '-corrupt-' + now + (u'-%i' % i) + ext | |
|
110 | else: | |
|
111 | # not much content, possibly empty; don't worry about clobbering | |
|
112 | # maybe we should just delete it? | |
|
113 | newpath = base + '-corrupt' + ext | |
|
114 | os.rename(self.hist_file, newpath) | |
|
115 | self.log.error("History file was moved to %s and a new file created.", newpath) | |
|
97 | 116 | self.init_db() |
|
98 | print("ERROR! History file wasn't a valid SQLite database.", | |
|
99 | "It was moved to %s" % newpath, "and a new file created.") | |
|
100 | 117 | return [] |
|
101 | ||
|
102 | 118 | else: |
|
103 |
# |
|
|
119 | # Failed with :memory:, something serious is wrong | |
|
104 | 120 | raise |
|
105 | 121 | |
|
106 | 122 | class HistoryAccessorBase(LoggingConfigurable): |
@@ -126,6 +142,11 b' class HistoryAccessor(HistoryAccessorBase):' | |||
|
126 | 142 | This is intended for use by standalone history tools. IPython shells use |
|
127 | 143 | HistoryManager, below, which is a subclass of this.""" |
|
128 | 144 | |
|
145 | # counter for init_db retries, so we don't keep trying over and over | |
|
146 | _corrupt_db_counter = 0 | |
|
147 | # after two failures, fallback on :memory: | |
|
148 | _corrupt_db_limit = 2 | |
|
149 | ||
|
129 | 150 | # String holding the path to the history file |
|
130 | 151 | hist_file = Unicode(config=True, |
|
131 | 152 | help="""Path to file to use for SQLite history database. |
@@ -239,6 +260,8 b' class HistoryAccessor(HistoryAccessorBase):' | |||
|
239 | 260 | (session integer, line integer, output text, |
|
240 | 261 | PRIMARY KEY (session, line))""") |
|
241 | 262 | self.db.commit() |
|
263 | # success! reset corrupt db count | |
|
264 | self._corrupt_db_counter = 0 | |
|
242 | 265 | |
|
243 | 266 | def writeout_cache(self): |
|
244 | 267 | """Overridden by HistoryManager to dump the cache before certain |
@@ -57,7 +57,7 b' from IPython.core.prefilter import PrefilterManager' | |||
|
57 | 57 | from IPython.core.profiledir import ProfileDir |
|
58 | 58 | from IPython.core.prompts import PromptManager |
|
59 | 59 | from IPython.core.usage import default_banner |
|
60 | from IPython.testing.skipdoctest import skip_doctest | |
|
60 | from IPython.testing.skipdoctest import skip_doctest_py2, skip_doctest | |
|
61 | 61 | from IPython.utils import PyColorize |
|
62 | 62 | from IPython.utils import io |
|
63 | 63 | from IPython.utils import py3compat |
@@ -1939,6 +1939,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
1939 | 1939 | self.set_hook('complete_command', reset_completer, str_key = '%reset') |
|
1940 | 1940 | |
|
1941 | 1941 | |
|
1942 | @skip_doctest_py2 | |
|
1942 | 1943 | def complete(self, text, line=None, cursor_pos=None): |
|
1943 | 1944 | """Return the completed text and a list of completions. |
|
1944 | 1945 |
@@ -61,12 +61,12 b' class TimeitResult(object):' | |||
|
61 | 61 | """ |
|
62 | 62 | Object returned by the timeit magic with info about the run. |
|
63 | 63 | |
|
64 | Contain the following attributes : | |
|
64 | Contains the following attributes : | |
|
65 | 65 | |
|
66 | loops: (int) number of loop done per measurement | |
|
67 | repeat: (int) number of time the mesurement has been repeated | |
|
68 |
best: (float) best execu |
|
|
69 |
all_runs: (list of float) execu |
|
|
66 | loops: (int) number of loops done per measurement | |
|
67 | repeat: (int) number of times the measurement has been repeated | |
|
68 | best: (float) best execution time / number | |
|
69 | all_runs: (list of float) execution time of each run (in s) | |
|
70 | 70 | compile_time: (float) time of statement compilation (s) |
|
71 | 71 | |
|
72 | 72 | """ |
@@ -298,7 +298,7 b' def get_pager_cmd(pager_cmd=None):' | |||
|
298 | 298 | Makes some attempts at finding an OS-correct one. |
|
299 | 299 | """ |
|
300 | 300 | if os.name == 'posix': |
|
301 |
default_pager_cmd = 'less - |
|
|
301 | default_pager_cmd = 'less -R' # -R for color control sequences | |
|
302 | 302 | elif os.name in ['nt','dos']: |
|
303 | 303 | default_pager_cmd = 'type' |
|
304 | 304 | |
@@ -308,8 +308,8 b' def get_pager_cmd(pager_cmd=None):' | |||
|
308 | 308 | except: |
|
309 | 309 | pager_cmd = default_pager_cmd |
|
310 | 310 | |
|
311 | if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): | |
|
312 |
pager_cmd += ' - |
|
|
311 | if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower(): | |
|
312 | pager_cmd += ' -R' | |
|
313 | 313 | |
|
314 | 314 | return pager_cmd |
|
315 | 315 |
@@ -790,6 +790,7 b' def test_nested_import_module_completer():' | |||
|
790 | 790 | _, matches = ip.complete(None, 'import IPython.co', 17) |
|
791 | 791 | nt.assert_in('IPython.core', matches) |
|
792 | 792 | nt.assert_not_in('import IPython.core', matches) |
|
793 | nt.assert_not_in('IPython.display', matches) | |
|
793 | 794 | |
|
794 | 795 | def test_import_module_completer(): |
|
795 | 796 | ip = get_ipython() |
@@ -99,6 +99,21 b' class NonAsciiTest(unittest.TestCase):' | |||
|
99 | 99 | with tt.AssertPrints("ZeroDivisionError"): |
|
100 | 100 | with tt.AssertPrints(u'дбИЖ', suppress=False): |
|
101 | 101 | ip.run_cell('fail()') |
|
102 | ||
|
103 | def test_nonascii_msg(self): | |
|
104 | cell = u"raise Exception('é')" | |
|
105 | expected = u"Exception('é')" | |
|
106 | ip.run_cell("%xmode plain") | |
|
107 | with tt.AssertPrints(expected): | |
|
108 | ip.run_cell(cell) | |
|
109 | ||
|
110 | ip.run_cell("%xmode verbose") | |
|
111 | with tt.AssertPrints(expected): | |
|
112 | ip.run_cell(cell) | |
|
113 | ||
|
114 | ip.run_cell("%xmode context") | |
|
115 | with tt.AssertPrints(expected): | |
|
116 | ip.run_cell(cell) | |
|
102 | 117 | |
|
103 | 118 | |
|
104 | 119 | class NestedGenExprTestCase(unittest.TestCase): |
@@ -709,10 +709,10 b' class ListTB(TBTools):' | |||
|
709 | 709 | have_filedata = False |
|
710 | 710 | Colors = self.Colors |
|
711 | 711 | list = [] |
|
712 | stype = Colors.excName + etype.__name__ + Colors.Normal | |
|
712 | stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal) | |
|
713 | 713 | if value is None: |
|
714 | 714 | # Not sure if this can still happen in Python 2.6 and above |
|
715 |
list.append( |
|
|
715 | list.append(stype + '\n') | |
|
716 | 716 | else: |
|
717 | 717 | if issubclass(etype, SyntaxError): |
|
718 | 718 | have_filedata = True |
@@ -752,10 +752,10 b' class ListTB(TBTools):' | |||
|
752 | 752 | except Exception: |
|
753 | 753 | s = self._some_str(value) |
|
754 | 754 | if s: |
|
755 |
list.append('%s%s:%s %s\n' % ( |
|
|
755 | list.append('%s%s:%s %s\n' % (stype, Colors.excName, | |
|
756 | 756 | Colors.Normal, s)) |
|
757 | 757 | else: |
|
758 |
list.append('%s\n' % |
|
|
758 | list.append('%s\n' % stype) | |
|
759 | 759 | |
|
760 | 760 | # sync with user hooks |
|
761 | 761 | if have_filedata: |
@@ -793,9 +793,9 b' class ListTB(TBTools):' | |||
|
793 | 793 | def _some_str(self, value): |
|
794 | 794 | # Lifted from traceback.py |
|
795 | 795 | try: |
|
796 | return str(value) | |
|
796 | return py3compat.cast_unicode(str(value)) | |
|
797 | 797 | except: |
|
798 | return '<unprintable %s object>' % type(value).__name__ | |
|
798 | return u'<unprintable %s object>' % type(value).__name__ | |
|
799 | 799 | |
|
800 | 800 | |
|
801 | 801 | #---------------------------------------------------------------------------- |
@@ -1432,6 +1432,7 b' class SyntaxTB(ListTB):' | |||
|
1432 | 1432 | newtext = ulinecache.getline(value.filename, value.lineno) |
|
1433 | 1433 | if newtext: |
|
1434 | 1434 | value.text = newtext |
|
1435 | self.last_syntax_error = value | |
|
1435 | 1436 | return super(SyntaxTB, self).structured_traceback(etype, value, elist, |
|
1436 | 1437 | tb_offset=tb_offset, context=context) |
|
1437 | 1438 |
@@ -41,7 +41,7 b' class Audio(DisplayObject):' | |||
|
41 | 41 | filename : unicode |
|
42 | 42 | Path to a local file to load the data from. |
|
43 | 43 | embed : boolean |
|
44 |
Should the |
|
|
44 | Should the audio data be embedded using a data URI (True) or should | |
|
45 | 45 | the original source be referenced. Set this to True if you want the |
|
46 | 46 | audio to playable later with no internet connection in the notebook. |
|
47 | 47 |
@@ -15,7 +15,7 b' from IPython.core import ultratb, compilerop' | |||
|
15 | 15 | from IPython.core.magic import Magics, magics_class, line_magic |
|
16 | 16 | from IPython.core.interactiveshell import DummyMod |
|
17 | 17 | from IPython.core.interactiveshell import InteractiveShell |
|
18 |
from IPython.terminal. |
|
|
18 | from IPython.terminal.ptshell import TerminalInteractiveShell | |
|
19 | 19 | from IPython.terminal.ipapp import load_default_config |
|
20 | 20 | |
|
21 | 21 | from traitlets import Bool, CBool, Unicode |
@@ -136,6 +136,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||
|
136 | 136 | else: |
|
137 | 137 | self.old_banner2 = '' |
|
138 | 138 | |
|
139 | if self.display_banner: | |
|
140 | self.show_banner() | |
|
141 | ||
|
139 | 142 | # Call the embedding code with a stack depth of 1 so it can skip over |
|
140 | 143 | # our call and get the original caller's namespaces. |
|
141 | 144 | self.mainloop(local_ns, module, stack_depth=stack_depth, |
@@ -182,6 +185,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||
|
182 | 185 | module = DummyMod() |
|
183 | 186 | module.__dict__ = global_ns |
|
184 | 187 | |
|
188 | if (display_banner is not None): | |
|
189 | warnings.warn("The display_banner parameter is deprecated.", DeprecationWarning) | |
|
190 | ||
|
185 | 191 | # Get locals and globals from caller |
|
186 | 192 | if ((local_ns is None or module is None or compile_flags is None) |
|
187 | 193 | and self.default_user_namespaces): |
@@ -191,7 +197,14 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||
|
191 | 197 | local_ns = call_frame.f_locals |
|
192 | 198 | if module is None: |
|
193 | 199 | global_ns = call_frame.f_globals |
|
194 | module = sys.modules[global_ns['__name__']] | |
|
200 | try: | |
|
201 | module = sys.modules[global_ns['__name__']] | |
|
202 | except KeyError: | |
|
203 | warnings.warn("Failed to get module %s" % \ | |
|
204 | global_ns.get('__name__', 'unknown module') | |
|
205 | ) | |
|
206 | module = DummyMod() | |
|
207 | module.__dict__ = global_ns | |
|
195 | 208 | if compile_flags is None: |
|
196 | 209 | compile_flags = (call_frame.f_code.co_flags & |
|
197 | 210 | compilerop.PyCF_MASK) |
@@ -226,7 +239,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||
|
226 | 239 | self.set_completer_frame() |
|
227 | 240 | |
|
228 | 241 | with self.builtin_trap, self.display_trap: |
|
229 |
self.interact( |
|
|
242 | self.interact() | |
|
230 | 243 | |
|
231 | 244 | # now, purge out the local namespace of IPython's hidden variables. |
|
232 | 245 | if local_ns is not None: |
@@ -4,18 +4,22 b' from __future__ import print_function' | |||
|
4 | 4 | import os |
|
5 | 5 | import sys |
|
6 | 6 | import signal |
|
7 | import unicodedata | |
|
8 | from warnings import warn | |
|
9 | from wcwidth import wcwidth | |
|
7 | 10 | |
|
11 | from IPython.core.error import TryNext | |
|
8 | 12 | from IPython.core.interactiveshell import InteractiveShell |
|
9 | 13 | from IPython.utils.py3compat import PY3, cast_unicode_py2, input |
|
10 | 14 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
|
11 | 15 | from IPython.utils.process import abbrev_cwd |
|
12 | from traitlets import Bool, Unicode, Dict | |
|
16 | from traitlets import Bool, CBool, Unicode, Dict, Integer | |
|
13 | 17 | |
|
14 | 18 | from prompt_toolkit.completion import Completer, Completion |
|
15 | from prompt_toolkit.enums import DEFAULT_BUFFER | |
|
19 | from prompt_toolkit.enums import DEFAULT_BUFFER, SEARCH_BUFFER | |
|
16 | 20 | from prompt_toolkit.filters import HasFocus, HasSelection, Condition |
|
17 | 21 | from prompt_toolkit.history import InMemoryHistory |
|
18 | from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop | |
|
22 | from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout | |
|
19 | 23 | from prompt_toolkit.interface import CommandLineInterface |
|
20 | 24 | from prompt_toolkit.key_binding.manager import KeyBindingManager |
|
21 | 25 | from prompt_toolkit.key_binding.vi_state import InputMode |
@@ -23,9 +27,9 b' from prompt_toolkit.key_binding.bindings.vi import ViStateFilter' | |||
|
23 | 27 | from prompt_toolkit.keys import Keys |
|
24 | 28 | from prompt_toolkit.layout.lexers import Lexer |
|
25 | 29 | from prompt_toolkit.layout.lexers import PygmentsLexer |
|
26 | from prompt_toolkit.styles import PygmentsStyle | |
|
30 | from prompt_toolkit.styles import PygmentsStyle, DynamicStyle | |
|
27 | 31 | |
|
28 | from pygments.styles import get_style_by_name | |
|
32 | from pygments.styles import get_style_by_name, get_all_styles | |
|
29 | 33 | from pygments.lexers import Python3Lexer, BashLexer, PythonLexer |
|
30 | 34 | from pygments.token import Token |
|
31 | 35 | |
@@ -33,7 +37,6 b' from .pt_inputhooks import get_inputhook_func' | |||
|
33 | 37 | from .interactiveshell import get_default_editor, TerminalMagics |
|
34 | 38 | |
|
35 | 39 | |
|
36 | ||
|
37 | 40 | class IPythonPTCompleter(Completer): |
|
38 | 41 | """Adaptor to provide IPython completions to prompt_toolkit""" |
|
39 | 42 | def __init__(self, ipy_completer): |
@@ -49,6 +52,22 b' class IPythonPTCompleter(Completer):' | |||
|
49 | 52 | ) |
|
50 | 53 | start_pos = -len(used) |
|
51 | 54 | for m in matches: |
|
55 | m = unicodedata.normalize('NFC', m) | |
|
56 | ||
|
57 | # When the first character of the completion has a zero length, | |
|
58 | # then it's probably a decomposed unicode character. E.g. caused by | |
|
59 | # the "\dot" completion. Try to compose again with the previous | |
|
60 | # character. | |
|
61 | if wcwidth(m[0]) == 0: | |
|
62 | if document.cursor_position + start_pos > 0: | |
|
63 | char_before = document.text[document.cursor_position + start_pos - 1] | |
|
64 | m = unicodedata.normalize('NFC', char_before + m) | |
|
65 | ||
|
66 | # Yield the modified completion instead, if this worked. | |
|
67 | if wcwidth(m[0:1]) == 1: | |
|
68 | yield Completion(m, start_position=start_pos - 1) | |
|
69 | continue | |
|
70 | ||
|
52 | 71 | # TODO: Use Jedi to determine meta_text |
|
53 | 72 | # (Jedi currently has a bug that results in incorrect information.) |
|
54 | 73 | # meta_text = '' |
@@ -74,8 +93,23 b' class IPythonPTLexer(Lexer):' | |||
|
74 | 93 | class TerminalInteractiveShell(InteractiveShell): |
|
75 | 94 | colors_force = True |
|
76 | 95 | |
|
96 | space_for_menu = Integer(6, config=True, help='Number of line at the bottom of the screen ' | |
|
97 | 'to reserve for the completion menu') | |
|
98 | ||
|
99 | def _space_for_menu_changed(self, old, new): | |
|
100 | self._update_layout() | |
|
101 | ||
|
77 | 102 | pt_cli = None |
|
78 | 103 | |
|
104 | autoedit_syntax = CBool(False, config=True, | |
|
105 | help="auto editing of files with syntax errors.") | |
|
106 | ||
|
107 | confirm_exit = CBool(True, config=True, | |
|
108 | help=""" | |
|
109 | Set to confirm when you try to exit IPython with an EOF (Control-D | |
|
110 | in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', | |
|
111 | you can force a direct exit without any confirmation.""", | |
|
112 | ) | |
|
79 | 113 | vi_mode = Bool(False, config=True, |
|
80 | 114 | help="Use vi style keybindings at the prompt", |
|
81 | 115 | ) |
@@ -84,10 +118,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
84 | 118 | help="Enable mouse support in the prompt" |
|
85 | 119 | ) |
|
86 | 120 | |
|
87 | highlighting_style = Unicode('', config=True, | |
|
88 | help="The name of a Pygments style to use for syntax highlighting" | |
|
121 | highlighting_style = Unicode('default', config=True, | |
|
122 | help="The name of a Pygments style to use for syntax highlighting: \n %s" % ', '.join(get_all_styles()) | |
|
89 | 123 | ) |
|
90 | 124 | |
|
125 | def _highlighting_style_changed(self, old, new): | |
|
126 | self._style = self._make_style_from_name(self.highlighting_style) | |
|
127 | ||
|
91 | 128 | highlighting_style_overrides = Dict(config=True, |
|
92 | 129 | help="Override highlighting format for specific tokens" |
|
93 | 130 | ) |
@@ -158,6 +195,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
158 | 195 | def _(event): |
|
159 | 196 | event.current_buffer.reset() |
|
160 | 197 | |
|
198 | @kbmanager.registry.add_binding(Keys.ControlC, filter=HasFocus(SEARCH_BUFFER)) | |
|
199 | def _(event): | |
|
200 | if event.current_buffer.document.text: | |
|
201 | event.current_buffer.reset() | |
|
202 | else: | |
|
203 | event.cli.push_focus(DEFAULT_BUFFER) | |
|
204 | ||
|
161 | 205 | supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) |
|
162 | 206 | |
|
163 | 207 | @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) |
@@ -189,13 +233,33 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
189 | 233 | if cell and (cell != last_cell): |
|
190 | 234 | history.append(cell) |
|
191 | 235 | |
|
236 | self._style = self._make_style_from_name(self.highlighting_style) | |
|
237 | style = DynamicStyle(lambda: self._style) | |
|
238 | ||
|
239 | self._app = create_prompt_application( | |
|
240 | key_bindings_registry=kbmanager.registry, | |
|
241 | history=history, | |
|
242 | completer=IPythonPTCompleter(self.Completer), | |
|
243 | enable_history_search=True, | |
|
244 | style=style, | |
|
245 | mouse_support=self.mouse_support, | |
|
246 | **self._layout_options() | |
|
247 | ) | |
|
248 | self.pt_cli = CommandLineInterface(self._app, | |
|
249 | eventloop=create_eventloop(self.inputhook)) | |
|
250 | ||
|
251 | def _make_style_from_name(self, name): | |
|
252 | """ | |
|
253 | Small wrapper that make an IPython compatible style from a style name | |
|
254 | ||
|
255 | We need that to add style for prompt ... etc. | |
|
256 | """ | |
|
257 | style_cls = get_style_by_name(name) | |
|
192 | 258 | style_overrides = { |
|
193 | 259 | Token.Prompt: '#009900', |
|
194 | 260 | Token.PromptNum: '#00ff00 bold', |
|
195 | 261 | } |
|
196 | if self.highlighting_style: | |
|
197 | style_cls = get_style_by_name(self.highlighting_style) | |
|
198 | else: | |
|
262 | if name is 'default': | |
|
199 | 263 | style_cls = get_style_by_name('default') |
|
200 | 264 | # The default theme needs to be visible on both a dark background |
|
201 | 265 | # and a light background, because we can't tell what the terminal |
@@ -212,21 +276,27 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
212 | 276 | style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, |
|
213 | 277 | style_dict=style_overrides) |
|
214 | 278 | |
|
215 | app = create_prompt_application(multiline=True, | |
|
216 | lexer=IPythonPTLexer(), | |
|
217 | get_prompt_tokens=self.get_prompt_tokens, | |
|
218 | get_continuation_tokens=self.get_continuation_tokens, | |
|
219 | key_bindings_registry=kbmanager.registry, | |
|
220 | history=history, | |
|
221 | completer=IPythonPTCompleter(self.Completer), | |
|
222 | enable_history_search=True, | |
|
223 | style=style, | |
|
224 | mouse_support=self.mouse_support, | |
|
225 | reserve_space_for_menu=6, | |
|
226 | ) | |
|
279 | return style | |
|
280 | ||
|
281 | def _layout_options(self): | |
|
282 | """ | |
|
283 | Return the current layout option for the current Terminal InteractiveShell | |
|
284 | """ | |
|
285 | return { | |
|
286 | 'lexer':IPythonPTLexer(), | |
|
287 | 'reserve_space_for_menu':self.space_for_menu, | |
|
288 | 'get_prompt_tokens':self.get_prompt_tokens, | |
|
289 | 'get_continuation_tokens':self.get_continuation_tokens, | |
|
290 | 'multiline':True, | |
|
291 | } | |
|
227 | 292 | |
|
228 | self.pt_cli = CommandLineInterface(app, | |
|
229 | eventloop=create_eventloop(self.inputhook)) | |
|
293 | ||
|
294 | def _update_layout(self): | |
|
295 | """ | |
|
296 | Ask for a re computation of the application layout, if for example , | |
|
297 | some configuration options have changed. | |
|
298 | """ | |
|
299 | self._app.layout = create_prompt_layout(**self._layout_options()) | |
|
230 | 300 | |
|
231 | 301 | def prompt_for_code(self): |
|
232 | 302 | document = self.pt_cli.run(pre_run=self.pre_prompt) |
@@ -286,12 +356,15 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
286 | 356 | try: |
|
287 | 357 | code = self.prompt_for_code() |
|
288 | 358 | except EOFError: |
|
289 | if self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): | |
|
359 | if (not self.confirm_exit) \ | |
|
360 | or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): | |
|
290 | 361 | self.ask_exit() |
|
291 | 362 | |
|
292 | 363 | else: |
|
293 | 364 | if code: |
|
294 | 365 | self.run_cell(code, store_history=True) |
|
366 | if self.autoedit_syntax and self.SyntaxTB.last_syntax_error: | |
|
367 | self.edit_syntax_error() | |
|
295 | 368 | |
|
296 | 369 | def mainloop(self): |
|
297 | 370 | # An extra layer of protection in case someone mashing Ctrl-C breaks |
@@ -314,5 +387,69 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
314 | 387 | else: |
|
315 | 388 | self._inputhook = None |
|
316 | 389 | |
|
390 | # Methods to support auto-editing of SyntaxErrors: | |
|
391 | ||
|
392 | def edit_syntax_error(self): | |
|
393 | """The bottom half of the syntax error handler called in the main loop. | |
|
394 | ||
|
395 | Loop until syntax error is fixed or user cancels. | |
|
396 | """ | |
|
397 | ||
|
398 | while self.SyntaxTB.last_syntax_error: | |
|
399 | # copy and clear last_syntax_error | |
|
400 | err = self.SyntaxTB.clear_err_state() | |
|
401 | if not self._should_recompile(err): | |
|
402 | return | |
|
403 | try: | |
|
404 | # may set last_syntax_error again if a SyntaxError is raised | |
|
405 | self.safe_execfile(err.filename, self.user_ns) | |
|
406 | except: | |
|
407 | self.showtraceback() | |
|
408 | else: | |
|
409 | try: | |
|
410 | with open(err.filename) as f: | |
|
411 | # This should be inside a display_trap block and I | |
|
412 | # think it is. | |
|
413 | sys.displayhook(f.read()) | |
|
414 | except: | |
|
415 | self.showtraceback() | |
|
416 | ||
|
417 | def _should_recompile(self, e): | |
|
418 | """Utility routine for edit_syntax_error""" | |
|
419 | ||
|
420 | if e.filename in ('<ipython console>', '<input>', '<string>', | |
|
421 | '<console>', '<BackgroundJob compilation>', | |
|
422 | None): | |
|
423 | return False | |
|
424 | try: | |
|
425 | if (self.autoedit_syntax and | |
|
426 | not self.ask_yes_no( | |
|
427 | 'Return to editor to correct syntax error? ' | |
|
428 | '[Y/n] ', 'y')): | |
|
429 | return False | |
|
430 | except EOFError: | |
|
431 | return False | |
|
432 | ||
|
433 | def int0(x): | |
|
434 | try: | |
|
435 | return int(x) | |
|
436 | except TypeError: | |
|
437 | return 0 | |
|
438 | ||
|
439 | # always pass integer line and offset values to editor hook | |
|
440 | try: | |
|
441 | self.hooks.fix_error_editor(e.filename, | |
|
442 | int0(e.lineno), int0(e.offset), | |
|
443 | e.msg) | |
|
444 | except TryNext: | |
|
445 | warn('Could not open editor') | |
|
446 | return False | |
|
447 | return True | |
|
448 | ||
|
449 | # Run !system commands directly, not through pipes, so terminal programs | |
|
450 | # work correctly. | |
|
451 | system = InteractiveShell.system_raw | |
|
452 | ||
|
453 | ||
|
317 | 454 | if __name__ == '__main__': |
|
318 | 455 | TerminalInteractiveShell.instance().interact() |
@@ -25,8 +25,6 b' import logging' | |||
|
25 | 25 | import os |
|
26 | 26 | import re |
|
27 | 27 | import sys |
|
28 | import traceback | |
|
29 | import unittest | |
|
30 | 28 | |
|
31 | 29 | from testpath import modified_env |
|
32 | 30 | |
@@ -41,10 +39,9 b' from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,' | |||
|
41 | 39 | linecache) |
|
42 | 40 | |
|
43 | 41 | # Third-party modules |
|
44 | import nose.core | |
|
45 | 42 | |
|
46 | 43 | from nose.plugins import doctests, Plugin |
|
47 |
from nose.util import anyp, |
|
|
44 | from nose.util import anyp, tolist | |
|
48 | 45 | |
|
49 | 46 | # Our own imports |
|
50 | 47 | from IPython.utils.py3compat import builtin_mod, PY3, getcwd |
@@ -143,7 +140,7 b' class DocTestFinder(doctest.DocTestFinder):' | |||
|
143 | 140 | # doctests in extension modules. |
|
144 | 141 | |
|
145 | 142 | # Local shorthands |
|
146 |
from inspect import isroutine, isclass |
|
|
143 | from inspect import isroutine, isclass | |
|
147 | 144 | |
|
148 | 145 | # Look for tests in a module's contained objects. |
|
149 | 146 | if inspect.ismodule(obj) and self._recurse: |
@@ -36,3 +36,8 b' def skip_doctest_py3(f):' | |||
|
36 | 36 | """Decorator - skip the doctest under Python 3.""" |
|
37 | 37 | f.skip_doctest = (sys.version_info[0] >= 3) |
|
38 | 38 | return f |
|
39 | ||
|
40 | def skip_doctest_py2(f): | |
|
41 | """Decorator - skip the doctest under Python 3.""" | |
|
42 | f.skip_doctest = (sys.version_info[0] < 3) | |
|
43 | return f |
@@ -9,22 +9,18 b' Authors:' | |||
|
9 | 9 | * Alexander Belchenko (e-mail: bialix AT ukr.net) |
|
10 | 10 | """ |
|
11 | 11 | |
|
12 | #----------------------------------------------------------------------------- | |
|
13 | # Copyright (C) 2008-2011 The IPython Development Team | |
|
14 | # | |
|
15 | # Distributed under the terms of the BSD License. The full license is in | |
|
16 | # the file COPYING, distributed as part of this software. | |
|
17 | #----------------------------------------------------------------------------- | |
|
18 | ||
|
19 | #----------------------------------------------------------------------------- | |
|
20 | # Imports | |
|
21 | #----------------------------------------------------------------------------- | |
|
12 | # Copyright (c) IPython Development Team. | |
|
13 | # Distributed under the terms of the Modified BSD License. | |
|
22 | 14 | |
|
23 | 15 | import os |
|
24 | 16 | import struct |
|
25 | 17 | import sys |
|
26 | 18 | import warnings |
|
27 | import backports.shutil_get_terminal_size | |
|
19 | try: | |
|
20 | from shutil import get_terminal_size as _get_terminal_size | |
|
21 | except ImportError: | |
|
22 | # use backport on Python 2 | |
|
23 | from backports.shutil_get_terminal_size import get_terminal_size as _get_terminal_size | |
|
28 | 24 | |
|
29 | 25 | from . import py3compat |
|
30 | 26 | |
@@ -122,4 +118,4 b' def freeze_term_title():' | |||
|
122 | 118 | |
|
123 | 119 | |
|
124 | 120 | def get_terminal_size(defaultx=80, defaulty=25): |
|
125 |
return |
|
|
121 | return _get_terminal_size((defaultx, defaulty)) |
@@ -19,7 +19,11 b' import random' | |||
|
19 | 19 | import sys |
|
20 | 20 | |
|
21 | 21 | import nose.tools as nt |
|
22 | import path | |
|
22 | try: | |
|
23 | from pathlib import Path | |
|
24 | except ImportError: | |
|
25 | # Python 2 backport | |
|
26 | from pathlib2 import Path | |
|
23 | 27 | |
|
24 | 28 | from IPython.utils import text |
|
25 | 29 | |
@@ -207,7 +211,7 b' def test_LSString():' | |||
|
207 | 211 | nt.assert_equal(lss.l, ['abc', 'def']) |
|
208 | 212 | nt.assert_equal(lss.s, 'abc def') |
|
209 | 213 | lss = text.LSString(os.getcwd()) |
|
210 |
nt.assert_is_instance(lss.p[0], |
|
|
214 | nt.assert_is_instance(lss.p[0], Path) | |
|
211 | 215 | |
|
212 | 216 | def test_SList(): |
|
213 | 217 | sl = text.SList(['a 11', 'b 1', 'a 2']) |
@@ -14,6 +14,11 b' import re' | |||
|
14 | 14 | import sys |
|
15 | 15 | import textwrap |
|
16 | 16 | from string import Formatter |
|
17 | try: | |
|
18 | from pathlib import Path | |
|
19 | except ImportError: | |
|
20 | # Python 2 backport | |
|
21 | from pathlib2 import Path | |
|
17 | 22 | |
|
18 | 23 | from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest |
|
19 | 24 | from IPython.utils import py3compat |
@@ -64,11 +69,10 b' class LSString(str):' | |||
|
64 | 69 | n = nlstr = property(get_nlstr) |
|
65 | 70 | |
|
66 | 71 | def get_paths(self): |
|
67 | from path import path | |
|
68 | 72 | try: |
|
69 | 73 | return self.__paths |
|
70 | 74 | except AttributeError: |
|
71 |
self.__paths = [ |
|
|
75 | self.__paths = [Path(p) for p in self.split('\n') if os.path.exists(p)] | |
|
72 | 76 | return self.__paths |
|
73 | 77 | |
|
74 | 78 | p = paths = property(get_paths) |
@@ -123,11 +127,10 b' class SList(list):' | |||
|
123 | 127 | n = nlstr = property(get_nlstr) |
|
124 | 128 | |
|
125 | 129 | def get_paths(self): |
|
126 | from path import path | |
|
127 | 130 | try: |
|
128 | 131 | return self.__paths |
|
129 | 132 | except AttributeError: |
|
130 |
self.__paths = [ |
|
|
133 | self.__paths = [Path(p) for p in self if os.path.exists(p)] | |
|
131 | 134 | return self.__paths |
|
132 | 135 | |
|
133 | 136 | p = paths = property(get_paths) |
@@ -28,7 +28,7 b' these manuals. If you have Sphinx installed, you can build them by typing' | |||
|
28 | 28 | See the `install page <http://ipython.org/install.html>`__ to install IPython. |
|
29 | 29 | |
|
30 | 30 | The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*. |
|
31 |
See the `Jupyter installation docs <http://jupyter.readthedocs.o |
|
|
31 | See the `Jupyter installation docs <http://jupyter.readthedocs.io/en/latest/install.html>`__ | |
|
32 | 32 | if you want to use these. |
|
33 | 33 | |
|
34 | 34 | Officially, IPython requires Python version 2.7, or 3.3 and above. |
@@ -22,7 +22,7 b" ON_RTD = os.environ.get('READTHEDOCS', None) == 'True'" | |||
|
22 | 22 | if ON_RTD: |
|
23 | 23 | # Mock the presence of matplotlib, which we don't have on RTD |
|
24 | 24 | # see |
|
25 |
# http://read-the-docs.readthedocs.o |
|
|
25 | # http://read-the-docs.readthedocs.io/en/latest/faq.html | |
|
26 | 26 | tags.add('rtd') |
|
27 | 27 | |
|
28 | 28 | # RTD doesn't use the Makefile, so re-run autogen_{things}.py here. |
@@ -201,12 +201,12 b' html_additional_pages = {' | |||
|
201 | 201 | # Output file base name for HTML help builder. |
|
202 | 202 | htmlhelp_basename = 'ipythondoc' |
|
203 | 203 | |
|
204 |
intersphinx_mapping = {'python': ('http://docs.python.org/ |
|
|
204 | intersphinx_mapping = {'python': ('http://docs.python.org/3/', None), | |
|
205 | 205 | 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), |
|
206 |
'traitlets': ('http://traitlets.readthedocs.o |
|
|
207 |
'jupyterclient': ('http://jupyter-client.readthedocs.o |
|
|
208 |
'ipyparallel': ('http://ipyparallel.readthedocs.o |
|
|
209 |
'jupyter': ('http://jupyter.readthedocs.o |
|
|
206 | 'traitlets': ('http://traitlets.readthedocs.io/en/latest/', None), | |
|
207 | 'jupyterclient': ('http://jupyter-client.readthedocs.io/en/latest/', None), | |
|
208 | 'ipyparallel': ('http://ipyparallel.readthedocs.io/en/latest/', None), | |
|
209 | 'jupyter': ('http://jupyter.readthedocs.io/en/latest/', None), | |
|
210 | 210 | } |
|
211 | 211 | |
|
212 | 212 | # Options for LaTeX output |
@@ -19,4 +19,4 b" Developer's guide for third party tools and libraries" | |||
|
19 | 19 | lexer |
|
20 | 20 | pycompat |
|
21 | 21 | config |
|
22 | inputhook_app No newline at end of file | |
|
22 | inputhook_app |
@@ -7,7 +7,7 b' You can now re-use the kernel machinery in IPython to easily make new kernels.' | |||
|
7 | 7 | This is useful for languages that have Python bindings, such as `Octave |
|
8 | 8 | <http://www.gnu.org/software/octave/>`_ (via |
|
9 | 9 | `Oct2Py <http://blink1073.github.io/oct2py/docs/index.html>`_), or languages |
|
10 |
where the REPL can be controlled in a tty using `pexpect <http://pexpect.readthedocs.o |
|
|
10 | where the REPL can be controlled in a tty using `pexpect <http://pexpect.readthedocs.io/en/latest/>`_, | |
|
11 | 11 | such as bash. |
|
12 | 12 | |
|
13 | 13 | .. seealso:: |
@@ -27,10 +27,10 b' Contents' | |||
|
27 | 27 | |
|
28 | 28 | .. seealso:: |
|
29 | 29 | |
|
30 |
`Jupyter documentation <http://jupyter.readthedocs.o |
|
|
30 | `Jupyter documentation <http://jupyter.readthedocs.io/en/latest/>`__ | |
|
31 | 31 | The Notebook code and many other pieces formerly in IPython are now parts |
|
32 | 32 | of Project Jupyter. |
|
33 |
`ipyparallel documentation <http://ipyparallel.readthedocs.o |
|
|
33 | `ipyparallel documentation <http://ipyparallel.readthedocs.io/en/latest/>`__ | |
|
34 | 34 | Formerly ``IPython.parallel``. |
|
35 | 35 | |
|
36 | 36 |
@@ -2,7 +2,7 b' IPython requires Python 2.7 or \xe2\x89\xa5 3.3.' | |||
|
2 | 2 | |
|
3 | 3 | .. seealso:: |
|
4 | 4 | |
|
5 |
`Installing Jupyter <http://jupyter.readthedocs.o |
|
|
5 | `Installing Jupyter <http://jupyter.readthedocs.io/en/latest/install.html>`__ | |
|
6 | 6 | The Notebook, nbconvert, and many other former pieces of IPython are now |
|
7 | 7 | part of Project Jupyter. |
|
8 | 8 |
@@ -15,4 +15,4 b' Using IPython for interactive work' | |||
|
15 | 15 | .. seealso:: |
|
16 | 16 | |
|
17 | 17 | `A Qt Console for Jupyter <http://jupyter.org/qtconsole/>`__ |
|
18 |
`The Jupyter Notebook <http://jupyter-notebook.readthedocs.o |
|
|
18 | `The Jupyter Notebook <http://jupyter-notebook.readthedocs.io/en/latest/>`__ |
@@ -219,7 +219,7 b' different numbers which correspond to the Process ID of the kernel.' | |||
|
219 | 219 | |
|
220 | 220 | You can read more about using `ipython qtconsole |
|
221 | 221 | <http://jupyter.org/qtconsole/>`_, and |
|
222 |
`ipython notebook <http://jupyter-notebook.readthedocs.o |
|
|
222 | `ipython notebook <http://jupyter-notebook.readthedocs.io/en/latest/>`_. There | |
|
223 | 223 | is also a :ref:`message spec <messaging>` which documents the protocol for |
|
224 | 224 | communication between kernels |
|
225 | 225 | and clients. |
@@ -1000,7 +1000,7 b' Pull Requests (793):' | |||
|
1000 | 1000 | * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. |
|
1001 | 1001 | * :ghpull:`2270`: SSHLauncher tweaks |
|
1002 | 1002 | * :ghpull:`2269`: add missing location when disambiguating controller IP |
|
1003 |
* :ghpull:`2263`: Allow docs to build on http://readthedocs.o |
|
|
1003 | * :ghpull:`2263`: Allow docs to build on http://readthedocs.io/ | |
|
1004 | 1004 | * :ghpull:`2256`: Adding data publication example notebook. |
|
1005 | 1005 | * :ghpull:`2255`: better flush iopub with AsyncResults |
|
1006 | 1006 | * :ghpull:`2261`: Fix: longest_substr([]) -> '' |
@@ -3,9 +3,33 b'' | |||
|
3 | 3 | Issues closed in the 4.x development cycle |
|
4 | 4 | ========================================== |
|
5 | 5 | |
|
6 | Issues closed in 4.1 | |
|
6 | ||
|
7 | Issues closed in 4.2 | |
|
7 | 8 | -------------------- |
|
8 | 9 | |
|
10 | GitHub stats for 2015/02/02 - 2016/04/20 (since 4.1) | |
|
11 | ||
|
12 | These lists are automatically generated, and may be incomplete or contain duplicates. | |
|
13 | ||
|
14 | We closed 10 issues and merged 22 pull requests. | |
|
15 | The full list can be seen `on GitHub <https://github.com/ipython/ipython/issues?q=milestone%3A4.2+>`__ | |
|
16 | ||
|
17 | The following 10 authors contributed 27 commits. | |
|
18 | ||
|
19 | * Benjamin Ragan-Kelley | |
|
20 | * Carlos Cordoba | |
|
21 | * Gökhan Karabulut | |
|
22 | * Jonas Rauber | |
|
23 | * Matthias Bussonnier | |
|
24 | * Paul Ivanov | |
|
25 | * Sebastian Bank | |
|
26 | * Thomas A Caswell | |
|
27 | * Thomas Kluyver | |
|
28 | * Vincent Woo | |
|
29 | ||
|
30 | ||
|
31 | Issues closed in 4.1 | |
|
32 | -------------------- | |
|
9 | 33 | |
|
10 | 34 | GitHub stats for 2015/08/12 - 2016/02/02 (since 4.0.0) |
|
11 | 35 |
@@ -2,6 +2,19 b'' | |||
|
2 | 2 | 4.x Series |
|
3 | 3 | ============ |
|
4 | 4 | |
|
5 | IPython 4.2 | |
|
6 | =========== | |
|
7 | ||
|
8 | IPython 4.2 (April, 2016) includes various bugfixes and improvements over 4.1. | |
|
9 | ||
|
10 | - Fix ``ipython -i`` on errors, which was broken in 4.1. | |
|
11 | - The delay meant to highlight deprecated commands that have moved to jupyter has been removed. | |
|
12 | - Improve compatibility with future versions of traitlets and matplotlib. | |
|
13 | - Use stdlib :func:`python:shutil.get_terminal_size` to measure terminal width when displaying tracebacks | |
|
14 | (provided by ``backports.shutil_get_terminal_size`` on Python 2). | |
|
15 | ||
|
16 | You can see the rest `on GitHub <https://github.com/ipython/ipython/issues?q=milestone%3A4.2>`__. | |
|
17 | ||
|
5 | 18 | |
|
6 | 19 | IPython 4.1 |
|
7 | 20 | =========== |
@@ -34,8 +47,8 b' Released August, 2015' | |||
|
34 | 47 | |
|
35 | 48 | IPython 4.0 is the first major release after the Big Split. |
|
36 | 49 | IPython no longer contains the notebook, qtconsole, etc. which have moved to |
|
37 |
`jupyter <https://jupyter.readthedocs.o |
|
|
38 |
IPython subprojects, such as `IPython.parallel <https://ipyparallel.readthedocs.o |
|
|
50 | `jupyter <https://jupyter.readthedocs.io>`_. | |
|
51 | IPython subprojects, such as `IPython.parallel <https://ipyparallel.readthedocs.io>`_ and `widgets <https://ipywidgets.readthedocs.io>`_ have moved to their own repos as well. | |
|
39 | 52 | |
|
40 | 53 | The following subpackages are deprecated: |
|
41 | 54 |
@@ -354,7 +354,7 b'' | |||
|
354 | 354 | "cell_type": "markdown", |
|
355 | 355 | "metadata": {}, |
|
356 | 356 | "source": [ |
|
357 |
"[Vincent](https://vincent.readthedocs.o |
|
|
357 | "[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." | |
|
358 | 358 | ] |
|
359 | 359 | }, |
|
360 | 360 | { |
@@ -198,7 +198,6 b' install_requires = [' | |||
|
198 | 198 | 'traitlets', |
|
199 | 199 | 'prompt_toolkit>=0.60', |
|
200 | 200 | 'pygments', |
|
201 | 'backports.shutil_get_terminal_size', | |
|
202 | 201 | ] |
|
203 | 202 | |
|
204 | 203 | # Platform-specific dependencies: |
@@ -206,6 +205,8 b' install_requires = [' | |||
|
206 | 205 | # but requires pip >= 6. pip < 6 ignores these. |
|
207 | 206 | |
|
208 | 207 | extras_require.update({ |
|
208 | ':python_version == "2.7"': ['backports.shutil_get_terminal_size'], | |
|
209 | ':python_version == "2.7" or python_version == "3.3"': ['pathlib2'], | |
|
209 | 210 | ':sys_platform != "win32"': ['pexpect'], |
|
210 | 211 | ':sys_platform == "darwin"': ['appnope'], |
|
211 | 212 | ':sys_platform == "win32"': ['colorama'], |
@@ -168,7 +168,7 b' if __name__ == "__main__":' | |||
|
168 | 168 | state='closed', |
|
169 | 169 | auth=True, |
|
170 | 170 | ) |
|
171 | issues, pulls = split_pulls(issues_and_pulls) | |
|
171 | issues, pulls = split_pulls(issues_and_pulls, project=project) | |
|
172 | 172 | else: |
|
173 | 173 | issues = issues_closed_since(since, project=project, pulls=False) |
|
174 | 174 | pulls = issues_closed_since(since, project=project, pulls=True) |
General Comments 0
You need to be logged in to leave comments.
Login now