Show More
@@ -71,11 +71,10 b' from IPython.core.error import TryNext' | |||||
71 | from IPython.core.inputsplitter import ESC_MAGIC |
|
71 | from IPython.core.inputsplitter import ESC_MAGIC | |
72 | from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol |
|
72 | from IPython.core.latex_symbols import latex_symbols, reverse_latex_symbol | |
73 | from IPython.utils import generics |
|
73 | from IPython.utils import generics | |
74 | from IPython.utils import io |
|
|||
75 | from IPython.utils.decorators import undoc |
|
74 | from IPython.utils.decorators import undoc | |
76 | from IPython.utils.dir2 import dir2, get_real_method |
|
75 | from IPython.utils.dir2 import dir2, get_real_method | |
77 | from IPython.utils.process import arg_split |
|
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 | from traitlets import CBool, Enum |
|
78 | from traitlets import CBool, Enum | |
80 |
|
79 | |||
81 | try: |
|
80 | try: | |
@@ -201,6 +200,9 b' def completions_sorting_key(word):' | |||||
201 | elif word.startswith('_'): |
|
200 | elif word.startswith('_'): | |
202 | prio1 = 1 |
|
201 | prio1 = 1 | |
203 |
|
202 | |||
|
203 | if word.endswith('='): | |||
|
204 | prio1 = -1 | |||
|
205 | ||||
204 | if word.startswith('%%'): |
|
206 | if word.startswith('%%'): | |
205 | # If there's another % in there, this is something else, so leave it alone |
|
207 | # If there's another % in there, this is something else, so leave it alone | |
206 | if not "%" in word[2:]: |
|
208 | if not "%" in word[2:]: | |
@@ -358,7 +360,7 b' class Completer(Configurable):' | |||||
358 | for word in lst: |
|
360 | for word in lst: | |
359 | if word[:n] == text and word != "__builtins__": |
|
361 | if word[:n] == text and word != "__builtins__": | |
360 | match_append(word) |
|
362 | match_append(word) | |
361 | return matches |
|
363 | return [cast_unicode_py2(m) for m in matches] | |
362 |
|
364 | |||
363 | def attr_matches(self, text): |
|
365 | def attr_matches(self, text): | |
364 | """Compute matches when text contains a dot. |
|
366 | """Compute matches when text contains a dot. | |
@@ -410,8 +412,7 b' class Completer(Configurable):' | |||||
410 | pass |
|
412 | pass | |
411 | # Build match list to return |
|
413 | # Build match list to return | |
412 | n = len(attr) |
|
414 | n = len(attr) | |
413 |
re |
|
415 | return [u"%s.%s" % (expr, w) for w in words if w[:n] == attr ] | |
414 | return res |
|
|||
415 |
|
416 | |||
416 |
|
417 | |||
417 | def get__all__entries(obj): |
|
418 | def get__all__entries(obj): | |
@@ -421,7 +422,7 b' def get__all__entries(obj):' | |||||
421 | except: |
|
422 | except: | |
422 | return [] |
|
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 | def match_dict_keys(keys, prefix, delims): |
|
428 | def match_dict_keys(keys, prefix, delims): | |
@@ -695,9 +696,9 b' class IPCompleter(Completer):' | |||||
695 | # when escaped with backslash |
|
696 | # when escaped with backslash | |
696 | if text.startswith('!'): |
|
697 | if text.startswith('!'): | |
697 | text = text[1:] |
|
698 | text = text[1:] | |
698 | text_prefix = '!' |
|
699 | text_prefix = u'!' | |
699 | else: |
|
700 | else: | |
700 | text_prefix = '' |
|
701 | text_prefix = u'' | |
701 |
|
702 | |||
702 | text_until_cursor = self.text_until_cursor |
|
703 | text_until_cursor = self.text_until_cursor | |
703 | # track strings with open quotes |
|
704 | # track strings with open quotes | |
@@ -728,7 +729,7 b' class IPCompleter(Completer):' | |||||
728 | text = os.path.expanduser(text) |
|
729 | text = os.path.expanduser(text) | |
729 |
|
730 | |||
730 | if text == "": |
|
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 | # Compute the matches from the filesystem |
|
734 | # Compute the matches from the filesystem | |
734 | m0 = self.clean_glob(text.replace('\\','')) |
|
735 | m0 = self.clean_glob(text.replace('\\','')) | |
@@ -751,8 +752,7 b' class IPCompleter(Completer):' | |||||
751 | protect_filename(f) for f in m0] |
|
752 | protect_filename(f) for f in m0] | |
752 |
|
753 | |||
753 | # Mark directories in input list by appending '/' to their names. |
|
754 | # Mark directories in input list by appending '/' to their names. | |
754 |
|
|
755 | return [cast_unicode_py2(x+'/') if os.path.isdir(x) else x for x in matches] | |
755 | return matches |
|
|||
756 |
|
756 | |||
757 | def magic_matches(self, text): |
|
757 | def magic_matches(self, text): | |
758 | """Match magics""" |
|
758 | """Match magics""" | |
@@ -773,7 +773,7 b' class IPCompleter(Completer):' | |||||
773 | comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] |
|
773 | comp = [ pre2+m for m in cell_magics if m.startswith(bare_text)] | |
774 | if not text.startswith(pre2): |
|
774 | if not text.startswith(pre2): | |
775 | comp += [ pre+m for m in line_magics if m.startswith(bare_text)] |
|
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 | def python_jedi_matches(self, text, line_buffer, cursor_pos): |
|
778 | def python_jedi_matches(self, text, line_buffer, cursor_pos): | |
779 | """Match attributes or global Python names using Jedi.""" |
|
779 | """Match attributes or global Python names using Jedi.""" | |
@@ -849,7 +849,6 b' class IPCompleter(Completer):' | |||||
849 | matches = [] |
|
849 | matches = [] | |
850 | else: |
|
850 | else: | |
851 | matches = self.global_matches(text) |
|
851 | matches = self.global_matches(text) | |
852 |
|
||||
853 | return matches |
|
852 | return matches | |
854 |
|
853 | |||
855 | def _default_arguments_from_docstring(self, doc): |
|
854 | def _default_arguments_from_docstring(self, doc): | |
@@ -978,7 +977,7 b' class IPCompleter(Completer):' | |||||
978 |
|
977 | |||
979 | for namedArg in namedArgs: |
|
978 | for namedArg in namedArgs: | |
980 | if namedArg.startswith(text): |
|
979 | if namedArg.startswith(text): | |
981 | argMatches.append("%s=" %namedArg) |
|
980 | argMatches.append(u"%s=" %namedArg) | |
982 | return argMatches |
|
981 | return argMatches | |
983 |
|
982 | |||
984 | def dict_key_matches(self, text): |
|
983 | def dict_key_matches(self, text): | |
@@ -1164,12 +1163,12 b' class IPCompleter(Completer):' | |||||
1164 | res = c(event) |
|
1163 | res = c(event) | |
1165 | if res: |
|
1164 | if res: | |
1166 | # first, try case sensitive match |
|
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 | if withcase: |
|
1167 | if withcase: | |
1169 | return withcase |
|
1168 | return withcase | |
1170 | # if none, then case insensitive ones are ok too |
|
1169 | # if none, then case insensitive ones are ok too | |
1171 | text_low = text.lower() |
|
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 | except TryNext: |
|
1172 | except TryNext: | |
1174 | pass |
|
1173 | pass | |
1175 |
|
1174 |
@@ -944,7 +944,7 b' def format_display_data(obj, include=None, exclude=None):' | |||||
944 | """ |
|
944 | """ | |
945 | from IPython.core.interactiveshell import InteractiveShell |
|
945 | from IPython.core.interactiveshell import InteractiveShell | |
946 |
|
946 | |||
947 | InteractiveShell.instance().display_formatter.format( |
|
947 | return InteractiveShell.instance().display_formatter.format( | |
948 | obj, |
|
948 | obj, | |
949 | include, |
|
949 | include, | |
950 | exclude |
|
950 | exclude |
@@ -1,18 +1,10 b'' | |||||
1 | """ History related magics and functionality """ |
|
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 | #----------------------------------------------------------------------------- |
|
3 | # Copyright (c) IPython Development Team. | |
11 | # Imports |
|
4 | # Distributed under the terms of the Modified BSD License. | |
12 | #----------------------------------------------------------------------------- |
|
5 | ||
13 | from __future__ import print_function |
|
6 | from __future__ import print_function | |
14 |
|
7 | |||
15 | # Stdlib imports |
|
|||
16 | import atexit |
|
8 | import atexit | |
17 | import datetime |
|
9 | import datetime | |
18 | import os |
|
10 | import os | |
@@ -26,7 +18,6 b' except ImportError:' | |||||
26 | sqlite3 = None |
|
18 | sqlite3 = None | |
27 | import threading |
|
19 | import threading | |
28 |
|
20 | |||
29 | # Our own packages |
|
|||
30 | from traitlets.config.configurable import LoggingConfigurable |
|
21 | from traitlets.config.configurable import LoggingConfigurable | |
31 | from decorator import decorator |
|
22 | from decorator import decorator | |
32 | from IPython.utils.decorators import undoc |
|
23 | from IPython.utils.decorators import undoc | |
@@ -80,27 +71,52 b' else:' | |||||
80 | class OperationalError(Exception): |
|
71 | class OperationalError(Exception): | |
81 | "Dummy exception when sqlite could not be imported. Should never occur." |
|
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 | @decorator |
|
78 | @decorator | |
84 | def catch_corrupt_db(f, self, *a, **kw): |
|
79 | def catch_corrupt_db(f, self, *a, **kw): | |
85 | """A decorator which wraps HistoryAccessor method calls to catch errors from |
|
80 | """A decorator which wraps HistoryAccessor method calls to catch errors from | |
86 | a corrupt SQLite database, move the old database out of the way, and create |
|
81 | a corrupt SQLite database, move the old database out of the way, and create | |
87 | a new one. |
|
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 | try: |
|
87 | try: | |
90 | return f(self, *a, **kw) |
|
88 | return f(self, *a, **kw) | |
91 | except (DatabaseError, OperationalError): |
|
89 | except (DatabaseError, OperationalError) as e: | |
92 | if os.path.isfile(self.hist_file): |
|
90 | self._corrupt_db_counter += 1 | |
93 | # Try to move the file out of the way |
|
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 | |||
94 | base,ext = os.path.splitext(self.hist_file) |
|
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? | |||
95 | newpath = base + '-corrupt' + ext |
|
113 | newpath = base + '-corrupt' + ext | |
96 | os.rename(self.hist_file, newpath) |
|
114 | os.rename(self.hist_file, newpath) | |
|
115 | self.log.error("History file was moved to %s and a new file created.", newpath) | |||
97 | self.init_db() |
|
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 | return [] |
|
117 | return [] | |
101 |
|
||||
102 | else: |
|
118 | else: | |
103 |
# |
|
119 | # Failed with :memory:, something serious is wrong | |
104 | raise |
|
120 | raise | |
105 |
|
121 | |||
106 | class HistoryAccessorBase(LoggingConfigurable): |
|
122 | class HistoryAccessorBase(LoggingConfigurable): | |
@@ -126,6 +142,11 b' class HistoryAccessor(HistoryAccessorBase):' | |||||
126 | This is intended for use by standalone history tools. IPython shells use |
|
142 | This is intended for use by standalone history tools. IPython shells use | |
127 | HistoryManager, below, which is a subclass of this.""" |
|
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 | # String holding the path to the history file |
|
150 | # String holding the path to the history file | |
130 | hist_file = Unicode(config=True, |
|
151 | hist_file = Unicode(config=True, | |
131 | help="""Path to file to use for SQLite history database. |
|
152 | help="""Path to file to use for SQLite history database. | |
@@ -239,6 +260,8 b' class HistoryAccessor(HistoryAccessorBase):' | |||||
239 | (session integer, line integer, output text, |
|
260 | (session integer, line integer, output text, | |
240 | PRIMARY KEY (session, line))""") |
|
261 | PRIMARY KEY (session, line))""") | |
241 | self.db.commit() |
|
262 | self.db.commit() | |
|
263 | # success! reset corrupt db count | |||
|
264 | self._corrupt_db_counter = 0 | |||
242 |
|
265 | |||
243 | def writeout_cache(self): |
|
266 | def writeout_cache(self): | |
244 | """Overridden by HistoryManager to dump the cache before certain |
|
267 | """Overridden by HistoryManager to dump the cache before certain |
@@ -57,7 +57,7 b' from IPython.core.prefilter import PrefilterManager' | |||||
57 | from IPython.core.profiledir import ProfileDir |
|
57 | from IPython.core.profiledir import ProfileDir | |
58 | from IPython.core.prompts import PromptManager |
|
58 | from IPython.core.prompts import PromptManager | |
59 | from IPython.core.usage import default_banner |
|
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 | from IPython.utils import PyColorize |
|
61 | from IPython.utils import PyColorize | |
62 | from IPython.utils import io |
|
62 | from IPython.utils import io | |
63 | from IPython.utils import py3compat |
|
63 | from IPython.utils import py3compat | |
@@ -1939,6 +1939,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
1939 | self.set_hook('complete_command', reset_completer, str_key = '%reset') |
|
1939 | self.set_hook('complete_command', reset_completer, str_key = '%reset') | |
1940 |
|
1940 | |||
1941 |
|
1941 | |||
|
1942 | @skip_doctest_py2 | |||
1942 | def complete(self, text, line=None, cursor_pos=None): |
|
1943 | def complete(self, text, line=None, cursor_pos=None): | |
1943 | """Return the completed text and a list of completions. |
|
1944 | """Return the completed text and a list of completions. | |
1944 |
|
1945 |
@@ -61,12 +61,12 b' class TimeitResult(object):' | |||||
61 | """ |
|
61 | """ | |
62 | Object returned by the timeit magic with info about the run. |
|
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 |
|
66 | loops: (int) number of loops done per measurement | |
67 | repeat: (int) number of time the mesurement has been repeated |
|
67 | repeat: (int) number of times the measurement has been repeated | |
68 |
best: (float) best execu |
|
68 | best: (float) best execution time / number | |
69 |
all_runs: (list of float) execu |
|
69 | all_runs: (list of float) execution time of each run (in s) | |
70 | compile_time: (float) time of statement compilation (s) |
|
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 | Makes some attempts at finding an OS-correct one. |
|
298 | Makes some attempts at finding an OS-correct one. | |
299 | """ |
|
299 | """ | |
300 | if os.name == 'posix': |
|
300 | if os.name == 'posix': | |
301 |
default_pager_cmd = 'less - |
|
301 | default_pager_cmd = 'less -R' # -R for color control sequences | |
302 | elif os.name in ['nt','dos']: |
|
302 | elif os.name in ['nt','dos']: | |
303 | default_pager_cmd = 'type' |
|
303 | default_pager_cmd = 'type' | |
304 |
|
304 | |||
@@ -308,8 +308,8 b' def get_pager_cmd(pager_cmd=None):' | |||||
308 | except: |
|
308 | except: | |
309 | pager_cmd = default_pager_cmd |
|
309 | pager_cmd = default_pager_cmd | |
310 |
|
310 | |||
311 | if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', ''): |
|
311 | if pager_cmd == 'less' and '-r' not in os.environ.get('LESS', '').lower(): | |
312 |
pager_cmd += ' - |
|
312 | pager_cmd += ' -R' | |
313 |
|
313 | |||
314 | return pager_cmd |
|
314 | return pager_cmd | |
315 |
|
315 |
@@ -790,6 +790,7 b' def test_nested_import_module_completer():' | |||||
790 | _, matches = ip.complete(None, 'import IPython.co', 17) |
|
790 | _, matches = ip.complete(None, 'import IPython.co', 17) | |
791 | nt.assert_in('IPython.core', matches) |
|
791 | nt.assert_in('IPython.core', matches) | |
792 | nt.assert_not_in('import IPython.core', matches) |
|
792 | nt.assert_not_in('import IPython.core', matches) | |
|
793 | nt.assert_not_in('IPython.display', matches) | |||
793 |
|
794 | |||
794 | def test_import_module_completer(): |
|
795 | def test_import_module_completer(): | |
795 | ip = get_ipython() |
|
796 | ip = get_ipython() |
@@ -100,6 +100,21 b' class NonAsciiTest(unittest.TestCase):' | |||||
100 | with tt.AssertPrints(u'дбИЖ', suppress=False): |
|
100 | with tt.AssertPrints(u'дбИЖ', suppress=False): | |
101 | ip.run_cell('fail()') |
|
101 | ip.run_cell('fail()') | |
102 |
|
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) | |||
|
117 | ||||
103 |
|
118 | |||
104 | class NestedGenExprTestCase(unittest.TestCase): |
|
119 | class NestedGenExprTestCase(unittest.TestCase): | |
105 | """ |
|
120 | """ |
@@ -709,10 +709,10 b' class ListTB(TBTools):' | |||||
709 | have_filedata = False |
|
709 | have_filedata = False | |
710 | Colors = self.Colors |
|
710 | Colors = self.Colors | |
711 | list = [] |
|
711 | list = [] | |
712 | stype = Colors.excName + etype.__name__ + Colors.Normal |
|
712 | stype = py3compat.cast_unicode(Colors.excName + etype.__name__ + Colors.Normal) | |
713 | if value is None: |
|
713 | if value is None: | |
714 | # Not sure if this can still happen in Python 2.6 and above |
|
714 | # Not sure if this can still happen in Python 2.6 and above | |
715 |
list.append( |
|
715 | list.append(stype + '\n') | |
716 | else: |
|
716 | else: | |
717 | if issubclass(etype, SyntaxError): |
|
717 | if issubclass(etype, SyntaxError): | |
718 | have_filedata = True |
|
718 | have_filedata = True | |
@@ -752,10 +752,10 b' class ListTB(TBTools):' | |||||
752 | except Exception: |
|
752 | except Exception: | |
753 | s = self._some_str(value) |
|
753 | s = self._some_str(value) | |
754 | if s: |
|
754 | if s: | |
755 |
list.append('%s%s:%s %s\n' % ( |
|
755 | list.append('%s%s:%s %s\n' % (stype, Colors.excName, | |
756 | Colors.Normal, s)) |
|
756 | Colors.Normal, s)) | |
757 | else: |
|
757 | else: | |
758 |
list.append('%s\n' % |
|
758 | list.append('%s\n' % stype) | |
759 |
|
759 | |||
760 | # sync with user hooks |
|
760 | # sync with user hooks | |
761 | if have_filedata: |
|
761 | if have_filedata: | |
@@ -793,9 +793,9 b' class ListTB(TBTools):' | |||||
793 | def _some_str(self, value): |
|
793 | def _some_str(self, value): | |
794 | # Lifted from traceback.py |
|
794 | # Lifted from traceback.py | |
795 | try: |
|
795 | try: | |
796 | return str(value) |
|
796 | return py3compat.cast_unicode(str(value)) | |
797 | except: |
|
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 | newtext = ulinecache.getline(value.filename, value.lineno) |
|
1432 | newtext = ulinecache.getline(value.filename, value.lineno) | |
1433 | if newtext: |
|
1433 | if newtext: | |
1434 | value.text = newtext |
|
1434 | value.text = newtext | |
|
1435 | self.last_syntax_error = value | |||
1435 | return super(SyntaxTB, self).structured_traceback(etype, value, elist, |
|
1436 | return super(SyntaxTB, self).structured_traceback(etype, value, elist, | |
1436 | tb_offset=tb_offset, context=context) |
|
1437 | tb_offset=tb_offset, context=context) | |
1437 |
|
1438 |
@@ -41,7 +41,7 b' class Audio(DisplayObject):' | |||||
41 | filename : unicode |
|
41 | filename : unicode | |
42 | Path to a local file to load the data from. |
|
42 | Path to a local file to load the data from. | |
43 | embed : boolean |
|
43 | embed : boolean | |
44 |
Should the |
|
44 | Should the audio data be embedded using a data URI (True) or should | |
45 | the original source be referenced. Set this to True if you want the |
|
45 | the original source be referenced. Set this to True if you want the | |
46 | audio to playable later with no internet connection in the notebook. |
|
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 | from IPython.core.magic import Magics, magics_class, line_magic |
|
15 | from IPython.core.magic import Magics, magics_class, line_magic | |
16 | from IPython.core.interactiveshell import DummyMod |
|
16 | from IPython.core.interactiveshell import DummyMod | |
17 | from IPython.core.interactiveshell import InteractiveShell |
|
17 | from IPython.core.interactiveshell import InteractiveShell | |
18 |
from IPython.terminal. |
|
18 | from IPython.terminal.ptshell import TerminalInteractiveShell | |
19 | from IPython.terminal.ipapp import load_default_config |
|
19 | from IPython.terminal.ipapp import load_default_config | |
20 |
|
20 | |||
21 | from traitlets import Bool, CBool, Unicode |
|
21 | from traitlets import Bool, CBool, Unicode | |
@@ -136,6 +136,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||||
136 | else: |
|
136 | else: | |
137 | self.old_banner2 = '' |
|
137 | self.old_banner2 = '' | |
138 |
|
138 | |||
|
139 | if self.display_banner: | |||
|
140 | self.show_banner() | |||
|
141 | ||||
139 | # Call the embedding code with a stack depth of 1 so it can skip over |
|
142 | # Call the embedding code with a stack depth of 1 so it can skip over | |
140 | # our call and get the original caller's namespaces. |
|
143 | # our call and get the original caller's namespaces. | |
141 | self.mainloop(local_ns, module, stack_depth=stack_depth, |
|
144 | self.mainloop(local_ns, module, stack_depth=stack_depth, | |
@@ -182,6 +185,9 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||||
182 | module = DummyMod() |
|
185 | module = DummyMod() | |
183 | module.__dict__ = global_ns |
|
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 | # Get locals and globals from caller |
|
191 | # Get locals and globals from caller | |
186 | if ((local_ns is None or module is None or compile_flags is None) |
|
192 | if ((local_ns is None or module is None or compile_flags is None) | |
187 | and self.default_user_namespaces): |
|
193 | and self.default_user_namespaces): | |
@@ -191,7 +197,14 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||||
191 | local_ns = call_frame.f_locals |
|
197 | local_ns = call_frame.f_locals | |
192 | if module is None: |
|
198 | if module is None: | |
193 | global_ns = call_frame.f_globals |
|
199 | global_ns = call_frame.f_globals | |
|
200 | try: | |||
194 | module = sys.modules[global_ns['__name__']] |
|
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 | if compile_flags is None: |
|
208 | if compile_flags is None: | |
196 | compile_flags = (call_frame.f_code.co_flags & |
|
209 | compile_flags = (call_frame.f_code.co_flags & | |
197 | compilerop.PyCF_MASK) |
|
210 | compilerop.PyCF_MASK) | |
@@ -226,7 +239,7 b' class InteractiveShellEmbed(TerminalInteractiveShell):' | |||||
226 | self.set_completer_frame() |
|
239 | self.set_completer_frame() | |
227 |
|
240 | |||
228 | with self.builtin_trap, self.display_trap: |
|
241 | with self.builtin_trap, self.display_trap: | |
229 |
self.interact( |
|
242 | self.interact() | |
230 |
|
243 | |||
231 | # now, purge out the local namespace of IPython's hidden variables. |
|
244 | # now, purge out the local namespace of IPython's hidden variables. | |
232 | if local_ns is not None: |
|
245 | if local_ns is not None: |
@@ -4,18 +4,22 b' from __future__ import print_function' | |||||
4 | import os |
|
4 | import os | |
5 | import sys |
|
5 | import sys | |
6 | import signal |
|
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 | from IPython.core.interactiveshell import InteractiveShell |
|
12 | from IPython.core.interactiveshell import InteractiveShell | |
9 | from IPython.utils.py3compat import PY3, cast_unicode_py2, input |
|
13 | from IPython.utils.py3compat import PY3, cast_unicode_py2, input | |
10 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
|
14 | from IPython.utils.terminal import toggle_set_term_title, set_term_title | |
11 | from IPython.utils.process import abbrev_cwd |
|
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 | from prompt_toolkit.completion import Completer, Completion |
|
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 | from prompt_toolkit.filters import HasFocus, HasSelection, Condition |
|
20 | from prompt_toolkit.filters import HasFocus, HasSelection, Condition | |
17 | from prompt_toolkit.history import InMemoryHistory |
|
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 | from prompt_toolkit.interface import CommandLineInterface |
|
23 | from prompt_toolkit.interface import CommandLineInterface | |
20 | from prompt_toolkit.key_binding.manager import KeyBindingManager |
|
24 | from prompt_toolkit.key_binding.manager import KeyBindingManager | |
21 | from prompt_toolkit.key_binding.vi_state import InputMode |
|
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 | from prompt_toolkit.keys import Keys |
|
27 | from prompt_toolkit.keys import Keys | |
24 | from prompt_toolkit.layout.lexers import Lexer |
|
28 | from prompt_toolkit.layout.lexers import Lexer | |
25 | from prompt_toolkit.layout.lexers import PygmentsLexer |
|
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 | from pygments.lexers import Python3Lexer, BashLexer, PythonLexer |
|
33 | from pygments.lexers import Python3Lexer, BashLexer, PythonLexer | |
30 | from pygments.token import Token |
|
34 | from pygments.token import Token | |
31 |
|
35 | |||
@@ -33,7 +37,6 b' from .pt_inputhooks import get_inputhook_func' | |||||
33 | from .interactiveshell import get_default_editor, TerminalMagics |
|
37 | from .interactiveshell import get_default_editor, TerminalMagics | |
34 |
|
38 | |||
35 |
|
39 | |||
36 |
|
||||
37 | class IPythonPTCompleter(Completer): |
|
40 | class IPythonPTCompleter(Completer): | |
38 | """Adaptor to provide IPython completions to prompt_toolkit""" |
|
41 | """Adaptor to provide IPython completions to prompt_toolkit""" | |
39 | def __init__(self, ipy_completer): |
|
42 | def __init__(self, ipy_completer): | |
@@ -49,6 +52,22 b' class IPythonPTCompleter(Completer):' | |||||
49 | ) |
|
52 | ) | |
50 | start_pos = -len(used) |
|
53 | start_pos = -len(used) | |
51 | for m in matches: |
|
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 | # TODO: Use Jedi to determine meta_text |
|
71 | # TODO: Use Jedi to determine meta_text | |
53 | # (Jedi currently has a bug that results in incorrect information.) |
|
72 | # (Jedi currently has a bug that results in incorrect information.) | |
54 | # meta_text = '' |
|
73 | # meta_text = '' | |
@@ -74,8 +93,23 b' class IPythonPTLexer(Lexer):' | |||||
74 | class TerminalInteractiveShell(InteractiveShell): |
|
93 | class TerminalInteractiveShell(InteractiveShell): | |
75 | colors_force = True |
|
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 | pt_cli = None |
|
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 | vi_mode = Bool(False, config=True, |
|
113 | vi_mode = Bool(False, config=True, | |
80 | help="Use vi style keybindings at the prompt", |
|
114 | help="Use vi style keybindings at the prompt", | |
81 | ) |
|
115 | ) | |
@@ -84,10 +118,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
84 | help="Enable mouse support in the prompt" |
|
118 | help="Enable mouse support in the prompt" | |
85 | ) |
|
119 | ) | |
86 |
|
120 | |||
87 | highlighting_style = Unicode('', config=True, |
|
121 | highlighting_style = Unicode('default', config=True, | |
88 | help="The name of a Pygments style to use for syntax highlighting" |
|
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 | highlighting_style_overrides = Dict(config=True, |
|
128 | highlighting_style_overrides = Dict(config=True, | |
92 | help="Override highlighting format for specific tokens" |
|
129 | help="Override highlighting format for specific tokens" | |
93 | ) |
|
130 | ) | |
@@ -158,6 +195,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
158 | def _(event): |
|
195 | def _(event): | |
159 | event.current_buffer.reset() |
|
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 | supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) |
|
205 | supports_suspend = Condition(lambda cli: hasattr(signal, 'SIGTSTP')) | |
162 |
|
206 | |||
163 | @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) |
|
207 | @kbmanager.registry.add_binding(Keys.ControlZ, filter=supports_suspend) | |
@@ -189,13 +233,33 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
189 | if cell and (cell != last_cell): |
|
233 | if cell and (cell != last_cell): | |
190 | history.append(cell) |
|
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 | style_overrides = { |
|
258 | style_overrides = { | |
193 | Token.Prompt: '#009900', |
|
259 | Token.Prompt: '#009900', | |
194 | Token.PromptNum: '#00ff00 bold', |
|
260 | Token.PromptNum: '#00ff00 bold', | |
195 | } |
|
261 | } | |
196 | if self.highlighting_style: |
|
262 | if name is 'default': | |
197 | style_cls = get_style_by_name(self.highlighting_style) |
|
|||
198 | else: |
|
|||
199 | style_cls = get_style_by_name('default') |
|
263 | style_cls = get_style_by_name('default') | |
200 | # The default theme needs to be visible on both a dark background |
|
264 | # The default theme needs to be visible on both a dark background | |
201 | # and a light background, because we can't tell what the terminal |
|
265 | # and a light background, because we can't tell what the terminal | |
@@ -212,21 +276,27 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
212 | style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, |
|
276 | style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, | |
213 | style_dict=style_overrides) |
|
277 | style_dict=style_overrides) | |
214 |
|
278 | |||
215 | app = create_prompt_application(multiline=True, |
|
279 | return style | |
216 | lexer=IPythonPTLexer(), |
|
280 | ||
217 | get_prompt_tokens=self.get_prompt_tokens, |
|
281 | def _layout_options(self): | |
218 | get_continuation_tokens=self.get_continuation_tokens, |
|
282 | """ | |
219 | key_bindings_registry=kbmanager.registry, |
|
283 | Return the current layout option for the current Terminal InteractiveShell | |
220 | history=history, |
|
284 | """ | |
221 | completer=IPythonPTCompleter(self.Completer), |
|
285 | return { | |
222 | enable_history_search=True, |
|
286 | 'lexer':IPythonPTLexer(), | |
223 | style=style, |
|
287 | 'reserve_space_for_menu':self.space_for_menu, | |
224 | mouse_support=self.mouse_support, |
|
288 | 'get_prompt_tokens':self.get_prompt_tokens, | |
225 | reserve_space_for_menu=6, |
|
289 | 'get_continuation_tokens':self.get_continuation_tokens, | |
226 | ) |
|
290 | 'multiline':True, | |
|
291 | } | |||
227 |
|
292 | |||
228 | self.pt_cli = CommandLineInterface(app, |
|
293 | ||
229 | eventloop=create_eventloop(self.inputhook)) |
|
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 | def prompt_for_code(self): |
|
301 | def prompt_for_code(self): | |
232 | document = self.pt_cli.run(pre_run=self.pre_prompt) |
|
302 | document = self.pt_cli.run(pre_run=self.pre_prompt) | |
@@ -286,12 +356,15 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
286 | try: |
|
356 | try: | |
287 | code = self.prompt_for_code() |
|
357 | code = self.prompt_for_code() | |
288 | except EOFError: |
|
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 | self.ask_exit() |
|
361 | self.ask_exit() | |
291 |
|
362 | |||
292 | else: |
|
363 | else: | |
293 | if code: |
|
364 | if code: | |
294 | self.run_cell(code, store_history=True) |
|
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 | def mainloop(self): |
|
369 | def mainloop(self): | |
297 | # An extra layer of protection in case someone mashing Ctrl-C breaks |
|
370 | # An extra layer of protection in case someone mashing Ctrl-C breaks | |
@@ -314,5 +387,69 b' class TerminalInteractiveShell(InteractiveShell):' | |||||
314 | else: |
|
387 | else: | |
315 | self._inputhook = None |
|
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 | if __name__ == '__main__': |
|
454 | if __name__ == '__main__': | |
318 | TerminalInteractiveShell.instance().interact() |
|
455 | TerminalInteractiveShell.instance().interact() |
@@ -25,8 +25,6 b' import logging' | |||||
25 | import os |
|
25 | import os | |
26 | import re |
|
26 | import re | |
27 | import sys |
|
27 | import sys | |
28 | import traceback |
|
|||
29 | import unittest |
|
|||
30 |
|
28 | |||
31 | from testpath import modified_env |
|
29 | from testpath import modified_env | |
32 |
|
30 | |||
@@ -41,10 +39,9 b' from doctest import (REPORTING_FLAGS, REPORT_ONLY_FIRST_FAILURE,' | |||||
41 | linecache) |
|
39 | linecache) | |
42 |
|
40 | |||
43 | # Third-party modules |
|
41 | # Third-party modules | |
44 | import nose.core |
|
|||
45 |
|
42 | |||
46 | from nose.plugins import doctests, Plugin |
|
43 | from nose.plugins import doctests, Plugin | |
47 |
from nose.util import anyp, |
|
44 | from nose.util import anyp, tolist | |
48 |
|
45 | |||
49 | # Our own imports |
|
46 | # Our own imports | |
50 | from IPython.utils.py3compat import builtin_mod, PY3, getcwd |
|
47 | from IPython.utils.py3compat import builtin_mod, PY3, getcwd | |
@@ -143,7 +140,7 b' class DocTestFinder(doctest.DocTestFinder):' | |||||
143 | # doctests in extension modules. |
|
140 | # doctests in extension modules. | |
144 |
|
141 | |||
145 | # Local shorthands |
|
142 | # Local shorthands | |
146 |
from inspect import isroutine, isclass |
|
143 | from inspect import isroutine, isclass | |
147 |
|
144 | |||
148 | # Look for tests in a module's contained objects. |
|
145 | # Look for tests in a module's contained objects. | |
149 | if inspect.ismodule(obj) and self._recurse: |
|
146 | if inspect.ismodule(obj) and self._recurse: |
@@ -36,3 +36,8 b' def skip_doctest_py3(f):' | |||||
36 | """Decorator - skip the doctest under Python 3.""" |
|
36 | """Decorator - skip the doctest under Python 3.""" | |
37 | f.skip_doctest = (sys.version_info[0] >= 3) |
|
37 | f.skip_doctest = (sys.version_info[0] >= 3) | |
38 | return f |
|
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 | * Alexander Belchenko (e-mail: bialix AT ukr.net) |
|
9 | * Alexander Belchenko (e-mail: bialix AT ukr.net) | |
10 | """ |
|
10 | """ | |
11 |
|
11 | |||
12 | #----------------------------------------------------------------------------- |
|
12 | # Copyright (c) IPython Development Team. | |
13 | # Copyright (C) 2008-2011 The IPython Development Team |
|
13 | # Distributed under the terms of the Modified BSD License. | |
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 | #----------------------------------------------------------------------------- |
|
|||
22 |
|
14 | |||
23 | import os |
|
15 | import os | |
24 | import struct |
|
16 | import struct | |
25 | import sys |
|
17 | import sys | |
26 | import warnings |
|
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 | from . import py3compat |
|
25 | from . import py3compat | |
30 |
|
26 | |||
@@ -122,4 +118,4 b' def freeze_term_title():' | |||||
122 |
|
118 | |||
123 |
|
119 | |||
124 | def get_terminal_size(defaultx=80, defaulty=25): |
|
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 | import sys |
|
19 | import sys | |
20 |
|
20 | |||
21 | import nose.tools as nt |
|
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 | from IPython.utils import text |
|
28 | from IPython.utils import text | |
25 |
|
29 | |||
@@ -207,7 +211,7 b' def test_LSString():' | |||||
207 | nt.assert_equal(lss.l, ['abc', 'def']) |
|
211 | nt.assert_equal(lss.l, ['abc', 'def']) | |
208 | nt.assert_equal(lss.s, 'abc def') |
|
212 | nt.assert_equal(lss.s, 'abc def') | |
209 | lss = text.LSString(os.getcwd()) |
|
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 | def test_SList(): |
|
216 | def test_SList(): | |
213 | sl = text.SList(['a 11', 'b 1', 'a 2']) |
|
217 | sl = text.SList(['a 11', 'b 1', 'a 2']) |
@@ -14,6 +14,11 b' import re' | |||||
14 | import sys |
|
14 | import sys | |
15 | import textwrap |
|
15 | import textwrap | |
16 | from string import Formatter |
|
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 | from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest |
|
23 | from IPython.testing.skipdoctest import skip_doctest_py3, skip_doctest | |
19 | from IPython.utils import py3compat |
|
24 | from IPython.utils import py3compat | |
@@ -64,11 +69,10 b' class LSString(str):' | |||||
64 | n = nlstr = property(get_nlstr) |
|
69 | n = nlstr = property(get_nlstr) | |
65 |
|
70 | |||
66 | def get_paths(self): |
|
71 | def get_paths(self): | |
67 | from path import path |
|
|||
68 | try: |
|
72 | try: | |
69 | return self.__paths |
|
73 | return self.__paths | |
70 | except AttributeError: |
|
74 | except AttributeError: | |
71 |
self.__paths = [ |
|
75 | self.__paths = [Path(p) for p in self.split('\n') if os.path.exists(p)] | |
72 | return self.__paths |
|
76 | return self.__paths | |
73 |
|
77 | |||
74 | p = paths = property(get_paths) |
|
78 | p = paths = property(get_paths) | |
@@ -123,11 +127,10 b' class SList(list):' | |||||
123 | n = nlstr = property(get_nlstr) |
|
127 | n = nlstr = property(get_nlstr) | |
124 |
|
128 | |||
125 | def get_paths(self): |
|
129 | def get_paths(self): | |
126 | from path import path |
|
|||
127 | try: |
|
130 | try: | |
128 | return self.__paths |
|
131 | return self.__paths | |
129 | except AttributeError: |
|
132 | except AttributeError: | |
130 |
self.__paths = [ |
|
133 | self.__paths = [Path(p) for p in self if os.path.exists(p)] | |
131 | return self.__paths |
|
134 | return self.__paths | |
132 |
|
135 | |||
133 | p = paths = property(get_paths) |
|
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 | See the `install page <http://ipython.org/install.html>`__ to install IPython. |
|
28 | See the `install page <http://ipython.org/install.html>`__ to install IPython. | |
29 |
|
29 | |||
30 | The Notebook, Qt console and a number of other pieces are now parts of *Jupyter*. |
|
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 | if you want to use these. |
|
32 | if you want to use these. | |
33 |
|
33 | |||
34 | Officially, IPython requires Python version 2.7, or 3.3 and above. |
|
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 | if ON_RTD: |
|
22 | if ON_RTD: | |
23 | # Mock the presence of matplotlib, which we don't have on RTD |
|
23 | # Mock the presence of matplotlib, which we don't have on RTD | |
24 | # see |
|
24 | # see | |
25 |
# http://read-the-docs.readthedocs.o |
|
25 | # http://read-the-docs.readthedocs.io/en/latest/faq.html | |
26 | tags.add('rtd') |
|
26 | tags.add('rtd') | |
27 |
|
27 | |||
28 | # RTD doesn't use the Makefile, so re-run autogen_{things}.py here. |
|
28 | # RTD doesn't use the Makefile, so re-run autogen_{things}.py here. | |
@@ -201,12 +201,12 b' html_additional_pages = {' | |||||
201 | # Output file base name for HTML help builder. |
|
201 | # Output file base name for HTML help builder. | |
202 | htmlhelp_basename = 'ipythondoc' |
|
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 | 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), |
|
205 | 'rpy2': ('http://rpy.sourceforge.net/rpy2/doc-2.4/html/', None), | |
206 |
'traitlets': ('http://traitlets.readthedocs.o |
|
206 | 'traitlets': ('http://traitlets.readthedocs.io/en/latest/', None), | |
207 |
'jupyterclient': ('http://jupyter-client.readthedocs.o |
|
207 | 'jupyterclient': ('http://jupyter-client.readthedocs.io/en/latest/', None), | |
208 |
'ipyparallel': ('http://ipyparallel.readthedocs.o |
|
208 | 'ipyparallel': ('http://ipyparallel.readthedocs.io/en/latest/', None), | |
209 |
'jupyter': ('http://jupyter.readthedocs.o |
|
209 | 'jupyter': ('http://jupyter.readthedocs.io/en/latest/', None), | |
210 | } |
|
210 | } | |
211 |
|
211 | |||
212 | # Options for LaTeX output |
|
212 | # Options for LaTeX output |
1 | NO CONTENT: modified file |
|
NO CONTENT: modified file |
@@ -7,7 +7,7 b' You can now re-use the kernel machinery in IPython to easily make new kernels.' | |||||
7 | This is useful for languages that have Python bindings, such as `Octave |
|
7 | This is useful for languages that have Python bindings, such as `Octave | |
8 | <http://www.gnu.org/software/octave/>`_ (via |
|
8 | <http://www.gnu.org/software/octave/>`_ (via | |
9 | `Oct2Py <http://blink1073.github.io/oct2py/docs/index.html>`_), or languages |
|
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 | such as bash. |
|
11 | such as bash. | |
12 |
|
12 | |||
13 | .. seealso:: |
|
13 | .. seealso:: |
@@ -27,10 +27,10 b' Contents' | |||||
27 |
|
27 | |||
28 | .. seealso:: |
|
28 | .. seealso:: | |
29 |
|
29 | |||
30 |
`Jupyter documentation <http://jupyter.readthedocs.o |
|
30 | `Jupyter documentation <http://jupyter.readthedocs.io/en/latest/>`__ | |
31 | The Notebook code and many other pieces formerly in IPython are now parts |
|
31 | The Notebook code and many other pieces formerly in IPython are now parts | |
32 | of Project Jupyter. |
|
32 | of Project Jupyter. | |
33 |
`ipyparallel documentation <http://ipyparallel.readthedocs.o |
|
33 | `ipyparallel documentation <http://ipyparallel.readthedocs.io/en/latest/>`__ | |
34 | Formerly ``IPython.parallel``. |
|
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 | .. seealso:: |
|
3 | .. seealso:: | |
4 |
|
4 | |||
5 |
`Installing Jupyter <http://jupyter.readthedocs.o |
|
5 | `Installing Jupyter <http://jupyter.readthedocs.io/en/latest/install.html>`__ | |
6 | The Notebook, nbconvert, and many other former pieces of IPython are now |
|
6 | The Notebook, nbconvert, and many other former pieces of IPython are now | |
7 | part of Project Jupyter. |
|
7 | part of Project Jupyter. | |
8 |
|
8 |
@@ -15,4 +15,4 b' Using IPython for interactive work' | |||||
15 | .. seealso:: |
|
15 | .. seealso:: | |
16 |
|
16 | |||
17 | `A Qt Console for Jupyter <http://jupyter.org/qtconsole/>`__ |
|
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 | You can read more about using `ipython qtconsole |
|
220 | You can read more about using `ipython qtconsole | |
221 | <http://jupyter.org/qtconsole/>`_, and |
|
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 | is also a :ref:`message spec <messaging>` which documents the protocol for |
|
223 | is also a :ref:`message spec <messaging>` which documents the protocol for | |
224 | communication between kernels |
|
224 | communication between kernels | |
225 | and clients. |
|
225 | and clients. |
@@ -1000,7 +1000,7 b' Pull Requests (793):' | |||||
1000 | * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. |
|
1000 | * :ghpull:`2274`: CLN: Use name to id mapping of notebooks instead of searching. | |
1001 | * :ghpull:`2270`: SSHLauncher tweaks |
|
1001 | * :ghpull:`2270`: SSHLauncher tweaks | |
1002 | * :ghpull:`2269`: add missing location when disambiguating controller IP |
|
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 | * :ghpull:`2256`: Adding data publication example notebook. |
|
1004 | * :ghpull:`2256`: Adding data publication example notebook. | |
1005 | * :ghpull:`2255`: better flush iopub with AsyncResults |
|
1005 | * :ghpull:`2255`: better flush iopub with AsyncResults | |
1006 | * :ghpull:`2261`: Fix: longest_substr([]) -> '' |
|
1006 | * :ghpull:`2261`: Fix: longest_substr([]) -> '' |
@@ -3,9 +3,33 b'' | |||||
3 | Issues closed in the 4.x development cycle |
|
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 | GitHub stats for 2015/08/12 - 2016/02/02 (since 4.0.0) |
|
34 | GitHub stats for 2015/08/12 - 2016/02/02 (since 4.0.0) | |
11 |
|
35 |
@@ -2,6 +2,19 b'' | |||||
2 | 4.x Series |
|
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 | IPython 4.1 |
|
19 | IPython 4.1 | |
7 | =========== |
|
20 | =========== | |
@@ -34,8 +47,8 b' Released August, 2015' | |||||
34 |
|
47 | |||
35 | IPython 4.0 is the first major release after the Big Split. |
|
48 | IPython 4.0 is the first major release after the Big Split. | |
36 | IPython no longer contains the notebook, qtconsole, etc. which have moved to |
|
49 | IPython no longer contains the notebook, qtconsole, etc. which have moved to | |
37 |
`jupyter <https://jupyter.readthedocs.o |
|
50 | `jupyter <https://jupyter.readthedocs.io>`_. | |
38 |
IPython subprojects, such as `IPython.parallel <https://ipyparallel.readthedocs.o |
|
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 | The following subpackages are deprecated: |
|
53 | The following subpackages are deprecated: | |
41 |
|
54 |
@@ -354,7 +354,7 b'' | |||||
354 | "cell_type": "markdown", |
|
354 | "cell_type": "markdown", | |
355 | "metadata": {}, |
|
355 | "metadata": {}, | |
356 | "source": [ |
|
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 | 'traitlets', |
|
198 | 'traitlets', | |
199 | 'prompt_toolkit>=0.60', |
|
199 | 'prompt_toolkit>=0.60', | |
200 | 'pygments', |
|
200 | 'pygments', | |
201 | 'backports.shutil_get_terminal_size', |
|
|||
202 | ] |
|
201 | ] | |
203 |
|
202 | |||
204 | # Platform-specific dependencies: |
|
203 | # Platform-specific dependencies: | |
@@ -206,6 +205,8 b' install_requires = [' | |||||
206 | # but requires pip >= 6. pip < 6 ignores these. |
|
205 | # but requires pip >= 6. pip < 6 ignores these. | |
207 |
|
206 | |||
208 | extras_require.update({ |
|
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 | ':sys_platform != "win32"': ['pexpect'], |
|
210 | ':sys_platform != "win32"': ['pexpect'], | |
210 | ':sys_platform == "darwin"': ['appnope'], |
|
211 | ':sys_platform == "darwin"': ['appnope'], | |
211 | ':sys_platform == "win32"': ['colorama'], |
|
212 | ':sys_platform == "win32"': ['colorama'], |
@@ -168,7 +168,7 b' if __name__ == "__main__":' | |||||
168 | state='closed', |
|
168 | state='closed', | |
169 | auth=True, |
|
169 | auth=True, | |
170 | ) |
|
170 | ) | |
171 | issues, pulls = split_pulls(issues_and_pulls) |
|
171 | issues, pulls = split_pulls(issues_and_pulls, project=project) | |
172 | else: |
|
172 | else: | |
173 | issues = issues_closed_since(since, project=project, pulls=False) |
|
173 | issues = issues_closed_since(since, project=project, pulls=False) | |
174 | pulls = issues_closed_since(since, project=project, pulls=True) |
|
174 | pulls = issues_closed_since(since, project=project, pulls=True) |
General Comments 0
You need to be logged in to leave comments.
Login now