Show More
@@ -0,0 +1,25 b'' | |||||
|
1 | History Range Glob feature | |||
|
2 | ========================== | |||
|
3 | ||||
|
4 | Previously, when using ``%history``, users could specify either | |||
|
5 | a range of sessions and lines, for example: | |||
|
6 | ||||
|
7 | .. code-block:: python | |||
|
8 | ||||
|
9 | ~8/1-~6/5 # see history from the first line of 8 sessions ago, | |||
|
10 | # to the fifth line of 6 sessions ago.`` | |||
|
11 | ||||
|
12 | Or users could specify a glob pattern: | |||
|
13 | ||||
|
14 | .. code-block:: python | |||
|
15 | ||||
|
16 | -g <pattern> # glob ALL history for the specified pattern. | |||
|
17 | ||||
|
18 | However users could *not* specify both. | |||
|
19 | ||||
|
20 | If a user *did* specify both a range and a glob pattern, | |||
|
21 | then the glob pattern would be used (globbing *all* history) *and the range would be ignored*. | |||
|
22 | ||||
|
23 | --- | |||
|
24 | ||||
|
25 | With this enhancment, if a user specifies both a range and a glob pattern, then the glob pattern will be applied to the specified range of history. |
@@ -0,0 +1,7 b'' | |||||
|
1 | Don't start a multiline cell with sunken parenthesis | |||
|
2 | ---------------------------------------------------- | |||
|
3 | ||||
|
4 | From now on IPython will not ask for the next line of input when given a single | |||
|
5 | line with more closing than opening brackets. For example, this means that if | |||
|
6 | you (mis)type ']]' instead of '[]', a ``SyntaxError`` will show up, instead of | |||
|
7 | the ``...:`` prompt continuation. |
@@ -2,9 +2,9 b' name: Run MyPy' | |||||
2 |
|
2 | |||
3 | on: |
|
3 | on: | |
4 | push: |
|
4 | push: | |
5 | branches: [ master ] |
|
5 | branches: [ master, 7.x] | |
6 | pull_request: |
|
6 | pull_request: | |
7 | branches: [ master ] |
|
7 | branches: [ master, 7.x] | |
8 |
|
8 | |||
9 | jobs: |
|
9 | jobs: | |
10 | build: |
|
10 | build: |
@@ -5,9 +5,9 b' name: Python package' | |||||
5 |
|
5 | |||
6 | on: |
|
6 | on: | |
7 | push: |
|
7 | push: | |
8 | branches: [ master ] |
|
8 | branches: [ master, 7.x ] | |
9 | pull_request: |
|
9 | pull_request: | |
10 | branches: [ master ] |
|
10 | branches: [ master, 7.x ] | |
11 |
|
11 | |||
12 | jobs: |
|
12 | jobs: | |
13 | build: |
|
13 | build: |
@@ -37,7 +37,7 b' install:' | |||||
37 | - pip install -e file://$PWD#egg=ipython[test] --upgrade |
|
37 | - pip install -e file://$PWD#egg=ipython[test] --upgrade | |
38 | - pip install trio curio --upgrade --upgrade-strategy eager |
|
38 | - pip install trio curio --upgrade --upgrade-strategy eager | |
39 | - pip install 'pytest' 'matplotlib !=3.2.0' |
|
39 | - pip install 'pytest' 'matplotlib !=3.2.0' | |
40 |
- pip install codecov check-manifest pytest-cov --upgrade anyio pytest- |
|
40 | - pip install codecov check-manifest pytest-cov --upgrade anyio pytest-trio | |
41 |
|
41 | |||
42 |
|
42 | |||
43 | script: |
|
43 | script: |
@@ -112,25 +112,53 b' class CachingCompiler(codeop.Compile):' | |||||
112 | """ |
|
112 | """ | |
113 | return self.flags |
|
113 | return self.flags | |
114 |
|
114 | |||
115 |
def |
|
115 | def get_code_name(self, raw_code, transformed_code, number): | |
|
116 | """Compute filename given the code, and the cell number. | |||
|
117 | ||||
|
118 | Parameters | |||
|
119 | ---------- | |||
|
120 | raw_code : str | |||
|
121 | The raw cell code. | |||
|
122 | transformed_code : str | |||
|
123 | The executable Python source code to cache and compile. | |||
|
124 | number : int | |||
|
125 | A number which forms part of the code's name. Used for the execution | |||
|
126 | counter. | |||
|
127 | ||||
|
128 | Returns | |||
|
129 | ------- | |||
|
130 | The computed filename. | |||
|
131 | """ | |||
|
132 | return code_name(transformed_code, number) | |||
|
133 | ||||
|
134 | def cache(self, transformed_code, number=0, raw_code=None): | |||
116 | """Make a name for a block of code, and cache the code. |
|
135 | """Make a name for a block of code, and cache the code. | |
117 |
|
136 | |||
118 | Parameters |
|
137 | Parameters | |
119 | ---------- |
|
138 | ---------- | |
120 | code : str |
|
139 | transformed_code : str | |
121 | The Python source code to cache. |
|
140 | The executable Python source code to cache and compile. | |
122 | number : int |
|
141 | number : int | |
123 | A number which forms part of the code's name. Used for the execution |
|
142 | A number which forms part of the code's name. Used for the execution | |
124 | counter. |
|
143 | counter. | |
|
144 | raw_code : str | |||
|
145 | The raw code before transformation, if None, set to `transformed_code`. | |||
125 |
|
146 | |||
126 | Returns |
|
147 | Returns | |
127 | ------- |
|
148 | ------- | |
128 | The name of the cached code (as a string). Pass this as the filename |
|
149 | The name of the cached code (as a string). Pass this as the filename | |
129 | argument to compilation, so that tracebacks are correctly hooked up. |
|
150 | argument to compilation, so that tracebacks are correctly hooked up. | |
130 | """ |
|
151 | """ | |
131 | name = code_name(code, number) |
|
152 | if raw_code is None: | |
132 | entry = (len(code), time.time(), |
|
153 | raw_code = transformed_code | |
133 | [line+'\n' for line in code.splitlines()], name) |
|
154 | ||
|
155 | name = self.get_code_name(raw_code, transformed_code, number) | |||
|
156 | entry = ( | |||
|
157 | len(transformed_code), | |||
|
158 | time.time(), | |||
|
159 | [line + "\n" for line in transformed_code.splitlines()], | |||
|
160 | name, | |||
|
161 | ) | |||
134 | linecache.cache[name] = entry |
|
162 | linecache.cache[name] = entry | |
135 | linecache._ipython_cache[name] = entry |
|
163 | linecache._ipython_cache[name] = entry | |
136 | return name |
|
164 | return name |
@@ -201,7 +201,9 b" def provisionalcompleter(action='ignore'):" | |||||
201 |
|
201 | |||
202 | >>> completer.do_experimental_things() # raises. |
|
202 | >>> completer.do_experimental_things() # raises. | |
203 |
|
203 | |||
204 |
.. note:: |
|
204 | .. note:: | |
|
205 | ||||
|
206 | Unstable | |||
205 |
|
207 | |||
206 | By using this context manager you agree that the API in use may change |
|
208 | By using this context manager you agree that the API in use may change | |
207 | without warning, and that you won't complain if they do so. |
|
209 | without warning, and that you won't complain if they do so. | |
@@ -356,7 +358,9 b' class Completion:' | |||||
356 | """ |
|
358 | """ | |
357 | Completion object used and return by IPython completers. |
|
359 | Completion object used and return by IPython completers. | |
358 |
|
360 | |||
359 |
.. warning:: |
|
361 | .. warning:: | |
|
362 | ||||
|
363 | Unstable | |||
360 |
|
364 | |||
361 | This function is unstable, API may change without warning. |
|
365 | This function is unstable, API may change without warning. | |
362 | It will also raise unless use in proper context manager. |
|
366 | It will also raise unless use in proper context manager. | |
@@ -419,7 +423,9 b' def _deduplicate_completions(text: str, completions: _IC)-> _IC:' | |||||
419 | """ |
|
423 | """ | |
420 | Deduplicate a set of completions. |
|
424 | Deduplicate a set of completions. | |
421 |
|
425 | |||
422 |
.. warning:: |
|
426 | .. warning:: | |
|
427 | ||||
|
428 | Unstable | |||
423 |
|
429 | |||
424 | This function is unstable, API may change without warning. |
|
430 | This function is unstable, API may change without warning. | |
425 |
|
431 | |||
@@ -459,7 +465,9 b' def rectify_completions(text: str, completions: _IC, *, _debug=False)->_IC:' | |||||
459 | """ |
|
465 | """ | |
460 | Rectify a set of completions to all have the same ``start`` and ``end`` |
|
466 | Rectify a set of completions to all have the same ``start`` and ``end`` | |
461 |
|
467 | |||
462 |
.. warning:: |
|
468 | .. warning:: | |
|
469 | ||||
|
470 | Unstable | |||
463 |
|
471 | |||
464 | This function is unstable, API may change without warning. |
|
472 | This function is unstable, API may change without warning. | |
465 | It will also raise unless use in proper context manager. |
|
473 | It will also raise unless use in proper context manager. | |
@@ -1837,7 +1845,9 b' class IPCompleter(Completer):' | |||||
1837 | """ |
|
1845 | """ | |
1838 | Returns an iterator over the possible completions |
|
1846 | Returns an iterator over the possible completions | |
1839 |
|
1847 | |||
1840 |
.. warning:: |
|
1848 | .. warning:: | |
|
1849 | ||||
|
1850 | Unstable | |||
1841 |
|
1851 | |||
1842 | This function is unstable, API may change without warning. |
|
1852 | This function is unstable, API may change without warning. | |
1843 | It will also raise unless use in proper context manager. |
|
1853 | It will also raise unless use in proper context manager. |
@@ -23,6 +23,7 b' import os' | |||||
23 | import sys |
|
23 | import sys | |
24 | import traceback |
|
24 | import traceback | |
25 | from pprint import pformat |
|
25 | from pprint import pformat | |
|
26 | from pathlib import Path | |||
26 |
|
27 | |||
27 | from IPython.core import ultratb |
|
28 | from IPython.core import ultratb | |
28 | from IPython.core.release import author_email |
|
29 | from IPython.core.release import author_email | |
@@ -151,10 +152,10 b' class CrashHandler(object):' | |||||
151 | try: |
|
152 | try: | |
152 | rptdir = self.app.ipython_dir |
|
153 | rptdir = self.app.ipython_dir | |
153 | except: |
|
154 | except: | |
154 |
rptdir = |
|
155 | rptdir = Path.cwd() | |
155 |
if rptdir is None or not |
|
156 | if rptdir is None or not Path.is_dir(rptdir): | |
156 |
rptdir = |
|
157 | rptdir = Path.cwd() | |
157 |
report_name = |
|
158 | report_name = rptdir / self.crash_report_fname | |
158 | # write the report filename into the instance dict so it can get |
|
159 | # write the report filename into the instance dict so it can get | |
159 | # properly expanded out in the user message template |
|
160 | # properly expanded out in the user message template | |
160 | self.crash_report_fname = report_name |
|
161 | self.crash_report_fname = report_name |
@@ -50,6 +50,7 b' from pdb import Pdb as OldPdb' | |||||
50 | # it does so with some limitations. The rest of this support is implemented in |
|
50 | # it does so with some limitations. The rest of this support is implemented in | |
51 | # the Tracer constructor. |
|
51 | # the Tracer constructor. | |
52 |
|
52 | |||
|
53 | ||||
53 | def make_arrow(pad): |
|
54 | def make_arrow(pad): | |
54 | """generate the leading arrow in front of traceback or debugger""" |
|
55 | """generate the leading arrow in front of traceback or debugger""" | |
55 | if pad >= 2: |
|
56 | if pad >= 2: | |
@@ -237,7 +238,7 b' class Pdb(OldPdb):' | |||||
237 | self.shell = TerminalInteractiveShell.instance() |
|
238 | self.shell = TerminalInteractiveShell.instance() | |
238 | # needed by any code which calls __import__("__main__") after |
|
239 | # needed by any code which calls __import__("__main__") after | |
239 | # the debugger was entered. See also #9941. |
|
240 | # the debugger was entered. See also #9941. | |
240 |
sys.modules[ |
|
241 | sys.modules["__main__"] = save_main | |
241 |
|
242 | |||
242 | if color_scheme is not None: |
|
243 | if color_scheme is not None: | |
243 | warnings.warn( |
|
244 | warnings.warn( | |
@@ -272,7 +273,6 b' class Pdb(OldPdb):' | |||||
272 | cst['Neutral'].colors.breakpoint_enabled = C.LightRed |
|
273 | cst['Neutral'].colors.breakpoint_enabled = C.LightRed | |
273 | cst['Neutral'].colors.breakpoint_disabled = C.Red |
|
274 | cst['Neutral'].colors.breakpoint_disabled = C.Red | |
274 |
|
275 | |||
275 |
|
||||
276 | # Add a python parser so we can syntax highlight source while |
|
276 | # Add a python parser so we can syntax highlight source while | |
277 | # debugging. |
|
277 | # debugging. | |
278 | self.parser = PyColorize.Parser(style=color_scheme) |
|
278 | self.parser = PyColorize.Parser(style=color_scheme) | |
@@ -320,6 +320,18 b' class Pdb(OldPdb):' | |||||
320 | except KeyboardInterrupt: |
|
320 | except KeyboardInterrupt: | |
321 | self.stdout.write("\n" + self.shell.get_exception_only()) |
|
321 | self.stdout.write("\n" + self.shell.get_exception_only()) | |
322 |
|
322 | |||
|
323 | def precmd(self, line): | |||
|
324 | """Perform useful escapes on the command before it is executed.""" | |||
|
325 | ||||
|
326 | if line.endswith("??"): | |||
|
327 | line = "pinfo2 " + line[:-2] | |||
|
328 | elif line.endswith("?"): | |||
|
329 | line = "pinfo " + line[:-1] | |||
|
330 | ||||
|
331 | line = super().precmd(line) | |||
|
332 | ||||
|
333 | return line | |||
|
334 | ||||
323 | def new_do_frame(self, arg): |
|
335 | def new_do_frame(self, arg): | |
324 | OldPdb.do_frame(self, arg) |
|
336 | OldPdb.do_frame(self, arg) | |
325 |
|
337 | |||
@@ -402,11 +414,10 b' class Pdb(OldPdb):' | |||||
402 |
|
414 | |||
403 | Colors = self.color_scheme_table.active_colors |
|
415 | Colors = self.color_scheme_table.active_colors | |
404 | ColorsNormal = Colors.Normal |
|
416 | ColorsNormal = Colors.Normal | |
405 |
tpl_link = |
|
417 | tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal) | |
406 |
tpl_call = |
|
418 | tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal) | |
407 |
tpl_line = |
|
419 | tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal) | |
408 |
tpl_line_em = |
|
420 | tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal) | |
409 | ColorsNormal) |
|
|||
410 |
|
421 | |||
411 | frame, lineno = frame_lineno |
|
422 | frame, lineno = frame_lineno | |
412 |
|
423 | |||
@@ -439,8 +450,8 b' class Pdb(OldPdb):' | |||||
439 | if frame is self.curframe: |
|
450 | if frame is self.curframe: | |
440 | ret.append('> ') |
|
451 | ret.append('> ') | |
441 | else: |
|
452 | else: | |
442 |
ret.append( |
|
453 | ret.append(" ") | |
443 |
ret.append( |
|
454 | ret.append("%s(%s)%s\n" % (link, lineno, call)) | |
444 |
|
455 | |||
445 | start = lineno - 1 - context//2 |
|
456 | start = lineno - 1 - context//2 | |
446 | lines = linecache.getlines(filename) |
|
457 | lines = linecache.getlines(filename) | |
@@ -449,14 +460,14 b' class Pdb(OldPdb):' | |||||
449 | lines = lines[start : start + context] |
|
460 | lines = lines[start : start + context] | |
450 |
|
461 | |||
451 | for i,line in enumerate(lines): |
|
462 | for i, line in enumerate(lines): | |
452 |
show_arrow = |
|
463 | show_arrow = start + 1 + i == lineno | |
453 |
linetpl = (frame is self.curframe or show_arrow) |
|
464 | linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line | |
454 | and tpl_line_em \ |
|
465 | ret.append( | |
455 |
|
|
466 | self.__format_line( | |
456 | ret.append(self.__format_line(linetpl, filename, |
|
467 | linetpl, filename, start + 1 + i, line, arrow=show_arrow | |
457 | start + 1 + i, line, |
|
468 | ) | |
458 | arrow = show_arrow) ) |
|
469 | ) | |
459 |
return |
|
470 | return "".join(ret) | |
460 |
|
471 | |||
461 |
def __format_line(self, tpl_line, filename, lineno, line, arrow |
|
472 | def __format_line(self, tpl_line, filename, lineno, line, arrow=False): | |
462 | bp_mark = "" |
|
473 | bp_mark = "" | |
@@ -488,7 +499,6 b' class Pdb(OldPdb):' | |||||
488 |
|
499 | |||
489 | return tpl_line % (bp_mark_color + bp_mark, num, line) |
|
500 | return tpl_line % (bp_mark_color + bp_mark, num, line) | |
490 |
|
501 | |||
491 |
|
||||
492 | def print_list_lines(self, filename, first, last): |
|
502 | def print_list_lines(self, filename, first, last): | |
493 | """The printing (as opposed to the parsing part of a 'list' |
|
503 | """The printing (as opposed to the parsing part of a 'list' | |
494 | command.""" |
|
504 | command.""" | |
@@ -507,9 +517,13 b' class Pdb(OldPdb):' | |||||
507 | break |
|
517 | break | |
508 |
|
518 | |||
509 | if lineno == self.curframe.f_lineno: |
|
519 | if lineno == self.curframe.f_lineno: | |
510 |
line = self.__format_line( |
|
520 | line = self.__format_line( | |
|
521 | tpl_line_em, filename, lineno, line, arrow=True | |||
|
522 | ) | |||
511 | else: |
|
523 | else: | |
512 |
line = self.__format_line( |
|
524 | line = self.__format_line( | |
|
525 | tpl_line, filename, lineno, line, arrow=False | |||
|
526 | ) | |||
513 |
|
527 | |||
514 | src.append(line) |
|
528 | src.append(line) | |
515 | self.lineno = lineno |
|
529 | self.lineno = lineno | |
@@ -706,7 +720,7 b' class Pdb(OldPdb):' | |||||
706 |
|
720 | |||
707 | Will skip hidden frames. |
|
721 | Will skip hidden frames. | |
708 | """ |
|
722 | """ | |
709 |
|
|
723 | # modified version of upstream that skips | |
710 | # frames with __tracebackide__ |
|
724 | # frames with __tracebackide__ | |
711 | if self.curindex == 0: |
|
725 | if self.curindex == 0: | |
712 | self.error("Oldest frame") |
|
726 | self.error("Oldest frame") | |
@@ -720,11 +734,9 b' class Pdb(OldPdb):' | |||||
720 | if count < 0: |
|
734 | if count < 0: | |
721 | _newframe = 0 |
|
735 | _newframe = 0 | |
722 | else: |
|
736 | else: | |
723 | _newindex = self.curindex |
|
|||
724 | counter = 0 |
|
737 | counter = 0 | |
725 | hidden_frames = self.hidden_frames(self.stack) |
|
738 | hidden_frames = self.hidden_frames(self.stack) | |
726 | for i in range(self.curindex - 1, -1, -1): |
|
739 | for i in range(self.curindex - 1, -1, -1): | |
727 | frame = self.stack[i][0] |
|
|||
728 | if hidden_frames[i] and self.skip_hidden: |
|
740 | if hidden_frames[i] and self.skip_hidden: | |
729 | skipped += 1 |
|
741 | skipped += 1 | |
730 | continue |
|
742 | continue | |
@@ -765,12 +777,10 b' class Pdb(OldPdb):' | |||||
765 | if count < 0: |
|
777 | if count < 0: | |
766 | _newframe = len(self.stack) - 1 |
|
778 | _newframe = len(self.stack) - 1 | |
767 | else: |
|
779 | else: | |
768 | _newindex = self.curindex |
|
|||
769 | counter = 0 |
|
780 | counter = 0 | |
770 | skipped = 0 |
|
781 | skipped = 0 | |
771 | hidden_frames = self.hidden_frames(self.stack) |
|
782 | hidden_frames = self.hidden_frames(self.stack) | |
772 | for i in range(self.curindex + 1, len(self.stack)): |
|
783 | for i in range(self.curindex + 1, len(self.stack)): | |
773 | frame = self.stack[i][0] |
|
|||
774 | if hidden_frames[i] and self.skip_hidden: |
|
784 | if hidden_frames[i] and self.skip_hidden: | |
775 | skipped += 1 |
|
785 | skipped += 1 | |
776 | continue |
|
786 | continue | |
@@ -796,6 +806,20 b' class Pdb(OldPdb):' | |||||
796 | do_d = do_down |
|
806 | do_d = do_down | |
797 | do_u = do_up |
|
807 | do_u = do_up | |
798 |
|
808 | |||
|
809 | def do_context(self, context): | |||
|
810 | """context number_of_lines | |||
|
811 | Set the number of lines of source code to show when displaying | |||
|
812 | stacktrace information. | |||
|
813 | """ | |||
|
814 | try: | |||
|
815 | new_context = int(context) | |||
|
816 | if new_context <= 0: | |||
|
817 | raise ValueError() | |||
|
818 | self.context = new_context | |||
|
819 | except ValueError: | |||
|
820 | self.error("The 'context' command requires a positive integer argument.") | |||
|
821 | ||||
|
822 | ||||
799 | class InterruptiblePdb(Pdb): |
|
823 | class InterruptiblePdb(Pdb): | |
800 | """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" |
|
824 | """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" | |
801 |
|
825 |
@@ -656,7 +656,6 b' class GeoJSON(JSON):' | |||||
656 |
|
656 | |||
657 | Examples |
|
657 | Examples | |
658 | -------- |
|
658 | -------- | |
659 |
|
||||
660 | The following will display an interactive map of Mars with a point of |
|
659 | The following will display an interactive map of Mars with a point of | |
661 | interest on frontend that do support GeoJSON display. |
|
660 | interest on frontend that do support GeoJSON display. | |
662 |
|
661 | |||
@@ -723,7 +722,7 b' class Javascript(TextDisplayObject):' | |||||
723 | running the source code. The full URLs of the libraries should |
|
722 | running the source code. The full URLs of the libraries should | |
724 | be given. A single Javascript library URL can also be given as a |
|
723 | be given. A single Javascript library URL can also be given as a | |
725 | string. |
|
724 | string. | |
726 |
css |
|
725 | css : list or str | |
727 | A sequence of css files to load before running the source code. |
|
726 | A sequence of css files to load before running the source code. | |
728 | The full URLs of the css files should be given. A single css URL |
|
727 | The full URLs of the css files should be given. A single css URL | |
729 | can also be given as a string. |
|
728 | can also be given as a string. | |
@@ -851,18 +850,26 b' class Image(DisplayObject):' | |||||
851 |
|
850 | |||
852 | Examples |
|
851 | Examples | |
853 | -------- |
|
852 | -------- | |
854 |
|
|
853 | embedded image data, works in qtconsole and notebook | |
855 |
|
|
854 | when passed positionally, the first arg can be any of raw image data, | |
856 |
|
|
855 | a URL, or a filename from which to load image data. | |
857 |
|
|
856 | The result is always embedding image data for inline images. | |
858 | Image('http://www.google.fr/images/srpr/logo3w.png') |
|
857 | ||
859 | Image('/path/to/image.jpg') |
|
858 | >>> Image('http://www.google.fr/images/srpr/logo3w.png') | |
860 | Image(b'RAW_PNG_DATA...') |
|
859 | <IPython.core.display.Image object> | |
861 |
|
860 | |||
862 | # Specifying Image(url=...) does not embed the image data, |
|
861 | >>> Image('/path/to/image.jpg') | |
863 | # it only generates `<img>` tag with a link to the source. |
|
862 | <IPython.core.display.Image object> | |
864 | # This will not work in the qtconsole or offline. |
|
863 | ||
865 | Image(url='http://www.google.fr/images/srpr/logo3w.png') |
|
864 | >>> Image(b'RAW_PNG_DATA...') | |
|
865 | <IPython.core.display.Image object> | |||
|
866 | ||||
|
867 | Specifying Image(url=...) does not embed the image data, | |||
|
868 | it only generates ``<img>`` tag with a link to the source. | |||
|
869 | This will not work in the qtconsole or offline. | |||
|
870 | ||||
|
871 | >>> Image(url='http://www.google.fr/images/srpr/logo3w.png') | |||
|
872 | <IPython.core.display.Image object> | |||
866 |
|
873 | |||
867 | """ |
|
874 | """ | |
868 | if isinstance(data, (Path, PurePath)): |
|
875 | if isinstance(data, (Path, PurePath)): | |
@@ -1036,24 +1043,23 b' class Video(DisplayObject):' | |||||
1036 | ---------- |
|
1043 | ---------- | |
1037 | data : unicode, str or bytes |
|
1044 | data : unicode, str or bytes | |
1038 | The raw video data or a URL or filename to load the data from. |
|
1045 | The raw video data or a URL or filename to load the data from. | |
1039 | Raw data will require passing `embed=True`. |
|
1046 | Raw data will require passing ``embed=True``. | |
1040 | url : unicode |
|
1047 | url : unicode | |
1041 | A URL for the video. If you specify `url=`, |
|
1048 | A URL for the video. If you specify ``url=``, | |
1042 | the image data will not be embedded. |
|
1049 | the image data will not be embedded. | |
1043 | filename : unicode |
|
1050 | filename : unicode | |
1044 | Path to a local file containing the video. |
|
1051 | Path to a local file containing the video. | |
1045 | Will be interpreted as a local URL unless `embed=True`. |
|
1052 | Will be interpreted as a local URL unless ``embed=True``. | |
1046 | embed : bool |
|
1053 | embed : bool | |
1047 | Should the video be embedded using a data URI (True) or be |
|
1054 | Should the video be embedded using a data URI (True) or be | |
1048 | loaded using a <video> tag (False). |
|
1055 | loaded using a <video> tag (False). | |
1049 |
|
1056 | |||
1050 | Since videos are large, embedding them should be avoided, if possible. |
|
1057 | Since videos are large, embedding them should be avoided, if possible. | |
1051 | You must confirm embedding as your intention by passing `embed=True`. |
|
1058 | You must confirm embedding as your intention by passing ``embed=True``. | |
1052 |
|
1059 | |||
1053 | Local files can be displayed with URLs without embedding the content, via:: |
|
1060 | Local files can be displayed with URLs without embedding the content, via:: | |
1054 |
|
1061 | |||
1055 | Video('./video.mp4') |
|
1062 | Video('./video.mp4') | |
1056 |
|
||||
1057 | mimetype: unicode |
|
1063 | mimetype : unicode | |
1058 | Specify the mimetype for embedded videos. |
|
1064 | Specify the mimetype for embedded videos. | |
1059 | Default will be guessed from file extension, if available. |
|
1065 | Default will be guessed from file extension, if available. | |
@@ -1064,14 +1070,13 b' class Video(DisplayObject):' | |||||
1064 | Height in pixels to which to constrain the video in html. |
|
1070 | Height in pixels to which to constrain the video in html. | |
1065 | If not supplied, defaults to the height of the video. |
|
1071 | If not supplied, defaults to the height of the video. | |
1066 | html_attributes : str |
|
1072 | html_attributes : str | |
1067 | Attributes for the HTML `<video>` block. |
|
1073 | Attributes for the HTML ``<video>`` block. | |
1068 | Default: `"controls"` to get video controls. |
|
1074 | Default: ``"controls"`` to get video controls. | |
1069 | Other examples: `"controls muted"` for muted video with controls, |
|
1075 | Other examples: ``"controls muted"`` for muted video with controls, | |
1070 | `"loop autoplay"` for looping autoplaying video without controls. |
|
1076 | ``"loop autoplay"`` for looping autoplaying video without controls. | |
1071 |
|
1077 | |||
1072 | Examples |
|
1078 | Examples | |
1073 | -------- |
|
1079 | -------- | |
1074 |
|
||||
1075 | :: |
|
1080 | :: | |
1076 |
|
1081 | |||
1077 | Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4') |
|
1082 | Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4') | |
@@ -1165,7 +1170,7 b' def set_matplotlib_formats(*formats, **kwargs):' | |||||
1165 | ---------- |
|
1170 | ---------- | |
1166 | *formats : strs |
|
1171 | *formats : strs | |
1167 | One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'. |
|
1172 | One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'. | |
1168 |
**kwargs |
|
1173 | **kwargs | |
1169 | Keyword args will be relayed to ``figure.canvas.print_figure``. |
|
1174 | Keyword args will be relayed to ``figure.canvas.print_figure``. | |
1170 | """ |
|
1175 | """ | |
1171 | from IPython.core.interactiveshell import InteractiveShell |
|
1176 | from IPython.core.interactiveshell import InteractiveShell |
@@ -508,6 +508,20 b' def make_tokens_by_line(lines:List[str]):' | |||||
508 |
|
508 | |||
509 | return tokens_by_line |
|
509 | return tokens_by_line | |
510 |
|
510 | |||
|
511 | ||||
|
512 | def has_sunken_brackets(tokens: List[tokenize.TokenInfo]): | |||
|
513 | """Check if the depth of brackets in the list of tokens drops below 0""" | |||
|
514 | parenlev = 0 | |||
|
515 | for token in tokens: | |||
|
516 | if token.string in {"(", "[", "{"}: | |||
|
517 | parenlev += 1 | |||
|
518 | elif token.string in {")", "]", "}"}: | |||
|
519 | parenlev -= 1 | |||
|
520 | if parenlev < 0: | |||
|
521 | return True | |||
|
522 | return False | |||
|
523 | ||||
|
524 | ||||
511 | def show_linewise_tokens(s: str): |
|
525 | def show_linewise_tokens(s: str): | |
512 | """For investigation and debugging""" |
|
526 | """For investigation and debugging""" | |
513 | if not s.endswith('\n'): |
|
527 | if not s.endswith('\n'): | |
@@ -662,6 +676,15 b' class TransformerManager:' | |||||
662 |
|
676 | |||
663 | tokens_by_line = make_tokens_by_line(lines) |
|
677 | tokens_by_line = make_tokens_by_line(lines) | |
664 |
|
678 | |||
|
679 | # Bail if we got one line and there are more closing parentheses than | |||
|
680 | # the opening ones | |||
|
681 | if ( | |||
|
682 | len(lines) == 1 | |||
|
683 | and tokens_by_line | |||
|
684 | and has_sunken_brackets(tokens_by_line[0]) | |||
|
685 | ): | |||
|
686 | return "invalid", None | |||
|
687 | ||||
665 | if not tokens_by_line: |
|
688 | if not tokens_by_line: | |
666 | return 'incomplete', find_last_indent(lines) |
|
689 | return 'incomplete', find_last_indent(lines) | |
667 |
|
690 |
@@ -443,6 +443,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
443 | display_formatter = Instance(DisplayFormatter, allow_none=True) |
|
443 | display_formatter = Instance(DisplayFormatter, allow_none=True) | |
444 | displayhook_class = Type(DisplayHook) |
|
444 | displayhook_class = Type(DisplayHook) | |
445 | display_pub_class = Type(DisplayPublisher) |
|
445 | display_pub_class = Type(DisplayPublisher) | |
|
446 | compiler_class = Type(CachingCompiler) | |||
446 |
|
447 | |||
447 | sphinxify_docstring = Bool(False, help= |
|
448 | sphinxify_docstring = Bool(False, help= | |
448 | """ |
|
449 | """ | |
@@ -748,7 +749,7 b' class InteractiveShell(SingletonConfigurable):' | |||||
748 | self.more = False |
|
749 | self.more = False | |
749 |
|
750 | |||
750 | # command compiler |
|
751 | # command compiler | |
751 |
self.compile = |
|
752 | self.compile = self.compiler_class() | |
752 |
|
753 | |||
753 | # Make an empty namespace, which extension writers can rely on both |
|
754 | # Make an empty namespace, which extension writers can rely on both | |
754 | # existing and NEVER being used by ipython itself. This gives them a |
|
755 | # existing and NEVER being used by ipython itself. This gives them a | |
@@ -931,17 +932,27 b' class InteractiveShell(SingletonConfigurable):' | |||||
931 | # Our exe is inside or has access to the virtualenv, don't need to do anything. |
|
932 | # Our exe is inside or has access to the virtualenv, don't need to do anything. | |
932 | return |
|
933 | return | |
933 |
|
934 | |||
934 | warn("Attempting to work in a virtualenv. If you encounter problems, please " |
|
|||
935 | "install IPython inside the virtualenv.") |
|
|||
936 | if sys.platform == "win32": |
|
935 | if sys.platform == "win32": | |
937 |
virtual_env = Path(os.environ["VIRTUAL_ENV"]) |
|
936 | virtual_env = Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages") | |
938 | "Lib", "site-packages" |
|
|||
939 | ) |
|
|||
940 | else: |
|
937 | else: | |
941 |
virtual_env = Path( |
|
938 | virtual_env_path = Path( | |
942 |
"lib", "python{}.{}" |
|
939 | os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages" | |
943 | ) |
|
940 | ) | |
|
941 | p_ver = sys.version_info[:2] | |||
|
942 | ||||
|
943 | # Predict version from py[thon]-x.x in the $VIRTUAL_ENV | |||
|
944 | re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"]) | |||
|
945 | if re_m: | |||
|
946 | predicted_path = Path(str(virtual_env_path).format(*re_m.groups())) | |||
|
947 | if predicted_path.exists(): | |||
|
948 | p_ver = re_m.groups() | |||
944 |
|
949 | |||
|
950 | virtual_env = str(virtual_env_path).format(*p_ver) | |||
|
951 | ||||
|
952 | warn( | |||
|
953 | "Attempting to work in a virtualenv. If you encounter problems, " | |||
|
954 | "please install IPython inside the virtualenv." | |||
|
955 | ) | |||
945 | import site |
|
956 | import site | |
946 | sys.path.insert(0, virtual_env) |
|
957 | sys.path.insert(0, virtual_env) | |
947 | site.addsitedir(virtual_env) |
|
958 | site.addsitedir(virtual_env) | |
@@ -1765,8 +1776,14 b' class InteractiveShell(SingletonConfigurable):' | |||||
1765 | if meth == 'pdoc': |
|
1776 | if meth == 'pdoc': | |
1766 | pmethod(info.obj, oname, formatter) |
|
1777 | pmethod(info.obj, oname, formatter) | |
1767 | elif meth == 'pinfo': |
|
1778 | elif meth == 'pinfo': | |
1768 | pmethod(info.obj, oname, formatter, info, |
|
1779 | pmethod( | |
1769 | enable_html_pager=self.enable_html_pager, **kw) |
|
1780 | info.obj, | |
|
1781 | oname, | |||
|
1782 | formatter, | |||
|
1783 | info, | |||
|
1784 | enable_html_pager=self.enable_html_pager, | |||
|
1785 | **kw | |||
|
1786 | ) | |||
1770 | else: |
|
1787 | else: | |
1771 | pmethod(info.obj, oname) |
|
1788 | pmethod(info.obj, oname) | |
1772 | else: |
|
1789 | else: | |
@@ -2289,8 +2306,9 b' class InteractiveShell(SingletonConfigurable):' | |||||
2289 | # Defined here so that it's included in the documentation |
|
2306 | # Defined here so that it's included in the documentation | |
2290 | @functools.wraps(magic.MagicsManager.register_function) |
|
2307 | @functools.wraps(magic.MagicsManager.register_function) | |
2291 | def register_magic_function(self, func, magic_kind='line', magic_name=None): |
|
2308 | def register_magic_function(self, func, magic_kind='line', magic_name=None): | |
2292 |
self.magics_manager.register_function( |
|
2309 | self.magics_manager.register_function( | |
2293 |
|
|
2310 | func, magic_kind=magic_kind, magic_name=magic_name | |
|
2311 | ) | |||
2294 |
|
2312 | |||
2295 | def run_line_magic(self, magic_name, line, _stack_depth=1): |
|
2313 | def run_line_magic(self, magic_name, line, _stack_depth=1): | |
2296 | """Execute the given line magic. |
|
2314 | """Execute the given line magic. | |
@@ -3086,12 +3104,14 b' class InteractiveShell(SingletonConfigurable):' | |||||
3086 | # Our own compiler remembers the __future__ environment. If we want to |
|
3104 | # Our own compiler remembers the __future__ environment. If we want to | |
3087 | # run code with a separate __future__ environment, use the default |
|
3105 | # run code with a separate __future__ environment, use the default | |
3088 | # compiler |
|
3106 | # compiler | |
3089 |
compiler = self.compile if shell_futures else |
|
3107 | compiler = self.compile if shell_futures else self.compiler_class() | |
3090 |
|
3108 | |||
3091 | _run_async = False |
|
3109 | _run_async = False | |
3092 |
|
3110 | |||
3093 | with self.builtin_trap: |
|
3111 | with self.builtin_trap: | |
3094 |
cell_name = self.compile.cache( |
|
3112 | cell_name = self.compile.cache( | |
|
3113 | cell, self.execution_count, raw_code=raw_cell | |||
|
3114 | ) | |||
3095 |
|
3115 | |||
3096 | with self.display_trap: |
|
3116 | with self.display_trap: | |
3097 | # Compile to bytecode |
|
3117 | # Compile to bytecode |
@@ -20,7 +20,7 b' import re' | |||||
20 | import sys |
|
20 | import sys | |
21 | import ast |
|
21 | import ast | |
22 | from itertools import chain |
|
22 | from itertools import chain | |
23 | from urllib.request import urlopen |
|
23 | from urllib.request import Request, urlopen | |
24 | from urllib.parse import urlencode |
|
24 | from urllib.parse import urlencode | |
25 | from pathlib import Path |
|
25 | from pathlib import Path | |
26 |
|
26 | |||
@@ -29,6 +29,7 b' from IPython.core.error import TryNext, StdinNotImplementedError, UsageError' | |||||
29 | from IPython.core.macro import Macro |
|
29 | from IPython.core.macro import Macro | |
30 | from IPython.core.magic import Magics, magics_class, line_magic |
|
30 | from IPython.core.magic import Magics, magics_class, line_magic | |
31 | from IPython.core.oinspect import find_file, find_source_lines |
|
31 | from IPython.core.oinspect import find_file, find_source_lines | |
|
32 | from IPython.core.release import version | |||
32 | from IPython.testing.skipdoctest import skip_doctest |
|
33 | from IPython.testing.skipdoctest import skip_doctest | |
33 | from IPython.utils.contexts import preserve_keys |
|
34 | from IPython.utils.contexts import preserve_keys | |
34 | from IPython.utils.path import get_py_filename |
|
35 | from IPython.utils.path import get_py_filename | |
@@ -245,7 +246,7 b' class CodeMagics(Magics):' | |||||
245 |
|
246 | |||
246 | @line_magic |
|
247 | @line_magic | |
247 | def pastebin(self, parameter_s=''): |
|
248 | def pastebin(self, parameter_s=''): | |
248 |
"""Upload code to dpaste |
|
249 | """Upload code to dpaste.com, returning the URL. | |
249 |
|
250 | |||
250 | Usage:\\ |
|
251 | Usage:\\ | |
251 | %pastebin [-d "Custom description"] 1-7 |
|
252 | %pastebin [-d "Custom description"] 1-7 | |
@@ -255,7 +256,7 b' class CodeMagics(Magics):' | |||||
255 |
|
256 | |||
256 | Options: |
|
257 | Options: | |
257 |
|
258 | |||
258 |
-d: Pass a custom description |
|
259 | -d: Pass a custom description. The default will say | |
259 | "Pasted from IPython". |
|
260 | "Pasted from IPython". | |
260 | """ |
|
261 | """ | |
261 | opts, args = self.parse_options(parameter_s, 'd:') |
|
262 | opts, args = self.parse_options(parameter_s, 'd:') | |
@@ -266,13 +267,19 b' class CodeMagics(Magics):' | |||||
266 | print(e.args[0]) |
|
267 | print(e.args[0]) | |
267 | return |
|
268 | return | |
268 |
|
269 | |||
269 |
post_data = urlencode( |
|
270 | post_data = urlencode( | |
270 | "title": opts.get('d', "Pasted from IPython"), |
|
271 | { | |
271 | "syntax": "python3", |
|
272 | "title": opts.get("d", "Pasted from IPython"), | |
272 | "content": code |
|
273 | "syntax": "python", | |
273 | }).encode('utf-8') |
|
274 | "content": code, | |
274 |
|
275 | } | ||
275 | response = urlopen("http://dpaste.com/api/v2/", post_data) |
|
276 | ).encode("utf-8") | |
|
277 | ||||
|
278 | request = Request( | |||
|
279 | "http://dpaste.com/api/v2/", | |||
|
280 | headers={"User-Agent": "IPython v{}".format(version)}, | |||
|
281 | ) | |||
|
282 | response = urlopen(request, post_data) | |||
276 | return response.headers.get('Location') |
|
283 | return response.headers.get('Location') | |
277 |
|
284 | |||
278 | @line_magic |
|
285 | @line_magic |
@@ -16,6 +16,7 b'' | |||||
16 | import os |
|
16 | import os | |
17 | import sys |
|
17 | import sys | |
18 | from io import open as io_open |
|
18 | from io import open as io_open | |
|
19 | import fnmatch | |||
19 |
|
20 | |||
20 | # Our own packages |
|
21 | # Our own packages | |
21 | from IPython.core.error import StdinNotImplementedError |
|
22 | from IPython.core.error import StdinNotImplementedError | |
@@ -170,7 +171,8 b' class HistoryMagics(Magics):' | |||||
170 | pattern = None |
|
171 | pattern = None | |
171 | limit = None if args.limit is _unspecified else args.limit |
|
172 | limit = None if args.limit is _unspecified else args.limit | |
172 |
|
173 | |||
173 |
|
|
174 | range_pattern = False | |
|
175 | if args.pattern is not None and not args.range: | |||
174 | if args.pattern: |
|
176 | if args.pattern: | |
175 | pattern = "*" + " ".join(args.pattern) + "*" |
|
177 | pattern = "*" + " ".join(args.pattern) + "*" | |
176 | else: |
|
178 | else: | |
@@ -183,6 +185,9 b' class HistoryMagics(Magics):' | |||||
183 | hist = history_manager.get_tail(n, raw=raw, output=get_output) |
|
185 | hist = history_manager.get_tail(n, raw=raw, output=get_output) | |
184 | else: |
|
186 | else: | |
185 | if args.range: # Get history by ranges |
|
187 | if args.range: # Get history by ranges | |
|
188 | if args.pattern: | |||
|
189 | range_pattern = "*" + " ".join(args.pattern) + "*" | |||
|
190 | print_nums = True | |||
186 | hist = history_manager.get_range_by_str(" ".join(args.range), |
|
191 | hist = history_manager.get_range_by_str(" ".join(args.range), | |
187 | raw, get_output) |
|
192 | raw, get_output) | |
188 | else: # Just get history for the current session |
|
193 | else: # Just get history for the current session | |
@@ -200,6 +205,9 b' class HistoryMagics(Magics):' | |||||
200 | # into an editor. |
|
205 | # into an editor. | |
201 | if get_output: |
|
206 | if get_output: | |
202 | inline, output = inline |
|
207 | inline, output = inline | |
|
208 | if range_pattern: | |||
|
209 | if not fnmatch.fnmatch(inline, range_pattern): | |||
|
210 | continue | |||
203 | inline = inline.expandtabs(4).rstrip() |
|
211 | inline = inline.expandtabs(4).rstrip() | |
204 |
|
212 | |||
205 | multiline = "\n" in inline |
|
213 | multiline = "\n" in inline |
@@ -13,7 +13,6 b' import shlex' | |||||
13 | import sys |
|
13 | import sys | |
14 | from pathlib import Path |
|
14 | from pathlib import Path | |
15 |
|
15 | |||
16 | from pathlib import Path |
|
|||
17 | from IPython.core.magic import Magics, magics_class, line_magic |
|
16 | from IPython.core.magic import Magics, magics_class, line_magic | |
18 |
|
17 | |||
19 |
|
18 | |||
@@ -28,7 +27,7 b' def _get_conda_executable():' | |||||
28 | # Check if there is a conda executable in the same directory as the Python executable. |
|
27 | # Check if there is a conda executable in the same directory as the Python executable. | |
29 | # This is the case within conda's root environment. |
|
28 | # This is the case within conda's root environment. | |
30 | conda = Path(sys.executable).parent / "conda" |
|
29 | conda = Path(sys.executable).parent / "conda" | |
31 | if conda.isfile(): |
|
30 | if conda.is_file(): | |
32 | return str(conda) |
|
31 | return str(conda) | |
33 |
|
32 | |||
34 | # Otherwise, attempt to extract the executable from conda history. |
|
33 | # Otherwise, attempt to extract the executable from conda history. | |
@@ -83,8 +82,9 b' class PackagingMagics(Magics):' | |||||
83 |
|
82 | |||
84 | conda = _get_conda_executable() |
|
83 | conda = _get_conda_executable() | |
85 | args = shlex.split(line) |
|
84 | args = shlex.split(line) | |
86 | command = args[0] |
|
85 | command = args[0] if len(args) > 0 else "" | |
87 | args = args[1:] |
|
86 | args = args[1:] if len(args) > 1 else [""] | |
|
87 | ||||
88 | extra_args = [] |
|
88 | extra_args = [] | |
89 |
|
89 | |||
90 | # When the subprocess does not allow us to respond "yes" during the installation, |
|
90 | # When the subprocess does not allow us to respond "yes" during the installation, |
@@ -183,7 +183,7 b' def test_set_matplotlib_formats_kwargs():' | |||||
183 | ip = get_ipython() |
|
183 | ip = get_ipython() | |
184 | cfg = _get_inline_config() |
|
184 | cfg = _get_inline_config() | |
185 | cfg.print_figure_kwargs.update(dict(foo='bar')) |
|
185 | cfg.print_figure_kwargs.update(dict(foo='bar')) | |
186 |
kwargs = dict( |
|
186 | kwargs = dict(dpi=150) | |
187 | display.set_matplotlib_formats('png', **kwargs) |
|
187 | display.set_matplotlib_formats('png', **kwargs) | |
188 | formatter = ip.display_formatter.formatters['image/png'] |
|
188 | formatter = ip.display_formatter.formatters['image/png'] | |
189 | f = formatter.lookup_by_type(Figure) |
|
189 | f = formatter.lookup_by_type(Figure) |
@@ -255,18 +255,18 b' def test_find_assign_op_dedent():' | |||||
255 |
|
255 | |||
256 | def test_check_complete(): |
|
256 | def test_check_complete(): | |
257 | cc = ipt2.TransformerManager().check_complete |
|
257 | cc = ipt2.TransformerManager().check_complete | |
258 |
nt.assert_equal(cc("a = 1"), ( |
|
258 | nt.assert_equal(cc("a = 1"), ("complete", None)) | |
259 |
nt.assert_equal(cc("for a in range(5):"), ( |
|
259 | nt.assert_equal(cc("for a in range(5):"), ("incomplete", 4)) | |
260 |
nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ( |
|
260 | nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ("incomplete", 8)) | |
261 |
nt.assert_equal(cc("raise = 2"), ( |
|
261 | nt.assert_equal(cc("raise = 2"), ("invalid", None)) | |
262 |
nt.assert_equal(cc("a = [1,\n2,"), ( |
|
262 | nt.assert_equal(cc("a = [1,\n2,"), ("incomplete", 0)) | |
263 |
nt.assert_equal(cc(")"), ( |
|
263 | nt.assert_equal(cc("(\n))"), ("incomplete", 0)) | |
264 |
nt.assert_equal(cc("\\\r\n"), ( |
|
264 | nt.assert_equal(cc("\\\r\n"), ("incomplete", 0)) | |
265 |
nt.assert_equal(cc("a = '''\n hi"), ( |
|
265 | nt.assert_equal(cc("a = '''\n hi"), ("incomplete", 3)) | |
266 |
nt.assert_equal(cc("def a():\n x=1\n global x"), ( |
|
266 | nt.assert_equal(cc("def a():\n x=1\n global x"), ("invalid", None)) | |
267 |
nt.assert_equal(cc("a \\ "), ( |
|
267 | nt.assert_equal(cc("a \\ "), ("invalid", None)) # Nothing allowed after backslash | |
268 |
nt.assert_equal(cc("1\\\n+2"), ( |
|
268 | nt.assert_equal(cc("1\\\n+2"), ("complete", None)) | |
269 |
nt.assert_equal(cc("exit"), ( |
|
269 | nt.assert_equal(cc("exit"), ("complete", None)) | |
270 |
|
270 | |||
271 | example = dedent(""" |
|
271 | example = dedent(""" | |
272 | if True: |
|
272 | if True: | |
@@ -297,6 +297,24 b' def test_check_complete_II():' | |||||
297 | nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4)) |
|
297 | nt.assert_equal(cc('''def foo():\n """'''), ('incomplete', 4)) | |
298 |
|
298 | |||
299 |
|
299 | |||
|
300 | def test_check_complete_invalidates_sunken_brackets(): | |||
|
301 | """ | |||
|
302 | Test that a single line with more closing brackets than the opening ones is | |||
|
303 | interpretted as invalid | |||
|
304 | """ | |||
|
305 | cc = ipt2.TransformerManager().check_complete | |||
|
306 | nt.assert_equal(cc(")"), ("invalid", None)) | |||
|
307 | nt.assert_equal(cc("]"), ("invalid", None)) | |||
|
308 | nt.assert_equal(cc("}"), ("invalid", None)) | |||
|
309 | nt.assert_equal(cc(")("), ("invalid", None)) | |||
|
310 | nt.assert_equal(cc("]["), ("invalid", None)) | |||
|
311 | nt.assert_equal(cc("}{"), ("invalid", None)) | |||
|
312 | nt.assert_equal(cc("]()("), ("invalid", None)) | |||
|
313 | nt.assert_equal(cc("())("), ("invalid", None)) | |||
|
314 | nt.assert_equal(cc(")[]("), ("invalid", None)) | |||
|
315 | nt.assert_equal(cc("()]("), ("invalid", None)) | |||
|
316 | ||||
|
317 | ||||
300 | def test_null_cleanup_transformer(): |
|
318 | def test_null_cleanup_transformer(): | |
301 | manager = ipt2.TransformerManager() |
|
319 | manager = ipt2.TransformerManager() | |
302 | manager.cleanup_transforms.insert(0, null_cleanup_transformer) |
|
320 | manager.cleanup_transforms.insert(0, null_cleanup_transformer) |
@@ -117,84 +117,91 b' ZeroDivisionError Traceback (most recent call last)' | |||||
117 | ZeroDivisionError: ... |
|
117 | ZeroDivisionError: ... | |
118 | """ |
|
118 | """ | |
119 |
|
119 | |||
120 | def doctest_tb_sysexit(): |
|
120 | # TODO : Marc 2021 – this seem to fail due | |
121 | """ |
|
121 | # to upstream changes in CI for whatever reason. | |
122 | In [17]: %xmode plain |
|
122 | # Commenting for now, to revive someday (maybe?) | |
123 | Exception reporting mode: Plain |
|
123 | # nose won't work in 3.10 anyway and we'll have to disable iptest. | |
124 |
|
124 | # thus this likely need to bemigrated to pytest. | ||
125 | In [18]: %run simpleerr.py exit |
|
125 | ||
126 | An exception has occurred, use %tb to see the full traceback. |
|
126 | ||
127 | SystemExit: (1, 'Mode = exit') |
|
127 | # def doctest_tb_sysexit(): | |
128 |
|
128 | # """ | ||
129 | In [19]: %run simpleerr.py exit 2 |
|
129 | # In [17]: %xmode plain | |
130 | An exception has occurred, use %tb to see the full traceback. |
|
130 | # Exception reporting mode: Plain | |
131 | SystemExit: (2, 'Mode = exit') |
|
131 | # | |
132 |
|
132 | # In [18]: %run simpleerr.py exit | ||
133 | In [20]: %tb |
|
133 | # An exception has occurred, use %tb to see the full traceback. | |
134 | Traceback (most recent call last): |
|
134 | # SystemExit: (1, 'Mode = exit') | |
135 | File ... in <module> |
|
135 | # | |
136 | bar(mode) |
|
136 | # In [19]: %run simpleerr.py exit 2 | |
137 | File ... line 22, in bar |
|
137 | # An exception has occurred, use %tb to see the full traceback. | |
138 | sysexit(stat, mode) |
|
138 | # SystemExit: (2, 'Mode = exit') | |
139 | File ... line 11, in sysexit |
|
139 | # | |
140 | raise SystemExit(stat, 'Mode = %s' % mode) |
|
140 | # In [20]: %tb | |
141 | SystemExit: (2, 'Mode = exit') |
|
141 | # Traceback (most recent call last): | |
142 |
|
142 | # File ... in <module> | ||
143 | In [21]: %xmode context |
|
143 | # bar(mode) | |
144 | Exception reporting mode: Context |
|
144 | # File ... line 22, in bar | |
145 |
|
145 | # sysexit(stat, mode) | ||
146 | In [22]: %tb |
|
146 | # File ... line 11, in sysexit | |
147 | --------------------------------------------------------------------------- |
|
147 | # raise SystemExit(stat, 'Mode = %s' % mode) | |
148 | SystemExit Traceback (most recent call last) |
|
148 | # SystemExit: (2, 'Mode = exit') | |
149 | <BLANKLINE> |
|
149 | # | |
150 | ...<module> |
|
150 | # In [21]: %xmode context | |
151 | 29 except IndexError: |
|
151 | # Exception reporting mode: Context | |
152 | 30 mode = 'div' |
|
152 | # | |
153 | ---> 32 bar(mode) |
|
153 | # In [22]: %tb | |
154 | <BLANKLINE> |
|
154 | # --------------------------------------------------------------------------- | |
155 | ...bar(mode) |
|
155 | # SystemExit Traceback (most recent call last) | |
156 | 20 except: |
|
156 | # <BLANKLINE> | |
157 | 21 stat = 1 |
|
157 | # ...<module> | |
158 | ---> 22 sysexit(stat, mode) |
|
158 | # 29 except IndexError: | |
159 | 23 else: |
|
159 | # 30 mode = 'div' | |
160 | 24 raise ValueError('Unknown mode') |
|
160 | # ---> 32 bar(mode) | |
161 | <BLANKLINE> |
|
161 | # <BLANKLINE> | |
162 | ...sysexit(stat, mode) |
|
162 | # ...bar(mode) | |
163 | 10 def sysexit(stat, mode): |
|
163 | # 20 except: | |
164 | ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) |
|
164 | # 21 stat = 1 | |
165 | <BLANKLINE> |
|
165 | # ---> 22 sysexit(stat, mode) | |
166 | SystemExit: (2, 'Mode = exit') |
|
166 | # 23 else: | |
167 |
|
167 | # 24 raise ValueError('Unknown mode') | ||
168 | In [23]: %xmode verbose |
|
168 | # <BLANKLINE> | |
169 | Exception reporting mode: Verbose |
|
169 | # ...sysexit(stat, mode) | |
170 |
|
170 | # 10 def sysexit(stat, mode): | ||
171 | In [24]: %tb |
|
171 | # ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) | |
172 | --------------------------------------------------------------------------- |
|
172 | # <BLANKLINE> | |
173 | SystemExit Traceback (most recent call last) |
|
173 | # SystemExit: (2, 'Mode = exit') | |
174 | <BLANKLINE> |
|
174 | # | |
175 | ... in <module> |
|
175 | # In [23]: %xmode verbose | |
176 | 29 except IndexError: |
|
176 | # Exception reporting mode: Verbose | |
177 | 30 mode = 'div' |
|
177 | # | |
178 | ---> 32 bar(mode) |
|
178 | # In [24]: %tb | |
179 | mode = 'exit' |
|
179 | # --------------------------------------------------------------------------- | |
180 | <BLANKLINE> |
|
180 | # SystemExit Traceback (most recent call last) | |
181 | ... in bar(mode='exit') |
|
181 | # <BLANKLINE> | |
182 | 20 except: |
|
182 | # ... in <module> | |
183 | 21 stat = 1 |
|
183 | # 29 except IndexError: | |
184 | ---> 22 sysexit(stat, mode) |
|
184 | # 30 mode = 'div' | |
185 | mode = 'exit' |
|
185 | # ---> 32 bar(mode) | |
186 | stat = 2 |
|
186 | # mode = 'exit' | |
187 | 23 else: |
|
187 | # <BLANKLINE> | |
188 | 24 raise ValueError('Unknown mode') |
|
188 | # ... in bar(mode='exit') | |
189 | <BLANKLINE> |
|
189 | # 20 except: | |
190 | ... in sysexit(stat=2, mode='exit') |
|
190 | # 21 stat = 1 | |
191 |
|
|
191 | # ---> 22 sysexit(stat, mode) | |
192 | ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) |
|
192 | # mode = 'exit' | |
193 | stat = 2 |
|
193 | # stat = 2 | |
194 | mode = 'exit' |
|
194 | # 23 else: | |
195 | <BLANKLINE> |
|
195 | # 24 raise ValueError('Unknown mode') | |
196 | SystemExit: (2, 'Mode = exit') |
|
196 | # <BLANKLINE> | |
197 | """ |
|
197 | # ... in sysexit(stat=2, mode='exit') | |
|
198 | # 10 def sysexit(stat, mode): | |||
|
199 | # ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) | |||
|
200 | # stat = 2 | |||
|
201 | # mode = 'exit' | |||
|
202 | # <BLANKLINE> | |||
|
203 | # SystemExit: (2, 'Mode = exit') | |||
|
204 | # """ | |||
198 |
|
205 | |||
199 |
|
206 | |||
200 | def test_run_cell(): |
|
207 | def test_run_cell(): |
@@ -35,6 +35,8 b' from IPython.utils.tempdir import (TemporaryDirectory,' | |||||
35 | from IPython.utils.process import find_cmd |
|
35 | from IPython.utils.process import find_cmd | |
36 | from .test_debugger import PdbTestInput |
|
36 | from .test_debugger import PdbTestInput | |
37 |
|
37 | |||
|
38 | import pytest | |||
|
39 | ||||
38 |
|
40 | |||
39 | @magic.magics_class |
|
41 | @magic.magics_class | |
40 | class DummyMagics(magic.Magics): pass |
|
42 | class DummyMagics(magic.Magics): pass | |
@@ -954,7 +956,6 b' async def test_script_bg_out():' | |||||
954 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") |
|
956 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") | |
955 | ip.user_ns['output'].close() |
|
957 | ip.user_ns['output'].close() | |
956 |
|
958 | |||
957 |
|
||||
958 | @dec.skip_win32 |
|
959 | @dec.skip_win32 | |
959 | async def test_script_bg_err(): |
|
960 | async def test_script_bg_err(): | |
960 | ip = get_ipython() |
|
961 | ip = get_ipython() |
@@ -8,6 +8,8 b' from os import walk, sep, fsdecode' | |||||
8 |
|
8 | |||
9 | from IPython.core.display import DisplayObject, TextDisplayObject |
|
9 | from IPython.core.display import DisplayObject, TextDisplayObject | |
10 |
|
10 | |||
|
11 | from typing import Tuple | |||
|
12 | ||||
11 | __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', |
|
13 | __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', | |
12 | 'FileLink', 'FileLinks', 'Code'] |
|
14 | 'FileLink', 'FileLinks', 'Code'] | |
13 |
|
15 | |||
@@ -159,7 +161,7 b' class Audio(DisplayObject):' | |||||
159 | return val |
|
161 | return val | |
160 |
|
162 | |||
161 | @staticmethod |
|
163 | @staticmethod | |
162 | def _validate_and_normalize_with_numpy(data, normalize): |
|
164 | def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]: | |
163 | import numpy as np |
|
165 | import numpy as np | |
164 |
|
166 | |||
165 | data = np.array(data, dtype=float) |
|
167 | data = np.array(data, dtype=float) | |
@@ -178,8 +180,7 b' class Audio(DisplayObject):' | |||||
178 | max_abs_value = np.max(np.abs(data)) |
|
180 | max_abs_value = np.max(np.abs(data)) | |
179 | normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) |
|
181 | normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) | |
180 | scaled = data / normalization_factor * 32767 |
|
182 | scaled = data / normalization_factor * 32767 | |
181 |
return scaled.astype( |
|
183 | return scaled.astype("<h").tobytes(), nchan | |
182 |
|
||||
183 |
|
184 | |||
184 | @staticmethod |
|
185 | @staticmethod | |
185 | def _validate_and_normalize_without_numpy(data, normalize): |
|
186 | def _validate_and_normalize_without_numpy(data, normalize): |
@@ -1,5 +1,4 b'' | |||||
1 | import asyncio |
|
1 | import asyncio | |
2 | import signal |
|
|||
3 | import sys |
|
2 | import sys | |
4 | import threading |
|
3 | import threading | |
5 |
|
4 | |||
@@ -7,13 +6,8 b' from IPython.core.debugger import Pdb' | |||||
7 |
|
6 | |||
8 | from IPython.core.completer import IPCompleter |
|
7 | from IPython.core.completer import IPCompleter | |
9 | from .ptutils import IPythonPTCompleter |
|
8 | from .ptutils import IPythonPTCompleter | |
10 |
from .shortcuts import create_ipython_shortcuts |
|
9 | from .shortcuts import create_ipython_shortcuts | |
11 |
|
10 | |||
12 | from prompt_toolkit.enums import DEFAULT_BUFFER |
|
|||
13 | from prompt_toolkit.filters import (Condition, has_focus, has_selection, |
|
|||
14 | vi_insert_mode, emacs_insert_mode) |
|
|||
15 | from prompt_toolkit.key_binding import KeyBindings |
|
|||
16 | from prompt_toolkit.key_binding.bindings.completion import display_completions_like_readline |
|
|||
17 | from pygments.token import Token |
|
11 | from pygments.token import Token | |
18 | from prompt_toolkit.shortcuts.prompt import PromptSession |
|
12 | from prompt_toolkit.shortcuts.prompt import PromptSession | |
19 | from prompt_toolkit.enums import EditingMode |
|
13 | from prompt_toolkit.enums import EditingMode | |
@@ -45,10 +39,8 b' class TerminalPdb(Pdb):' | |||||
45 | return [(Token.Prompt, self.prompt)] |
|
39 | return [(Token.Prompt, self.prompt)] | |
46 |
|
40 | |||
47 | if self._ptcomp is None: |
|
41 | if self._ptcomp is None: | |
48 |
compl = IPCompleter( |
|
42 | compl = IPCompleter( | |
49 | namespace={}, |
|
43 | shell=self.shell, namespace={}, global_namespace={}, parent=self.shell | |
50 | global_namespace={}, |
|
|||
51 | parent=self.shell, |
|
|||
52 | ) |
|
44 | ) | |
53 | # add a completer for all the do_ methods |
|
45 | # add a completer for all the do_ methods | |
54 | methods_names = [m[3:] for m in dir(self) if m.startswith("do_")] |
|
46 | methods_names = [m[3:] for m in dir(self) if m.startswith("do_")] |
@@ -41,7 +41,7 b" CoreFoundation = ctypes.cdll.LoadLibrary(ctypes.util.find_library('CoreFoundatio" | |||||
41 |
|
41 | |||
42 | CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate |
|
42 | CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate | |
43 | CFFileDescriptorCreate.restype = void_p |
|
43 | CFFileDescriptorCreate.restype = void_p | |
44 | CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p] |
|
44 | CFFileDescriptorCreate.argtypes = [void_p, ctypes.c_int, ctypes.c_bool, void_p, void_p] | |
45 |
|
45 | |||
46 | CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor |
|
46 | CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor | |
47 | CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int |
|
47 | CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int | |
@@ -77,14 +77,31 b" kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')" | |||||
77 |
|
77 | |||
78 | def _NSApp(): |
|
78 | def _NSApp(): | |
79 | """Return the global NSApplication instance (NSApp)""" |
|
79 | """Return the global NSApplication instance (NSApp)""" | |
|
80 | objc.objc_msgSend.argtypes = [void_p, void_p] | |||
80 | return msg(C('NSApplication'), n('sharedApplication')) |
|
81 | return msg(C('NSApplication'), n('sharedApplication')) | |
81 |
|
82 | |||
82 |
|
83 | |||
83 | def _wake(NSApp): |
|
84 | def _wake(NSApp): | |
84 | """Wake the Application""" |
|
85 | """Wake the Application""" | |
85 | event = msg(C('NSEvent'), |
|
86 | objc.objc_msgSend.argtypes = [ | |
86 | n('otherEventWithType:location:modifierFlags:' |
|
87 | void_p, | |
87 | 'timestamp:windowNumber:context:subtype:data1:data2:'), |
|
88 | void_p, | |
|
89 | void_p, | |||
|
90 | void_p, | |||
|
91 | void_p, | |||
|
92 | void_p, | |||
|
93 | void_p, | |||
|
94 | void_p, | |||
|
95 | void_p, | |||
|
96 | void_p, | |||
|
97 | void_p, | |||
|
98 | ] | |||
|
99 | event = msg( | |||
|
100 | C("NSEvent"), | |||
|
101 | n( | |||
|
102 | "otherEventWithType:location:modifierFlags:" | |||
|
103 | "timestamp:windowNumber:context:subtype:data1:data2:" | |||
|
104 | ), | |||
88 | 15, # Type |
|
105 | 15, # Type | |
89 | 0, # location |
|
106 | 0, # location | |
90 | 0, # flags |
|
107 | 0, # flags | |
@@ -95,6 +112,7 b' def _wake(NSApp):' | |||||
95 | 0, # data1 |
|
112 | 0, # data1 | |
96 | 0, # data2 |
|
113 | 0, # data2 | |
97 | ) |
|
114 | ) | |
|
115 | objc.objc_msgSend.argtypes = [void_p, void_p, void_p, void_p] | |||
98 | msg(NSApp, n('postEvent:atStart:'), void_p(event), True) |
|
116 | msg(NSApp, n('postEvent:atStart:'), void_p(event), True) | |
99 |
|
117 | |||
100 |
|
118 | |||
@@ -106,6 +124,7 b' def _input_callback(fdref, flags, info):' | |||||
106 | CFFileDescriptorInvalidate(fdref) |
|
124 | CFFileDescriptorInvalidate(fdref) | |
107 | CFRelease(fdref) |
|
125 | CFRelease(fdref) | |
108 | NSApp = _NSApp() |
|
126 | NSApp = _NSApp() | |
|
127 | objc.objc_msgSend.argtypes = [void_p, void_p, void_p] | |||
109 | msg(NSApp, n('stop:'), NSApp) |
|
128 | msg(NSApp, n('stop:'), NSApp) | |
110 | _wake(NSApp) |
|
129 | _wake(NSApp) | |
111 |
|
130 | |||
@@ -128,6 +147,7 b' def inputhook(context):' | |||||
128 | """Inputhook for Cocoa (NSApp)""" |
|
147 | """Inputhook for Cocoa (NSApp)""" | |
129 | NSApp = _NSApp() |
|
148 | NSApp = _NSApp() | |
130 | _stop_on_read(context.fileno()) |
|
149 | _stop_on_read(context.fileno()) | |
|
150 | objc.objc_msgSend.argtypes = [void_p, void_p] | |||
131 | msg(NSApp, n('run')) |
|
151 | msg(NSApp, n('run')) | |
132 | if not _triggered.is_set(): |
|
152 | if not _triggered.is_set(): | |
133 | # app closed without firing callback, |
|
153 | # app closed without firing callback, |
@@ -1,6 +1,7 b'' | |||||
1 | import sys |
|
1 | import sys | |
2 | import os |
|
2 | import os | |
3 | from IPython.external.qt_for_kernel import QtCore, QtGui |
|
3 | from IPython.external.qt_for_kernel import QtCore, QtGui | |
|
4 | from IPython import get_ipython | |||
4 |
|
5 | |||
5 | # If we create a QApplication, keep a reference to it so that it doesn't get |
|
6 | # If we create a QApplication, keep a reference to it so that it doesn't get | |
6 | # garbage collected. |
|
7 | # garbage collected. | |
@@ -8,6 +9,12 b' _appref = None' | |||||
8 | _already_warned = False |
|
9 | _already_warned = False | |
9 |
|
10 | |||
10 |
|
11 | |||
|
12 | def _reclaim_excepthook(): | |||
|
13 | shell = get_ipython() | |||
|
14 | if shell is not None: | |||
|
15 | sys.excepthook = shell.excepthook | |||
|
16 | ||||
|
17 | ||||
11 | def inputhook(context): |
|
18 | def inputhook(context): | |
12 | global _appref |
|
19 | global _appref | |
13 | app = QtCore.QCoreApplication.instance() |
|
20 | app = QtCore.QCoreApplication.instance() | |
@@ -27,6 +34,13 b' def inputhook(context):' | |||||
27 | return |
|
34 | return | |
28 | QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) |
|
35 | QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) | |
29 | _appref = app = QtGui.QApplication([" "]) |
|
36 | _appref = app = QtGui.QApplication([" "]) | |
|
37 | ||||
|
38 | # "reclaim" IPython sys.excepthook after event loop starts | |||
|
39 | # without this, it defaults back to BaseIPythonApplication.excepthook | |||
|
40 | # and exceptions in the Qt event loop are rendered without traceback | |||
|
41 | # formatting and look like "bug in IPython". | |||
|
42 | QtCore.QTimer.singleShot(0, _reclaim_excepthook) | |||
|
43 | ||||
30 | event_loop = QtCore.QEventLoop(app) |
|
44 | event_loop = QtCore.QEventLoop(app) | |
31 |
|
45 | |||
32 | if sys.platform == 'win32': |
|
46 | if sys.platform == 'win32': |
@@ -9,6 +9,7 b' Module to define and register Terminal IPython shortcuts with' | |||||
9 | import warnings |
|
9 | import warnings | |
10 | import signal |
|
10 | import signal | |
11 | import sys |
|
11 | import sys | |
|
12 | import re | |||
12 | from typing import Callable |
|
13 | from typing import Callable | |
13 |
|
14 | |||
14 |
|
15 |
@@ -153,6 +153,14 b' Here is a full example of a magic package. You can distribute magics using' | |||||
153 | setuptools, distutils, or any other distribution tools like `flit |
|
153 | setuptools, distutils, or any other distribution tools like `flit | |
154 | <http://flit.readthedocs.io>`_ for pure Python packages. |
|
154 | <http://flit.readthedocs.io>`_ for pure Python packages. | |
155 |
|
155 | |||
|
156 | When distributing magics as part of a package, recommended best practice is to | |||
|
157 | execute the registration inside the `load_ipython_extension` as demonstrated in | |||
|
158 | the example below, instead of directly in the module (as in the initial example | |||
|
159 | with the ``@register_*`` decorators). This means a user will need to explicitly | |||
|
160 | choose to load your magic with ``%load_ext``. instead implicitly getting it when | |||
|
161 | importing the module. This is particularly relevant if loading your magic has | |||
|
162 | side effects, if it is slow to load, or if it might override another magic with | |||
|
163 | the same name. | |||
156 |
|
164 | |||
157 | .. sourcecode:: bash |
|
165 | .. sourcecode:: bash | |
158 |
|
166 |
@@ -119,11 +119,6 b' which adds a directory called ``profile_<name>`` to your IPython directory. Then' | |||||
119 | you can load this profile by adding ``--profile=<name>`` to your command line |
|
119 | you can load this profile by adding ``--profile=<name>`` to your command line | |
120 | options. Profiles are supported by all IPython applications. |
|
120 | options. Profiles are supported by all IPython applications. | |
121 |
|
121 | |||
122 | IPython ships with some sample profiles in :file:`IPython/config/profile`. If |
|
|||
123 | you create profiles with the name of one of our shipped profiles, these config |
|
|||
124 | files will be copied over instead of starting with the automatically generated |
|
|||
125 | config files. |
|
|||
126 |
|
||||
127 | IPython extends the config loader for Python files so that you can inherit |
|
122 | IPython extends the config loader for Python files so that you can inherit | |
128 | config from another profile. To do this, use a line like this in your Python |
|
123 | config from another profile. To do this, use a line like this in your Python | |
129 | config file: |
|
124 | config file: |
@@ -9,15 +9,15 b' IPython Documentation' | |||||
9 | :Release: |release| |
|
9 | :Release: |release| | |
10 | :Date: |today| |
|
10 | :Date: |today| | |
11 |
|
11 | |||
12 | Welcome to the official IPython documentation |
|
12 | Welcome to the official IPython documentation. | |
13 |
|
13 | |||
14 | IPython provides a rich toolkit to help you make the most of using Python |
|
14 | IPython provides a rich toolkit to help you make the most of using Python | |
15 | interactively. Its main components are: |
|
15 | interactively. Its main components are: | |
16 |
|
16 | |||
17 | * A powerful interactive Python shell |
|
17 | * A powerful interactive Python shell. | |
18 |
|
18 | |||
19 |
|
19 | |||
20 | .. image:: /_images/ipython-6-screenshot.png |
|
20 | .. image:: ./_images/ipython-6-screenshot.png | |
21 | :alt: Screenshot of IPython 6.0 |
|
21 | :alt: Screenshot of IPython 6.0 | |
22 | :align: center |
|
22 | :align: center | |
23 |
|
23 | |||
@@ -59,7 +59,7 b' The Command line interface inherits the above functionality and adds' | |||||
59 |
|
59 | |||
60 | * real multi-line editing thanks to `prompt_toolkit <http://python-prompt-toolkit.readthedocs.io/en/stable/>`_. |
|
60 | * real multi-line editing thanks to `prompt_toolkit <http://python-prompt-toolkit.readthedocs.io/en/stable/>`_. | |
61 |
|
61 | |||
62 | * syntax highlighting as you type |
|
62 | * syntax highlighting as you type. | |
63 |
|
63 | |||
64 | * integration with command line editor for a better workflow. |
|
64 | * integration with command line editor for a better workflow. | |
65 |
|
65 | |||
@@ -84,8 +84,6 b" The latest development version is always available from IPython's `GitHub" | |||||
84 | repository <http://github.com/ipython/ipython>`_. |
|
84 | repository <http://github.com/ipython/ipython>`_. | |
85 |
|
85 | |||
86 |
|
86 | |||
87 |
|
||||
88 |
|
||||
89 | .. toctree:: |
|
87 | .. toctree:: | |
90 | :maxdepth: 1 |
|
88 | :maxdepth: 1 | |
91 | :hidden: |
|
89 | :hidden: |
@@ -3,20 +3,20 b' Python vs IPython' | |||||
3 | ================= |
|
3 | ================= | |
4 |
|
4 | |||
5 | This document is meant to highlight the main differences between the Python |
|
5 | This document is meant to highlight the main differences between the Python | |
6 | language and what are the specific construct you can do only in IPython. |
|
6 | language and what are the specific constructs you can do only in IPython. | |
7 |
|
7 | |||
8 | Unless expressed otherwise all of the construct you will see here will raise a |
|
8 | Unless expressed otherwise all of the constructs you will see here will raise a | |
9 | ``SyntaxError`` if run in a pure Python shell, or if executing in a Python |
|
9 | ``SyntaxError`` if run in a pure Python shell, or if executing in a Python | |
10 | script. |
|
10 | script. | |
11 |
|
11 | |||
12 |
Each of these features |
|
12 | Each of these features is described more in detail in the further parts of the documentation. | |
13 |
|
13 | |||
14 |
|
14 | |||
15 | Quick overview: |
|
15 | Quick overview: | |
16 | =============== |
|
16 | =============== | |
17 |
|
17 | |||
18 |
|
18 | |||
19 | All the following construct are valid IPython syntax: |
|
19 | All the following constructs are valid IPython syntax: | |
20 |
|
20 | |||
21 | .. code-block:: ipython |
|
21 | .. code-block:: ipython | |
22 |
|
22 | |||
@@ -58,8 +58,8 b' All the following construct are valid IPython syntax:' | |||||
58 | ...: print $months[0]; |
|
58 | ...: print $months[0]; | |
59 |
|
59 | |||
60 |
|
60 | |||
61 | Each of these construct is compiled by IPython into valid python code and will |
|
61 | Each of these constructs is compiled by IPython into valid python code and will | |
62 | do most of the time what you expect it will do. Let see each of these example |
|
62 | do most of the time what you expect it will do. Let's see each of these examples | |
63 | in more detail. |
|
63 | in more detail. | |
64 |
|
64 | |||
65 |
|
65 | |||
@@ -89,7 +89,7 b' shortcut to get help. A question mark alone will bring up the IPython help:' | |||||
89 | ------------- |
|
89 | ------------- | |
90 | ... |
|
90 | ... | |
91 |
|
91 | |||
92 |
A single question mark before |
|
92 | A single question mark before or after an object available in the current | |
93 | namespace will show help relative to this object: |
|
93 | namespace will show help relative to this object: | |
94 |
|
94 | |||
95 | .. code-block:: ipython |
|
95 | .. code-block:: ipython | |
@@ -127,7 +127,7 b' and if possible display the python source code of this object.' | |||||
127 |
|
127 | |||
128 |
|
128 | |||
129 | If you are looking for an object, the use of wildcards ``*`` in conjunction |
|
129 | If you are looking for an object, the use of wildcards ``*`` in conjunction | |
130 | with question mark will allow you to search current namespace for object with |
|
130 | with a question mark will allow you to search the current namespace for objects with | |
131 | matching names: |
|
131 | matching names: | |
132 |
|
132 | |||
133 | .. code-block:: ipython |
|
133 | .. code-block:: ipython | |
@@ -142,10 +142,10 b' Shell Assignment' | |||||
142 | ================ |
|
142 | ================ | |
143 |
|
143 | |||
144 |
|
144 | |||
145 |
When doing interactive computing it is common |
|
145 | When doing interactive computing it is a common need to access the underlying shell. | |
146 | This is doable through the use of the exclamation mark ``!`` (or bang). |
|
146 | This is doable through the use of the exclamation mark ``!`` (or bang). | |
147 |
|
147 | |||
148 | This allow to execute simple command when present in beginning of line: |
|
148 | This allows to execute simple commands when present in beginning of the line: | |
149 |
|
149 | |||
150 | .. code-block:: ipython |
|
150 | .. code-block:: ipython | |
151 |
|
151 | |||
@@ -167,7 +167,7 b' Or edit file:' | |||||
167 |
|
167 | |||
168 | The line after the bang can call any program installed in the underlying |
|
168 | The line after the bang can call any program installed in the underlying | |
169 | shell, and support variable expansion in the form of ``$variable`` or ``{variable}``. |
|
169 | shell, and support variable expansion in the form of ``$variable`` or ``{variable}``. | |
170 | The later form of expansion supports arbitrary python expression: |
|
170 | The later form of expansion supports arbitrary python expressions: | |
171 |
|
171 | |||
172 | .. code-block:: ipython |
|
172 | .. code-block:: ipython | |
173 |
|
173 | |||
@@ -176,19 +176,19 b' The later form of expansion supports arbitrary python expression:' | |||||
176 | In[2]: !mv $file {file.upper()} |
|
176 | In[2]: !mv $file {file.upper()} | |
177 |
|
177 | |||
178 |
|
178 | |||
179 |
The bang can also be present |
|
179 | The bang (``!``) can also be present on the right hand side of an assignment, just | |
180 |
after the equal sign, or separated from it by a white space. In |
|
180 | after the equal sign, or separated from it by a white space. In this case the | |
181 |
standard output of the command after the bang |
|
181 | standard output of the command after the bang will be split out into lines | |
182 | in a list-like object and assign to the left hand side. |
|
182 | in a list-like object and assigned to the left hand side. | |
183 |
|
183 | |||
184 | This allow you for example to put the list of files of the current working directory in a variable: |
|
184 | This allows you, for example, to put the list of files of the current working directory in a variable: | |
185 |
|
185 | |||
186 | .. code-block:: ipython |
|
186 | .. code-block:: ipython | |
187 |
|
187 | |||
188 | In[1]: my_files = !ls |
|
188 | In[1]: my_files = !ls | |
189 |
|
189 | |||
190 |
|
190 | |||
191 | You can combine the different possibilities in for loops, condition, functions...: |
|
191 | You can combine the different possibilities in for loops, conditions, functions...: | |
192 |
|
192 | |||
193 | .. code-block:: ipython |
|
193 | .. code-block:: ipython | |
194 |
|
194 | |||
@@ -202,19 +202,19 b' You can combine the different possibilities in for loops, condition, functions..' | |||||
202 | Magics |
|
202 | Magics | |
203 | ------ |
|
203 | ------ | |
204 |
|
204 | |||
205 |
Magic |
|
205 | Magic functions (magics) are often present in the form of shell-like syntax, but they are | |
206 |
|
|
206 | python functions under the hood. The syntax and assignment possibilities are | |
207 | similar to the one with the bang (``!``) syntax, but with more flexibility and |
|
207 | similar to the one with the bang (``!``) syntax, but with more flexibility and | |
208 | power. Magic function start with a percent sign (``%``) or double percent (``%%``). |
|
208 | power. Magic functions start with a percent sign (``%``) or double percent signs (``%%``). | |
209 |
|
209 | |||
210 |
A magic call with a si |
|
210 | A magic call with a single percent sign will act only on one line: | |
211 |
|
211 | |||
212 | .. code-block:: ipython |
|
212 | .. code-block:: ipython | |
213 |
|
213 | |||
214 | In[1]: %xmode |
|
214 | In[1]: %xmode | |
215 | Exception reporting mode: Verbose |
|
215 | Exception reporting mode: Verbose | |
216 |
|
216 | |||
217 |
|
|
217 | Magics support assignment: | |
218 |
|
218 | |||
219 | .. code-block:: ipython |
|
219 | .. code-block:: ipython | |
220 |
|
220 | |||
@@ -224,7 +224,7 b' And support assignment:' | |||||
224 | In [2]: results |
|
224 | In [2]: results | |
225 | Out[2]: <TimeitResult : 1 loops, best of 1: 21.1 µs per loop> |
|
225 | Out[2]: <TimeitResult : 1 loops, best of 1: 21.1 µs per loop> | |
226 |
|
226 | |||
227 |
Magic with |
|
227 | Magics with double percent signs (``%%``) can spread over multiple lines, but they do not support assignments: | |
228 |
|
228 | |||
229 | .. code-block:: ipython |
|
229 | .. code-block:: ipython | |
230 |
|
230 |
@@ -22,6 +22,47 b' Need to be updated:' | |||||
22 |
|
22 | |||
23 | pr/* |
|
23 | pr/* | |
24 |
|
24 | |||
|
25 | IPython 8.0 is bringing a number of new features and improvements to both the | |||
|
26 | user of the terminal and of the kernel via Jupyter. The removal of compatibility | |||
|
27 | with older version of Python is also the opportunity to do a couple of | |||
|
28 | performance improvement in particular with respect to startup time. | |||
|
29 | ||||
|
30 | The main change in IPython 8.0 is the integration of the ``stack_data`` package; | |||
|
31 | which provide smarter information in traceback; in particular it will highlight | |||
|
32 | the AST node where an error occurs which can help to quickly narrow down errors. | |||
|
33 | ||||
|
34 | For example in the following snippet:: | |||
|
35 | ||||
|
36 | def foo(i): | |||
|
37 | x = [[[0]]] | |||
|
38 | return x[0][i][0] | |||
|
39 | ||||
|
40 | ||||
|
41 | def bar(): | |||
|
42 | return foo(0) + foo( | |||
|
43 | 1 | |||
|
44 | ) + foo(2) | |||
|
45 | ||||
|
46 | ||||
|
47 | Calling ``bar()`` would raise an ``IndexError`` on the return line of ``foo``, | |||
|
48 | IPython 8.0 is capable of telling you, where the index error occurs:: | |||
|
49 | ||||
|
50 | return x[0][i][0] | |||
|
51 | ^ | |||
|
52 | ||||
|
53 | To prepare for Python 3.10 we have also started working on removing reliance and | |||
|
54 | any dependency that is not Python 3.10 compatible; that include migrating our | |||
|
55 | test suite to Pytest, and starting to remove nose. | |||
|
56 | ||||
|
57 | We are also removing support for Python 3.6 allowing internal code to use more | |||
|
58 | efficient ``pathlib``, and make better use of type annotations. | |||
|
59 | ||||
|
60 | The completer has also seen significant updates and make use of newer Jedi API | |||
|
61 | offering faster and more reliable tab completion. | |||
|
62 | ||||
|
63 | For the terminal users this also enable the auto-suggestion feature, described | |||
|
64 | below, which show "ghost text" ahead of your cursor you can accept without | |||
|
65 | having to press the tab key or ask the completer to suggest completions. | |||
25 |
|
66 | |||
26 |
|
67 | |||
27 | Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__. |
|
68 | Autosuggestion is a very useful feature available in `fish <https://fishshell.com/>`__, `zsh <https://en.wikipedia.org/wiki/Z_shell>`__, and `prompt-toolkit <https://python-prompt-toolkit.readthedocs.io/en/master/pages/asking_for_input.html#auto-suggestion>`__. | |
@@ -93,6 +134,25 b' Currently, autosuggestions are only shown in the emacs or vi insert editing mode' | |||||
93 | - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode. |
|
134 | - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode. | |
94 | - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__. |
|
135 | - To use these shortcuts in vi insert mode, you will have to create `custom keybindings in your config.py <https://github.com/mskar/setup/commit/2892fcee46f9f80ef7788f0749edc99daccc52f4/>`__. | |
95 |
|
136 | |||
|
137 | ||||
|
138 | Show pinfo information in ipdb using "?" and "??" | |||
|
139 | ------------------------------------------------- | |||
|
140 | ||||
|
141 | In IPDB, it is now possible to show the information about an object using "?" | |||
|
142 | and "??", in much the same way it can be done when using the IPython prompt:: | |||
|
143 | ||||
|
144 | ipdb> partial? | |||
|
145 | Init signature: partial(self, /, *args, **kwargs) | |||
|
146 | Docstring: | |||
|
147 | partial(func, *args, **keywords) - new function with partial application | |||
|
148 | of the given arguments and keywords. | |||
|
149 | File: ~/.pyenv/versions/3.8.6/lib/python3.8/functools.py | |||
|
150 | Type: type | |||
|
151 | Subclasses: | |||
|
152 | ||||
|
153 | Previously, "pinfo" or "pinfo2" command had to be used for this purpose. | |||
|
154 | ||||
|
155 | ||||
96 | Autoreload 3 feature |
|
156 | Autoreload 3 feature | |
97 | ==================== |
|
157 | ==================== | |
98 |
|
158 | |||
@@ -107,6 +167,7 b' Try ``%autoreload 3`` in an IPython session after running ``%load_ext autoreload' | |||||
107 |
|
167 | |||
108 | For more information please see unit test - |
|
168 | For more information please see unit test - | |
109 | extensions/tests/test_autoreload.py : 'test_autoload_newly_added_objects' |
|
169 | extensions/tests/test_autoreload.py : 'test_autoload_newly_added_objects' | |
|
170 | ======= | |||
110 |
|
171 | |||
111 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. |
|
172 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. | |
112 |
|
173 |
@@ -2,6 +2,105 b'' | |||||
2 | 7.x Series |
|
2 | 7.x Series | |
3 | ============ |
|
3 | ============ | |
4 |
|
4 | |||
|
5 | .. _version 7.22: | |||
|
6 | ||||
|
7 | IPython 7.22 | |||
|
8 | ============ | |||
|
9 | ||||
|
10 | Second release of IPython for 2021, mostly containing bug fixes. Here is a quick | |||
|
11 | rundown of the few changes. | |||
|
12 | ||||
|
13 | - Fix some ``sys.excepthook`` shenanigan when embedding with qt, recommended if | |||
|
14 | you – for example – use `napari <https://napari.org>`__. :ghpull:`12842`. | |||
|
15 | - Fix bug when using the new ipdb ``%context`` magic :ghpull:`12844` | |||
|
16 | - Couples of deprecation cleanup :ghpull:`12868` | |||
|
17 | - Update for new dpast.com api if you use the ``%pastbin`` magic. :ghpull:`12712` | |||
|
18 | - Remove support for numpy before 1.16. :ghpull:`12836` | |||
|
19 | ||||
|
20 | ||||
|
21 | Thanks | |||
|
22 | ------ | |||
|
23 | ||||
|
24 | We have a new team member that you should see more often on the IPython | |||
|
25 | repository, Błażej Michalik (@MrMino) have been doing regular contributions to | |||
|
26 | IPython, and spent time replying to many issues and guiding new users to the | |||
|
27 | codebase; they now have triage permissions to the IPython repository and we'll | |||
|
28 | work toward giving them more permission in the future. | |||
|
29 | ||||
|
30 | Many thanks to all the contributors to this release you can find all individual | |||
|
31 | contributions to this milestone `on github <https://github.com/ipython/ipython/milestone/84>`__. | |||
|
32 | ||||
|
33 | Thanks as well to organisations, QuantStack for working on debugger | |||
|
34 | compatibility for Xeus_python, and the `D. E. Shaw group | |||
|
35 | <https://deshaw.com/>`__ for sponsoring work on IPython and related libraries. | |||
|
36 | ||||
|
37 | .. _version 721: | |||
|
38 | ||||
|
39 | IPython 7.21 | |||
|
40 | ============ | |||
|
41 | ||||
|
42 | IPython 7.21 is the first release we have back on schedule of one release every | |||
|
43 | month; it contains a number of minor fixes and improvements, notably, the new | |||
|
44 | context command for ipdb | |||
|
45 | ||||
|
46 | ||||
|
47 | New "context" command in ipdb | |||
|
48 | ----------------------------- | |||
|
49 | ||||
|
50 | It is now possible to change the number of lines shown in the backtrace | |||
|
51 | information in ipdb using "context" command. :ghpull:`12826` | |||
|
52 | ||||
|
53 | (thanks @MrMino, there are other improvement from them on master). | |||
|
54 | ||||
|
55 | Other notable changes in IPython 7.21 | |||
|
56 | ------------------------------------- | |||
|
57 | ||||
|
58 | - Fix some issues on new osx-arm64 :ghpull:`12804`, :ghpull:`12807`. | |||
|
59 | - Compatibility with Xeus-Python for debugger protocol, :ghpull:`12809` | |||
|
60 | - Misc docs fixes for compatibility and uniformity with Numpydoc. | |||
|
61 | :ghpull:`12824` | |||
|
62 | ||||
|
63 | ||||
|
64 | Thanks | |||
|
65 | ------ | |||
|
66 | ||||
|
67 | Many thanks to all the contributors to this release you can find all individual | |||
|
68 | contribution to this milestone `on github <https://github.com/ipython/ipython/milestone/83>`__. | |||
|
69 | ||||
|
70 | ||||
|
71 | .. _version 720: | |||
|
72 | ||||
|
73 | IPython 7.20 | |||
|
74 | ============ | |||
|
75 | ||||
|
76 | IPython 7.20 is the accumulation of 3 month of work on IPython, spacing between | |||
|
77 | IPython release have been increased from the usual once a month for various | |||
|
78 | reason. | |||
|
79 | ||||
|
80 | - Mainly as I'm too busy and the effectively sole maintainer, and | |||
|
81 | - Second because not much changes happened before mid December. | |||
|
82 | ||||
|
83 | The main driver for this release was the new version of Jedi 0.18 breaking API; | |||
|
84 | which was taken care of in the master branch early in 2020 but not in 7.x as I | |||
|
85 | though that by now 8.0 would be out. | |||
|
86 | ||||
|
87 | The inclusion of a resolver in pip did not help and actually made things worse. | |||
|
88 | If usually I would have simply pinned Jedi to ``<0.18``; this is not a solution | |||
|
89 | anymore as now pip is free to install Jedi 0.18, and downgrade IPython. | |||
|
90 | ||||
|
91 | I'll do my best to keep the regular release, but as the 8.0-dev branch and 7.x | |||
|
92 | are starting to diverge this is becoming difficult in particular with my limited | |||
|
93 | time, so if you have any cycles to spare I'll appreciate your help to respond to | |||
|
94 | issues and pushing 8.0 forward. | |||
|
95 | ||||
|
96 | Here are thus some of the changes for IPython 7.20. | |||
|
97 | ||||
|
98 | - Support for PyQt5 >= 5.11 :ghpull:`12715` | |||
|
99 | - ``%reset`` remove imports more agressively :ghpull:`12718` | |||
|
100 | - fix the ``%conda`` magic :ghpull:`12739` | |||
|
101 | - compatibility with Jedi 0.18, and bump minimum Jedi version. :ghpull:`12793` | |||
|
102 | ||||
|
103 | ||||
5 | .. _version 719: |
|
104 | .. _version 719: | |
6 |
|
105 | |||
7 | IPython 7.19 |
|
106 | IPython 7.19 |
@@ -171,15 +171,23 b' setuptools_extra_args = {}' | |||||
171 | # setuptools requirements |
|
171 | # setuptools requirements | |
172 |
|
172 | |||
173 | extras_require = dict( |
|
173 | extras_require = dict( | |
174 |
parallel |
|
174 | parallel=["ipyparallel"], | |
175 |
qtconsole |
|
175 | qtconsole=["qtconsole"], | |
176 |
doc |
|
176 | doc=["Sphinx>=1.3"], | |
177 | test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel', 'numpy>=1.14'], |
|
177 | test=[ | |
|
178 | "nose>=0.10.1", | |||
|
179 | "requests", | |||
|
180 | "testpath", | |||
|
181 | "pygments", | |||
|
182 | "nbformat", | |||
|
183 | "ipykernel", | |||
|
184 | "numpy>=1.16", | |||
|
185 | ], | |||
178 |
terminal |
|
186 | terminal=[], | |
179 |
kernel |
|
187 | kernel=["ipykernel"], | |
180 |
nbformat |
|
188 | nbformat=["nbformat"], | |
181 |
notebook |
|
189 | notebook=["notebook", "ipywidgets"], | |
182 |
nbconvert |
|
190 | nbconvert=["nbconvert"], | |
183 | ) |
|
191 | ) | |
184 |
|
192 | |||
185 | install_requires = [ |
|
193 | install_requires = [ |
General Comments 0
You need to be logged in to leave comments.
Login now