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 | 3 | on: |
|
4 | 4 | push: |
|
5 | branches: [ master ] | |
|
5 | branches: [ master, 7.x] | |
|
6 | 6 | pull_request: |
|
7 | branches: [ master ] | |
|
7 | branches: [ master, 7.x] | |
|
8 | 8 | |
|
9 | 9 | jobs: |
|
10 | 10 | build: |
@@ -5,9 +5,9 b' name: Python package' | |||
|
5 | 5 | |
|
6 | 6 | on: |
|
7 | 7 | push: |
|
8 | branches: [ master ] | |
|
8 | branches: [ master, 7.x ] | |
|
9 | 9 | pull_request: |
|
10 | branches: [ master ] | |
|
10 | branches: [ master, 7.x ] | |
|
11 | 11 | |
|
12 | 12 | jobs: |
|
13 | 13 | build: |
@@ -37,7 +37,7 b' install:' | |||
|
37 | 37 | - pip install -e file://$PWD#egg=ipython[test] --upgrade |
|
38 | 38 | - pip install trio curio --upgrade --upgrade-strategy eager |
|
39 | 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 | 43 | script: |
@@ -112,25 +112,53 b' class CachingCompiler(codeop.Compile):' | |||
|
112 | 112 | """ |
|
113 | 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 | 135 | """Make a name for a block of code, and cache the code. |
|
117 | 136 | |
|
118 | 137 | Parameters |
|
119 | 138 | ---------- |
|
120 | code : str | |
|
121 | The Python source code to cache. | |
|
139 | transformed_code : str | |
|
140 | The executable Python source code to cache and compile. | |
|
122 | 141 | number : int |
|
123 | 142 | A number which forms part of the code's name. Used for the execution |
|
124 | 143 | counter. |
|
144 | raw_code : str | |
|
145 | The raw code before transformation, if None, set to `transformed_code`. | |
|
125 | 146 | |
|
126 | 147 | Returns |
|
127 | 148 | ------- |
|
128 | 149 | The name of the cached code (as a string). Pass this as the filename |
|
129 | 150 | argument to compilation, so that tracebacks are correctly hooked up. |
|
130 | 151 | """ |
|
131 | name = code_name(code, number) | |
|
132 | entry = (len(code), time.time(), | |
|
133 | [line+'\n' for line in code.splitlines()], name) | |
|
152 | if raw_code is None: | |
|
153 | raw_code = transformed_code | |
|
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 | 162 | linecache.cache[name] = entry |
|
135 | 163 | linecache._ipython_cache[name] = entry |
|
136 | 164 | return name |
@@ -201,7 +201,9 b" def provisionalcompleter(action='ignore'):" | |||
|
201 | 201 | |
|
202 | 202 | >>> completer.do_experimental_things() # raises. |
|
203 | 203 | |
|
204 |
.. note:: |
|
|
204 | .. note:: | |
|
205 | ||
|
206 | Unstable | |
|
205 | 207 | |
|
206 | 208 | By using this context manager you agree that the API in use may change |
|
207 | 209 | without warning, and that you won't complain if they do so. |
@@ -356,7 +358,9 b' class Completion:' | |||
|
356 | 358 | """ |
|
357 | 359 | Completion object used and return by IPython completers. |
|
358 | 360 | |
|
359 |
.. warning:: |
|
|
361 | .. warning:: | |
|
362 | ||
|
363 | Unstable | |
|
360 | 364 | |
|
361 | 365 | This function is unstable, API may change without warning. |
|
362 | 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 | 424 | Deduplicate a set of completions. |
|
421 | 425 | |
|
422 |
.. warning:: |
|
|
426 | .. warning:: | |
|
427 | ||
|
428 | Unstable | |
|
423 | 429 | |
|
424 | 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 | 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 | 472 | This function is unstable, API may change without warning. |
|
465 | 473 | It will also raise unless use in proper context manager. |
@@ -1837,7 +1845,9 b' class IPCompleter(Completer):' | |||
|
1837 | 1845 | """ |
|
1838 | 1846 | Returns an iterator over the possible completions |
|
1839 | 1847 | |
|
1840 |
.. warning:: |
|
|
1848 | .. warning:: | |
|
1849 | ||
|
1850 | Unstable | |
|
1841 | 1851 | |
|
1842 | 1852 | This function is unstable, API may change without warning. |
|
1843 | 1853 | It will also raise unless use in proper context manager. |
@@ -23,6 +23,7 b' import os' | |||
|
23 | 23 | import sys |
|
24 | 24 | import traceback |
|
25 | 25 | from pprint import pformat |
|
26 | from pathlib import Path | |
|
26 | 27 | |
|
27 | 28 | from IPython.core import ultratb |
|
28 | 29 | from IPython.core.release import author_email |
@@ -151,10 +152,10 b' class CrashHandler(object):' | |||
|
151 | 152 | try: |
|
152 | 153 | rptdir = self.app.ipython_dir |
|
153 | 154 | except: |
|
154 |
rptdir = |
|
|
155 |
if rptdir is None or not |
|
|
156 |
rptdir = |
|
|
157 |
report_name = |
|
|
155 | rptdir = Path.cwd() | |
|
156 | if rptdir is None or not Path.is_dir(rptdir): | |
|
157 | rptdir = Path.cwd() | |
|
158 | report_name = rptdir / self.crash_report_fname | |
|
158 | 159 | # write the report filename into the instance dict so it can get |
|
159 | 160 | # properly expanded out in the user message template |
|
160 | 161 | self.crash_report_fname = report_name |
@@ -50,6 +50,7 b' from pdb import Pdb as OldPdb' | |||
|
50 | 50 | # it does so with some limitations. The rest of this support is implemented in |
|
51 | 51 | # the Tracer constructor. |
|
52 | 52 | |
|
53 | ||
|
53 | 54 | def make_arrow(pad): |
|
54 | 55 | """generate the leading arrow in front of traceback or debugger""" |
|
55 | 56 | if pad >= 2: |
@@ -237,7 +238,7 b' class Pdb(OldPdb):' | |||
|
237 | 238 | self.shell = TerminalInteractiveShell.instance() |
|
238 | 239 | # needed by any code which calls __import__("__main__") after |
|
239 | 240 | # the debugger was entered. See also #9941. |
|
240 |
sys.modules[ |
|
|
241 | sys.modules["__main__"] = save_main | |
|
241 | 242 | |
|
242 | 243 | if color_scheme is not None: |
|
243 | 244 | warnings.warn( |
@@ -272,7 +273,6 b' class Pdb(OldPdb):' | |||
|
272 | 273 | cst['Neutral'].colors.breakpoint_enabled = C.LightRed |
|
273 | 274 | cst['Neutral'].colors.breakpoint_disabled = C.Red |
|
274 | 275 | |
|
275 | ||
|
276 | 276 | # Add a python parser so we can syntax highlight source while |
|
277 | 277 | # debugging. |
|
278 | 278 | self.parser = PyColorize.Parser(style=color_scheme) |
@@ -320,6 +320,18 b' class Pdb(OldPdb):' | |||
|
320 | 320 | except KeyboardInterrupt: |
|
321 | 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 | 335 | def new_do_frame(self, arg): |
|
324 | 336 | OldPdb.do_frame(self, arg) |
|
325 | 337 | |
@@ -402,11 +414,10 b' class Pdb(OldPdb):' | |||
|
402 | 414 | |
|
403 | 415 | Colors = self.color_scheme_table.active_colors |
|
404 | 416 | ColorsNormal = Colors.Normal |
|
405 |
tpl_link = |
|
|
406 |
tpl_call = |
|
|
407 |
tpl_line = |
|
|
408 |
tpl_line_em = |
|
|
409 | ColorsNormal) | |
|
417 | tpl_link = "%s%%s%s" % (Colors.filenameEm, ColorsNormal) | |
|
418 | tpl_call = "%s%%s%s%%s%s" % (Colors.vName, Colors.valEm, ColorsNormal) | |
|
419 | tpl_line = "%%s%s%%s %s%%s" % (Colors.lineno, ColorsNormal) | |
|
420 | tpl_line_em = "%%s%s%%s %s%%s%s" % (Colors.linenoEm, Colors.line, ColorsNormal) | |
|
410 | 421 | |
|
411 | 422 | frame, lineno = frame_lineno |
|
412 | 423 | |
@@ -439,8 +450,8 b' class Pdb(OldPdb):' | |||
|
439 | 450 | if frame is self.curframe: |
|
440 | 451 | ret.append('> ') |
|
441 | 452 | else: |
|
442 |
ret.append( |
|
|
443 |
ret.append( |
|
|
453 | ret.append(" ") | |
|
454 | ret.append("%s(%s)%s\n" % (link, lineno, call)) | |
|
444 | 455 | |
|
445 | 456 | start = lineno - 1 - context//2 |
|
446 | 457 | lines = linecache.getlines(filename) |
@@ -449,14 +460,14 b' class Pdb(OldPdb):' | |||
|
449 | 460 | lines = lines[start : start + context] |
|
450 | 461 | |
|
451 | 462 | for i,line in enumerate(lines): |
|
452 |
show_arrow = |
|
|
453 |
linetpl = (frame is self.curframe or show_arrow) |
|
|
454 | and tpl_line_em \ | |
|
455 |
|
|
|
456 | ret.append(self.__format_line(linetpl, filename, | |
|
457 | start + 1 + i, line, | |
|
458 | arrow = show_arrow) ) | |
|
459 |
return |
|
|
463 | show_arrow = start + 1 + i == lineno | |
|
464 | linetpl = (frame is self.curframe or show_arrow) and tpl_line_em or tpl_line | |
|
465 | ret.append( | |
|
466 | self.__format_line( | |
|
467 | linetpl, filename, start + 1 + i, line, arrow=show_arrow | |
|
468 | ) | |
|
469 | ) | |
|
470 | return "".join(ret) | |
|
460 | 471 | |
|
461 | 472 |
def __format_line(self, tpl_line, filename, lineno, line, arrow |
|
462 | 473 | bp_mark = "" |
@@ -488,7 +499,6 b' class Pdb(OldPdb):' | |||
|
488 | 499 | |
|
489 | 500 | return tpl_line % (bp_mark_color + bp_mark, num, line) |
|
490 | 501 | |
|
491 | ||
|
492 | 502 | def print_list_lines(self, filename, first, last): |
|
493 | 503 | """The printing (as opposed to the parsing part of a 'list' |
|
494 | 504 | command.""" |
@@ -507,9 +517,13 b' class Pdb(OldPdb):' | |||
|
507 | 517 | break |
|
508 | 518 | |
|
509 | 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 | 523 | else: |
|
512 |
line = self.__format_line( |
|
|
524 | line = self.__format_line( | |
|
525 | tpl_line, filename, lineno, line, arrow=False | |
|
526 | ) | |
|
513 | 527 | |
|
514 | 528 | src.append(line) |
|
515 | 529 | self.lineno = lineno |
@@ -706,7 +720,7 b' class Pdb(OldPdb):' | |||
|
706 | 720 | |
|
707 | 721 | Will skip hidden frames. |
|
708 | 722 | """ |
|
709 |
|
|
|
723 | # modified version of upstream that skips | |
|
710 | 724 | # frames with __tracebackide__ |
|
711 | 725 | if self.curindex == 0: |
|
712 | 726 | self.error("Oldest frame") |
@@ -720,11 +734,9 b' class Pdb(OldPdb):' | |||
|
720 | 734 | if count < 0: |
|
721 | 735 | _newframe = 0 |
|
722 | 736 | else: |
|
723 | _newindex = self.curindex | |
|
724 | 737 | counter = 0 |
|
725 | 738 | hidden_frames = self.hidden_frames(self.stack) |
|
726 | 739 | for i in range(self.curindex - 1, -1, -1): |
|
727 | frame = self.stack[i][0] | |
|
728 | 740 | if hidden_frames[i] and self.skip_hidden: |
|
729 | 741 | skipped += 1 |
|
730 | 742 | continue |
@@ -765,12 +777,10 b' class Pdb(OldPdb):' | |||
|
765 | 777 | if count < 0: |
|
766 | 778 | _newframe = len(self.stack) - 1 |
|
767 | 779 | else: |
|
768 | _newindex = self.curindex | |
|
769 | 780 | counter = 0 |
|
770 | 781 | skipped = 0 |
|
771 | 782 | hidden_frames = self.hidden_frames(self.stack) |
|
772 | 783 | for i in range(self.curindex + 1, len(self.stack)): |
|
773 | frame = self.stack[i][0] | |
|
774 | 784 | if hidden_frames[i] and self.skip_hidden: |
|
775 | 785 | skipped += 1 |
|
776 | 786 | continue |
@@ -796,6 +806,20 b' class Pdb(OldPdb):' | |||
|
796 | 806 | do_d = do_down |
|
797 | 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 | 823 | class InterruptiblePdb(Pdb): |
|
800 | 824 | """Version of debugger where KeyboardInterrupt exits the debugger altogether.""" |
|
801 | 825 |
@@ -656,7 +656,6 b' class GeoJSON(JSON):' | |||
|
656 | 656 | |
|
657 | 657 | Examples |
|
658 | 658 | -------- |
|
659 | ||
|
660 | 659 | The following will display an interactive map of Mars with a point of |
|
661 | 660 | interest on frontend that do support GeoJSON display. |
|
662 | 661 | |
@@ -723,7 +722,7 b' class Javascript(TextDisplayObject):' | |||
|
723 | 722 | running the source code. The full URLs of the libraries should |
|
724 | 723 | be given. A single Javascript library URL can also be given as a |
|
725 | 724 | string. |
|
726 |
css |
|
|
725 | css : list or str | |
|
727 | 726 | A sequence of css files to load before running the source code. |
|
728 | 727 | The full URLs of the css files should be given. A single css URL |
|
729 | 728 | can also be given as a string. |
@@ -851,18 +850,26 b' class Image(DisplayObject):' | |||
|
851 | 850 | |
|
852 | 851 | Examples |
|
853 | 852 | -------- |
|
854 |
|
|
|
855 |
|
|
|
856 |
|
|
|
857 |
|
|
|
858 | Image('http://www.google.fr/images/srpr/logo3w.png') | |
|
859 | Image('/path/to/image.jpg') | |
|
860 | Image(b'RAW_PNG_DATA...') | |
|
861 | ||
|
862 | # Specifying Image(url=...) does not embed the image data, | |
|
863 | # it only generates `<img>` tag with a link to the source. | |
|
864 | # This will not work in the qtconsole or offline. | |
|
865 | Image(url='http://www.google.fr/images/srpr/logo3w.png') | |
|
853 | embedded image data, works in qtconsole and notebook | |
|
854 | when passed positionally, the first arg can be any of raw image data, | |
|
855 | a URL, or a filename from which to load image data. | |
|
856 | The result is always embedding image data for inline images. | |
|
857 | ||
|
858 | >>> Image('http://www.google.fr/images/srpr/logo3w.png') | |
|
859 | <IPython.core.display.Image object> | |
|
860 | ||
|
861 | >>> Image('/path/to/image.jpg') | |
|
862 | <IPython.core.display.Image object> | |
|
863 | ||
|
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 | 875 | if isinstance(data, (Path, PurePath)): |
@@ -1036,24 +1043,23 b' class Video(DisplayObject):' | |||
|
1036 | 1043 | ---------- |
|
1037 | 1044 | data : unicode, str or bytes |
|
1038 | 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 | 1047 | url : unicode |
|
1041 | A URL for the video. If you specify `url=`, | |
|
1048 | A URL for the video. If you specify ``url=``, | |
|
1042 | 1049 | the image data will not be embedded. |
|
1043 | 1050 | filename : unicode |
|
1044 | 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 | 1053 | embed : bool |
|
1047 | 1054 | Should the video be embedded using a data URI (True) or be |
|
1048 | 1055 | loaded using a <video> tag (False). |
|
1049 | 1056 | |
|
1050 | 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 | 1060 | Local files can be displayed with URLs without embedding the content, via:: |
|
1054 | 1061 | |
|
1055 | 1062 | Video('./video.mp4') |
|
1056 | ||
|
1057 | 1063 | mimetype: unicode |
|
1058 | 1064 | Specify the mimetype for embedded videos. |
|
1059 | 1065 | Default will be guessed from file extension, if available. |
@@ -1064,14 +1070,13 b' class Video(DisplayObject):' | |||
|
1064 | 1070 | Height in pixels to which to constrain the video in html. |
|
1065 | 1071 | If not supplied, defaults to the height of the video. |
|
1066 | 1072 | html_attributes : str |
|
1067 | Attributes for the HTML `<video>` block. | |
|
1068 | Default: `"controls"` to get video controls. | |
|
1069 | Other examples: `"controls muted"` for muted video with controls, | |
|
1070 | `"loop autoplay"` for looping autoplaying video without controls. | |
|
1073 | Attributes for the HTML ``<video>`` block. | |
|
1074 | Default: ``"controls"`` to get video controls. | |
|
1075 | Other examples: ``"controls muted"`` for muted video with controls, | |
|
1076 | ``"loop autoplay"`` for looping autoplaying video without controls. | |
|
1071 | 1077 | |
|
1072 | 1078 | Examples |
|
1073 | 1079 | -------- |
|
1074 | ||
|
1075 | 1080 | :: |
|
1076 | 1081 | |
|
1077 | 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 | 1171 | *formats : strs |
|
1167 | 1172 | One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'. |
|
1168 |
**kwargs |
|
|
1173 | **kwargs | |
|
1169 | 1174 | Keyword args will be relayed to ``figure.canvas.print_figure``. |
|
1170 | 1175 | """ |
|
1171 | 1176 | from IPython.core.interactiveshell import InteractiveShell |
@@ -508,6 +508,20 b' def make_tokens_by_line(lines:List[str]):' | |||
|
508 | 508 | |
|
509 | 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 | 525 | def show_linewise_tokens(s: str): |
|
512 | 526 | """For investigation and debugging""" |
|
513 | 527 | if not s.endswith('\n'): |
@@ -662,6 +676,15 b' class TransformerManager:' | |||
|
662 | 676 | |
|
663 | 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 | 688 | if not tokens_by_line: |
|
666 | 689 | return 'incomplete', find_last_indent(lines) |
|
667 | 690 |
@@ -443,6 +443,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
443 | 443 | display_formatter = Instance(DisplayFormatter, allow_none=True) |
|
444 | 444 | displayhook_class = Type(DisplayHook) |
|
445 | 445 | display_pub_class = Type(DisplayPublisher) |
|
446 | compiler_class = Type(CachingCompiler) | |
|
446 | 447 | |
|
447 | 448 | sphinxify_docstring = Bool(False, help= |
|
448 | 449 | """ |
@@ -748,7 +749,7 b' class InteractiveShell(SingletonConfigurable):' | |||
|
748 | 749 | self.more = False |
|
749 | 750 | |
|
750 | 751 | # command compiler |
|
751 |
self.compile = |
|
|
752 | self.compile = self.compiler_class() | |
|
752 | 753 | |
|
753 | 754 | # Make an empty namespace, which extension writers can rely on both |
|
754 | 755 | # existing and NEVER being used by ipython itself. This gives them a |
@@ -931,17 +932,27 b' class InteractiveShell(SingletonConfigurable):' | |||
|
931 | 932 | # Our exe is inside or has access to the virtualenv, don't need to do anything. |
|
932 | 933 | return |
|
933 | 934 | |
|
934 | warn("Attempting to work in a virtualenv. If you encounter problems, please " | |
|
935 | "install IPython inside the virtualenv.") | |
|
936 | 935 | if sys.platform == "win32": |
|
937 |
virtual_env = Path(os.environ["VIRTUAL_ENV"]) |
|
|
938 | "Lib", "site-packages" | |
|
939 | ) | |
|
936 | virtual_env = Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages") | |
|
940 | 937 | else: |
|
941 |
virtual_env = Path( |
|
|
942 |
"lib", "python{}.{}" |
|
|
938 | virtual_env_path = Path( | |
|
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 | 956 | import site |
|
946 | 957 | sys.path.insert(0, virtual_env) |
|
947 | 958 | site.addsitedir(virtual_env) |
@@ -1765,8 +1776,14 b' class InteractiveShell(SingletonConfigurable):' | |||
|
1765 | 1776 | if meth == 'pdoc': |
|
1766 | 1777 | pmethod(info.obj, oname, formatter) |
|
1767 | 1778 | elif meth == 'pinfo': |
|
1768 | pmethod(info.obj, oname, formatter, info, | |
|
1769 | enable_html_pager=self.enable_html_pager, **kw) | |
|
1779 | pmethod( | |
|
1780 | info.obj, | |
|
1781 | oname, | |
|
1782 | formatter, | |
|
1783 | info, | |
|
1784 | enable_html_pager=self.enable_html_pager, | |
|
1785 | **kw | |
|
1786 | ) | |
|
1770 | 1787 | else: |
|
1771 | 1788 | pmethod(info.obj, oname) |
|
1772 | 1789 | else: |
@@ -2289,8 +2306,9 b' class InteractiveShell(SingletonConfigurable):' | |||
|
2289 | 2306 | # Defined here so that it's included in the documentation |
|
2290 | 2307 | @functools.wraps(magic.MagicsManager.register_function) |
|
2291 | 2308 | def register_magic_function(self, func, magic_kind='line', magic_name=None): |
|
2292 |
self.magics_manager.register_function( |
|
|
2293 |
|
|
|
2309 | self.magics_manager.register_function( | |
|
2310 | func, magic_kind=magic_kind, magic_name=magic_name | |
|
2311 | ) | |
|
2294 | 2312 | |
|
2295 | 2313 | def run_line_magic(self, magic_name, line, _stack_depth=1): |
|
2296 | 2314 | """Execute the given line magic. |
@@ -3086,12 +3104,14 b' class InteractiveShell(SingletonConfigurable):' | |||
|
3086 | 3104 | # Our own compiler remembers the __future__ environment. If we want to |
|
3087 | 3105 | # run code with a separate __future__ environment, use the default |
|
3088 | 3106 | # compiler |
|
3089 |
compiler = self.compile if shell_futures else |
|
|
3107 | compiler = self.compile if shell_futures else self.compiler_class() | |
|
3090 | 3108 | |
|
3091 | 3109 | _run_async = False |
|
3092 | 3110 | |
|
3093 | 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 | 3116 | with self.display_trap: |
|
3097 | 3117 | # Compile to bytecode |
@@ -20,7 +20,7 b' import re' | |||
|
20 | 20 | import sys |
|
21 | 21 | import ast |
|
22 | 22 | from itertools import chain |
|
23 | from urllib.request import urlopen | |
|
23 | from urllib.request import Request, urlopen | |
|
24 | 24 | from urllib.parse import urlencode |
|
25 | 25 | from pathlib import Path |
|
26 | 26 | |
@@ -29,6 +29,7 b' from IPython.core.error import TryNext, StdinNotImplementedError, UsageError' | |||
|
29 | 29 | from IPython.core.macro import Macro |
|
30 | 30 | from IPython.core.magic import Magics, magics_class, line_magic |
|
31 | 31 | from IPython.core.oinspect import find_file, find_source_lines |
|
32 | from IPython.core.release import version | |
|
32 | 33 | from IPython.testing.skipdoctest import skip_doctest |
|
33 | 34 | from IPython.utils.contexts import preserve_keys |
|
34 | 35 | from IPython.utils.path import get_py_filename |
@@ -245,7 +246,7 b' class CodeMagics(Magics):' | |||
|
245 | 246 | |
|
246 | 247 | @line_magic |
|
247 | 248 | def pastebin(self, parameter_s=''): |
|
248 |
"""Upload code to dpaste |
|
|
249 | """Upload code to dpaste.com, returning the URL. | |
|
249 | 250 | |
|
250 | 251 | Usage:\\ |
|
251 | 252 | %pastebin [-d "Custom description"] 1-7 |
@@ -255,7 +256,7 b' class CodeMagics(Magics):' | |||
|
255 | 256 | |
|
256 | 257 | Options: |
|
257 | 258 | |
|
258 |
-d: Pass a custom description |
|
|
259 | -d: Pass a custom description. The default will say | |
|
259 | 260 | "Pasted from IPython". |
|
260 | 261 | """ |
|
261 | 262 | opts, args = self.parse_options(parameter_s, 'd:') |
@@ -266,13 +267,19 b' class CodeMagics(Magics):' | |||
|
266 | 267 | print(e.args[0]) |
|
267 | 268 | return |
|
268 | 269 | |
|
269 |
post_data = urlencode( |
|
|
270 | "title": opts.get('d', "Pasted from IPython"), | |
|
271 | "syntax": "python3", | |
|
272 | "content": code | |
|
273 | }).encode('utf-8') | |
|
274 | ||
|
275 | response = urlopen("http://dpaste.com/api/v2/", post_data) | |
|
270 | post_data = urlencode( | |
|
271 | { | |
|
272 | "title": opts.get("d", "Pasted from IPython"), | |
|
273 | "syntax": "python", | |
|
274 | "content": code, | |
|
275 | } | |
|
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 | 283 | return response.headers.get('Location') |
|
277 | 284 | |
|
278 | 285 | @line_magic |
@@ -16,6 +16,7 b'' | |||
|
16 | 16 | import os |
|
17 | 17 | import sys |
|
18 | 18 | from io import open as io_open |
|
19 | import fnmatch | |
|
19 | 20 | |
|
20 | 21 | # Our own packages |
|
21 | 22 | from IPython.core.error import StdinNotImplementedError |
@@ -170,7 +171,8 b' class HistoryMagics(Magics):' | |||
|
170 | 171 | pattern = None |
|
171 | 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 | 176 | if args.pattern: |
|
175 | 177 | pattern = "*" + " ".join(args.pattern) + "*" |
|
176 | 178 | else: |
@@ -183,6 +185,9 b' class HistoryMagics(Magics):' | |||
|
183 | 185 | hist = history_manager.get_tail(n, raw=raw, output=get_output) |
|
184 | 186 | else: |
|
185 | 187 | if args.range: # Get history by ranges |
|
188 | if args.pattern: | |
|
189 | range_pattern = "*" + " ".join(args.pattern) + "*" | |
|
190 | print_nums = True | |
|
186 | 191 | hist = history_manager.get_range_by_str(" ".join(args.range), |
|
187 | 192 | raw, get_output) |
|
188 | 193 | else: # Just get history for the current session |
@@ -200,6 +205,9 b' class HistoryMagics(Magics):' | |||
|
200 | 205 | # into an editor. |
|
201 | 206 | if get_output: |
|
202 | 207 | inline, output = inline |
|
208 | if range_pattern: | |
|
209 | if not fnmatch.fnmatch(inline, range_pattern): | |
|
210 | continue | |
|
203 | 211 | inline = inline.expandtabs(4).rstrip() |
|
204 | 212 | |
|
205 | 213 | multiline = "\n" in inline |
@@ -13,7 +13,6 b' import shlex' | |||
|
13 | 13 | import sys |
|
14 | 14 | from pathlib import Path |
|
15 | 15 | |
|
16 | from pathlib import Path | |
|
17 | 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 | 27 | # Check if there is a conda executable in the same directory as the Python executable. |
|
29 | 28 | # This is the case within conda's root environment. |
|
30 | 29 | conda = Path(sys.executable).parent / "conda" |
|
31 | if conda.isfile(): | |
|
30 | if conda.is_file(): | |
|
32 | 31 | return str(conda) |
|
33 | 32 | |
|
34 | 33 | # Otherwise, attempt to extract the executable from conda history. |
@@ -83,8 +82,9 b' class PackagingMagics(Magics):' | |||
|
83 | 82 | |
|
84 | 83 | conda = _get_conda_executable() |
|
85 | 84 | args = shlex.split(line) |
|
86 | command = args[0] | |
|
87 | args = args[1:] | |
|
85 | command = args[0] if len(args) > 0 else "" | |
|
86 | args = args[1:] if len(args) > 1 else [""] | |
|
87 | ||
|
88 | 88 | extra_args = [] |
|
89 | 89 | |
|
90 | 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 | 183 | ip = get_ipython() |
|
184 | 184 | cfg = _get_inline_config() |
|
185 | 185 | cfg.print_figure_kwargs.update(dict(foo='bar')) |
|
186 |
kwargs = dict( |
|
|
186 | kwargs = dict(dpi=150) | |
|
187 | 187 | display.set_matplotlib_formats('png', **kwargs) |
|
188 | 188 | formatter = ip.display_formatter.formatters['image/png'] |
|
189 | 189 | f = formatter.lookup_by_type(Figure) |
@@ -255,18 +255,18 b' def test_find_assign_op_dedent():' | |||
|
255 | 255 | |
|
256 | 256 | def test_check_complete(): |
|
257 | 257 | cc = ipt2.TransformerManager().check_complete |
|
258 |
nt.assert_equal(cc("a = 1"), ( |
|
|
259 |
nt.assert_equal(cc("for a in range(5):"), ( |
|
|
260 |
nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ( |
|
|
261 |
nt.assert_equal(cc("raise = 2"), ( |
|
|
262 |
nt.assert_equal(cc("a = [1,\n2,"), ( |
|
|
263 |
nt.assert_equal(cc(")"), ( |
|
|
264 |
nt.assert_equal(cc("\\\r\n"), ( |
|
|
265 |
nt.assert_equal(cc("a = '''\n hi"), ( |
|
|
266 |
nt.assert_equal(cc("def a():\n x=1\n global x"), ( |
|
|
267 |
nt.assert_equal(cc("a \\ "), ( |
|
|
268 |
nt.assert_equal(cc("1\\\n+2"), ( |
|
|
269 |
nt.assert_equal(cc("exit"), ( |
|
|
258 | nt.assert_equal(cc("a = 1"), ("complete", None)) | |
|
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:"), ("incomplete", 8)) | |
|
261 | nt.assert_equal(cc("raise = 2"), ("invalid", None)) | |
|
262 | nt.assert_equal(cc("a = [1,\n2,"), ("incomplete", 0)) | |
|
263 | nt.assert_equal(cc("(\n))"), ("incomplete", 0)) | |
|
264 | nt.assert_equal(cc("\\\r\n"), ("incomplete", 0)) | |
|
265 | nt.assert_equal(cc("a = '''\n hi"), ("incomplete", 3)) | |
|
266 | nt.assert_equal(cc("def a():\n x=1\n global x"), ("invalid", None)) | |
|
267 | nt.assert_equal(cc("a \\ "), ("invalid", None)) # Nothing allowed after backslash | |
|
268 | nt.assert_equal(cc("1\\\n+2"), ("complete", None)) | |
|
269 | nt.assert_equal(cc("exit"), ("complete", None)) | |
|
270 | 270 | |
|
271 | 271 | example = dedent(""" |
|
272 | 272 | if True: |
@@ -297,6 +297,24 b' def test_check_complete_II():' | |||
|
297 | 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 | 318 | def test_null_cleanup_transformer(): |
|
301 | 319 | manager = ipt2.TransformerManager() |
|
302 | 320 | manager.cleanup_transforms.insert(0, null_cleanup_transformer) |
@@ -117,84 +117,91 b' ZeroDivisionError Traceback (most recent call last)' | |||
|
117 | 117 | ZeroDivisionError: ... |
|
118 | 118 | """ |
|
119 | 119 | |
|
120 | def doctest_tb_sysexit(): | |
|
121 | """ | |
|
122 | In [17]: %xmode plain | |
|
123 | Exception reporting mode: Plain | |
|
124 | ||
|
125 | In [18]: %run simpleerr.py exit | |
|
126 | An exception has occurred, use %tb to see the full traceback. | |
|
127 | SystemExit: (1, 'Mode = exit') | |
|
128 | ||
|
129 | In [19]: %run simpleerr.py exit 2 | |
|
130 | An exception has occurred, use %tb to see the full traceback. | |
|
131 | SystemExit: (2, 'Mode = exit') | |
|
132 | ||
|
133 | In [20]: %tb | |
|
134 | Traceback (most recent call last): | |
|
135 | File ... in <module> | |
|
136 | bar(mode) | |
|
137 | File ... line 22, in bar | |
|
138 | sysexit(stat, mode) | |
|
139 | File ... line 11, in sysexit | |
|
140 | raise SystemExit(stat, 'Mode = %s' % mode) | |
|
141 | SystemExit: (2, 'Mode = exit') | |
|
142 | ||
|
143 | In [21]: %xmode context | |
|
144 | Exception reporting mode: Context | |
|
145 | ||
|
146 | In [22]: %tb | |
|
147 | --------------------------------------------------------------------------- | |
|
148 | SystemExit Traceback (most recent call last) | |
|
149 | <BLANKLINE> | |
|
150 | ...<module> | |
|
151 | 29 except IndexError: | |
|
152 | 30 mode = 'div' | |
|
153 | ---> 32 bar(mode) | |
|
154 | <BLANKLINE> | |
|
155 | ...bar(mode) | |
|
156 | 20 except: | |
|
157 | 21 stat = 1 | |
|
158 | ---> 22 sysexit(stat, mode) | |
|
159 | 23 else: | |
|
160 | 24 raise ValueError('Unknown mode') | |
|
161 | <BLANKLINE> | |
|
162 | ...sysexit(stat, mode) | |
|
163 | 10 def sysexit(stat, mode): | |
|
164 | ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) | |
|
165 | <BLANKLINE> | |
|
166 | SystemExit: (2, 'Mode = exit') | |
|
167 | ||
|
168 | In [23]: %xmode verbose | |
|
169 | Exception reporting mode: Verbose | |
|
170 | ||
|
171 | In [24]: %tb | |
|
172 | --------------------------------------------------------------------------- | |
|
173 | SystemExit Traceback (most recent call last) | |
|
174 | <BLANKLINE> | |
|
175 | ... in <module> | |
|
176 | 29 except IndexError: | |
|
177 | 30 mode = 'div' | |
|
178 | ---> 32 bar(mode) | |
|
179 | mode = 'exit' | |
|
180 | <BLANKLINE> | |
|
181 | ... in bar(mode='exit') | |
|
182 | 20 except: | |
|
183 | 21 stat = 1 | |
|
184 | ---> 22 sysexit(stat, mode) | |
|
185 | mode = 'exit' | |
|
186 | stat = 2 | |
|
187 | 23 else: | |
|
188 | 24 raise ValueError('Unknown mode') | |
|
189 | <BLANKLINE> | |
|
190 | ... in sysexit(stat=2, mode='exit') | |
|
191 |
|
|
|
192 | ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) | |
|
193 | stat = 2 | |
|
194 | mode = 'exit' | |
|
195 | <BLANKLINE> | |
|
196 | SystemExit: (2, 'Mode = exit') | |
|
197 | """ | |
|
120 | # TODO : Marc 2021 – this seem to fail due | |
|
121 | # to upstream changes in CI for whatever reason. | |
|
122 | # Commenting for now, to revive someday (maybe?) | |
|
123 | # nose won't work in 3.10 anyway and we'll have to disable iptest. | |
|
124 | # thus this likely need to bemigrated to pytest. | |
|
125 | ||
|
126 | ||
|
127 | # def doctest_tb_sysexit(): | |
|
128 | # """ | |
|
129 | # In [17]: %xmode plain | |
|
130 | # Exception reporting mode: Plain | |
|
131 | # | |
|
132 | # In [18]: %run simpleerr.py exit | |
|
133 | # An exception has occurred, use %tb to see the full traceback. | |
|
134 | # SystemExit: (1, 'Mode = exit') | |
|
135 | # | |
|
136 | # In [19]: %run simpleerr.py exit 2 | |
|
137 | # An exception has occurred, use %tb to see the full traceback. | |
|
138 | # SystemExit: (2, 'Mode = exit') | |
|
139 | # | |
|
140 | # In [20]: %tb | |
|
141 | # Traceback (most recent call last): | |
|
142 | # File ... in <module> | |
|
143 | # bar(mode) | |
|
144 | # File ... line 22, in bar | |
|
145 | # sysexit(stat, mode) | |
|
146 | # File ... line 11, in sysexit | |
|
147 | # raise SystemExit(stat, 'Mode = %s' % mode) | |
|
148 | # SystemExit: (2, 'Mode = exit') | |
|
149 | # | |
|
150 | # In [21]: %xmode context | |
|
151 | # Exception reporting mode: Context | |
|
152 | # | |
|
153 | # In [22]: %tb | |
|
154 | # --------------------------------------------------------------------------- | |
|
155 | # SystemExit Traceback (most recent call last) | |
|
156 | # <BLANKLINE> | |
|
157 | # ...<module> | |
|
158 | # 29 except IndexError: | |
|
159 | # 30 mode = 'div' | |
|
160 | # ---> 32 bar(mode) | |
|
161 | # <BLANKLINE> | |
|
162 | # ...bar(mode) | |
|
163 | # 20 except: | |
|
164 | # 21 stat = 1 | |
|
165 | # ---> 22 sysexit(stat, mode) | |
|
166 | # 23 else: | |
|
167 | # 24 raise ValueError('Unknown mode') | |
|
168 | # <BLANKLINE> | |
|
169 | # ...sysexit(stat, mode) | |
|
170 | # 10 def sysexit(stat, mode): | |
|
171 | # ---> 11 raise SystemExit(stat, 'Mode = %s' % mode) | |
|
172 | # <BLANKLINE> | |
|
173 | # SystemExit: (2, 'Mode = exit') | |
|
174 | # | |
|
175 | # In [23]: %xmode verbose | |
|
176 | # Exception reporting mode: Verbose | |
|
177 | # | |
|
178 | # In [24]: %tb | |
|
179 | # --------------------------------------------------------------------------- | |
|
180 | # SystemExit Traceback (most recent call last) | |
|
181 | # <BLANKLINE> | |
|
182 | # ... in <module> | |
|
183 | # 29 except IndexError: | |
|
184 | # 30 mode = 'div' | |
|
185 | # ---> 32 bar(mode) | |
|
186 | # mode = 'exit' | |
|
187 | # <BLANKLINE> | |
|
188 | # ... in bar(mode='exit') | |
|
189 | # 20 except: | |
|
190 | # 21 stat = 1 | |
|
191 | # ---> 22 sysexit(stat, mode) | |
|
192 | # mode = 'exit' | |
|
193 | # stat = 2 | |
|
194 | # 23 else: | |
|
195 | # 24 raise ValueError('Unknown mode') | |
|
196 | # <BLANKLINE> | |
|
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 | 207 | def test_run_cell(): |
@@ -35,6 +35,8 b' from IPython.utils.tempdir import (TemporaryDirectory,' | |||
|
35 | 35 | from IPython.utils.process import find_cmd |
|
36 | 36 | from .test_debugger import PdbTestInput |
|
37 | 37 | |
|
38 | import pytest | |
|
39 | ||
|
38 | 40 | |
|
39 | 41 | @magic.magics_class |
|
40 | 42 | class DummyMagics(magic.Magics): pass |
@@ -954,7 +956,6 b' async def test_script_bg_out():' | |||
|
954 | 956 | nt.assert_equal((await ip.user_ns["output"].read()), b"hi\n") |
|
955 | 957 | ip.user_ns['output'].close() |
|
956 | 958 | |
|
957 | ||
|
958 | 959 | @dec.skip_win32 |
|
959 | 960 | async def test_script_bg_err(): |
|
960 | 961 | ip = get_ipython() |
@@ -8,6 +8,8 b' from os import walk, sep, fsdecode' | |||
|
8 | 8 | |
|
9 | 9 | from IPython.core.display import DisplayObject, TextDisplayObject |
|
10 | 10 | |
|
11 | from typing import Tuple | |
|
12 | ||
|
11 | 13 | __all__ = ['Audio', 'IFrame', 'YouTubeVideo', 'VimeoVideo', 'ScribdDocument', |
|
12 | 14 | 'FileLink', 'FileLinks', 'Code'] |
|
13 | 15 | |
@@ -159,7 +161,7 b' class Audio(DisplayObject):' | |||
|
159 | 161 | return val |
|
160 | 162 | |
|
161 | 163 | @staticmethod |
|
162 | def _validate_and_normalize_with_numpy(data, normalize): | |
|
164 | def _validate_and_normalize_with_numpy(data, normalize) -> Tuple[bytes, int]: | |
|
163 | 165 | import numpy as np |
|
164 | 166 | |
|
165 | 167 | data = np.array(data, dtype=float) |
@@ -178,8 +180,7 b' class Audio(DisplayObject):' | |||
|
178 | 180 | max_abs_value = np.max(np.abs(data)) |
|
179 | 181 | normalization_factor = Audio._get_normalization_factor(max_abs_value, normalize) |
|
180 | 182 | scaled = data / normalization_factor * 32767 |
|
181 |
return scaled.astype( |
|
|
182 | ||
|
183 | return scaled.astype("<h").tobytes(), nchan | |
|
183 | 184 | |
|
184 | 185 | @staticmethod |
|
185 | 186 | def _validate_and_normalize_without_numpy(data, normalize): |
@@ -1,5 +1,4 b'' | |||
|
1 | 1 | import asyncio |
|
2 | import signal | |
|
3 | 2 | import sys |
|
4 | 3 | import threading |
|
5 | 4 | |
@@ -7,13 +6,8 b' from IPython.core.debugger import Pdb' | |||
|
7 | 6 | |
|
8 | 7 | from IPython.core.completer import IPCompleter |
|
9 | 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 | 11 | from pygments.token import Token |
|
18 | 12 | from prompt_toolkit.shortcuts.prompt import PromptSession |
|
19 | 13 | from prompt_toolkit.enums import EditingMode |
@@ -45,10 +39,8 b' class TerminalPdb(Pdb):' | |||
|
45 | 39 | return [(Token.Prompt, self.prompt)] |
|
46 | 40 | |
|
47 | 41 | if self._ptcomp is None: |
|
48 |
compl = IPCompleter( |
|
|
49 | namespace={}, | |
|
50 | global_namespace={}, | |
|
51 | parent=self.shell, | |
|
42 | compl = IPCompleter( | |
|
43 | shell=self.shell, namespace={}, global_namespace={}, parent=self.shell | |
|
52 | 44 | ) |
|
53 | 45 | # add a completer for all the do_ methods |
|
54 | 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 | 42 | CFFileDescriptorCreate = CoreFoundation.CFFileDescriptorCreate |
|
43 | 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 | 46 | CFFileDescriptorGetNativeDescriptor = CoreFoundation.CFFileDescriptorGetNativeDescriptor |
|
47 | 47 | CFFileDescriptorGetNativeDescriptor.restype = ctypes.c_int |
@@ -77,14 +77,31 b" kCFRunLoopCommonModes = void_p.in_dll(CoreFoundation, 'kCFRunLoopCommonModes')" | |||
|
77 | 77 | |
|
78 | 78 | def _NSApp(): |
|
79 | 79 | """Return the global NSApplication instance (NSApp)""" |
|
80 | objc.objc_msgSend.argtypes = [void_p, void_p] | |
|
80 | 81 | return msg(C('NSApplication'), n('sharedApplication')) |
|
81 | 82 | |
|
82 | 83 | |
|
83 | 84 | def _wake(NSApp): |
|
84 | 85 | """Wake the Application""" |
|
85 | event = msg(C('NSEvent'), | |
|
86 | n('otherEventWithType:location:modifierFlags:' | |
|
87 | 'timestamp:windowNumber:context:subtype:data1:data2:'), | |
|
86 | objc.objc_msgSend.argtypes = [ | |
|
87 | void_p, | |
|
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 | 105 | 15, # Type |
|
89 | 106 | 0, # location |
|
90 | 107 | 0, # flags |
@@ -95,6 +112,7 b' def _wake(NSApp):' | |||
|
95 | 112 | 0, # data1 |
|
96 | 113 | 0, # data2 |
|
97 | 114 | ) |
|
115 | objc.objc_msgSend.argtypes = [void_p, void_p, void_p, void_p] | |
|
98 | 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 | 124 | CFFileDescriptorInvalidate(fdref) |
|
107 | 125 | CFRelease(fdref) |
|
108 | 126 | NSApp = _NSApp() |
|
127 | objc.objc_msgSend.argtypes = [void_p, void_p, void_p] | |
|
109 | 128 | msg(NSApp, n('stop:'), NSApp) |
|
110 | 129 | _wake(NSApp) |
|
111 | 130 | |
@@ -128,6 +147,7 b' def inputhook(context):' | |||
|
128 | 147 | """Inputhook for Cocoa (NSApp)""" |
|
129 | 148 | NSApp = _NSApp() |
|
130 | 149 | _stop_on_read(context.fileno()) |
|
150 | objc.objc_msgSend.argtypes = [void_p, void_p] | |
|
131 | 151 | msg(NSApp, n('run')) |
|
132 | 152 | if not _triggered.is_set(): |
|
133 | 153 | # app closed without firing callback, |
@@ -1,6 +1,7 b'' | |||
|
1 | 1 | import sys |
|
2 | 2 | import os |
|
3 | 3 | from IPython.external.qt_for_kernel import QtCore, QtGui |
|
4 | from IPython import get_ipython | |
|
4 | 5 | |
|
5 | 6 | # If we create a QApplication, keep a reference to it so that it doesn't get |
|
6 | 7 | # garbage collected. |
@@ -8,6 +9,12 b' _appref = None' | |||
|
8 | 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 | 18 | def inputhook(context): |
|
12 | 19 | global _appref |
|
13 | 20 | app = QtCore.QCoreApplication.instance() |
@@ -27,6 +34,13 b' def inputhook(context):' | |||
|
27 | 34 | return |
|
28 | 35 | QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) |
|
29 | 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 | 44 | event_loop = QtCore.QEventLoop(app) |
|
31 | 45 | |
|
32 | 46 | if sys.platform == 'win32': |
@@ -9,6 +9,7 b' Module to define and register Terminal IPython shortcuts with' | |||
|
9 | 9 | import warnings |
|
10 | 10 | import signal |
|
11 | 11 | import sys |
|
12 | import re | |
|
12 | 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 | 153 | setuptools, distutils, or any other distribution tools like `flit |
|
154 | 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 | 165 | .. sourcecode:: bash |
|
158 | 166 |
@@ -119,11 +119,6 b' which adds a directory called ``profile_<name>`` to your IPython directory. Then' | |||
|
119 | 119 | you can load this profile by adding ``--profile=<name>`` to your command line |
|
120 | 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 | 122 | IPython extends the config loader for Python files so that you can inherit |
|
128 | 123 | config from another profile. To do this, use a line like this in your Python |
|
129 | 124 | config file: |
@@ -9,15 +9,15 b' IPython Documentation' | |||
|
9 | 9 | :Release: |release| |
|
10 | 10 | :Date: |today| |
|
11 | 11 | |
|
12 | Welcome to the official IPython documentation | |
|
12 | Welcome to the official IPython documentation. | |
|
13 | 13 | |
|
14 | 14 | IPython provides a rich toolkit to help you make the most of using Python |
|
15 | 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 | 21 | :alt: Screenshot of IPython 6.0 |
|
22 | 22 | :align: center |
|
23 | 23 | |
@@ -59,7 +59,7 b' The Command line interface inherits the above functionality and adds' | |||
|
59 | 59 | |
|
60 | 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 | 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 | 84 | repository <http://github.com/ipython/ipython>`_. |
|
85 | 85 | |
|
86 | 86 | |
|
87 | ||
|
88 | ||
|
89 | 87 | .. toctree:: |
|
90 | 88 | :maxdepth: 1 |
|
91 | 89 | :hidden: |
@@ -3,20 +3,20 b' Python vs IPython' | |||
|
3 | 3 | ================= |
|
4 | 4 | |
|
5 | 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 | 9 | ``SyntaxError`` if run in a pure Python shell, or if executing in a Python |
|
10 | 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 | 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 | 21 | .. code-block:: ipython |
|
22 | 22 | |
@@ -58,8 +58,8 b' All the following construct are valid IPython syntax:' | |||
|
58 | 58 | ...: print $months[0]; |
|
59 | 59 | |
|
60 | 60 | |
|
61 | Each of these construct 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 | |
|
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's see each of these examples | |
|
63 | 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 | 93 | namespace will show help relative to this object: |
|
94 | 94 | |
|
95 | 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 | 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 | 131 | matching names: |
|
132 | 132 | |
|
133 | 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 | 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 | 150 | .. code-block:: ipython |
|
151 | 151 | |
@@ -167,7 +167,7 b' Or edit file:' | |||
|
167 | 167 | |
|
168 | 168 | The line after the bang can call any program installed in the underlying |
|
169 | 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 | 172 | .. code-block:: ipython |
|
173 | 173 | |
@@ -176,19 +176,19 b' The later form of expansion supports arbitrary python expression:' | |||
|
176 | 176 | In[2]: !mv $file {file.upper()} |
|
177 | 177 | |
|
178 | 178 | |
|
179 |
The bang can also be present |
|
|
180 |
after the equal sign, or separated from it by a white space. In |
|
|
181 |
standard output of the command after the bang |
|
|
182 | in a list-like object and assign to the left hand side. | |
|
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 this case the | |
|
181 | standard output of the command after the bang will be split out into lines | |
|
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 | 186 | .. code-block:: ipython |
|
187 | 187 | |
|
188 | 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 | 193 | .. code-block:: ipython |
|
194 | 194 | |
@@ -202,19 +202,19 b' You can combine the different possibilities in for loops, condition, functions..' | |||
|
202 | 202 | Magics |
|
203 | 203 | ------ |
|
204 | 204 | |
|
205 |
Magic |
|
|
206 |
|
|
|
205 | Magic functions (magics) are often present in the form of shell-like syntax, but they are | |
|
206 | python functions under the hood. The syntax and assignment possibilities are | |
|
207 | 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 | 212 | .. code-block:: ipython |
|
213 | 213 | |
|
214 | 214 | In[1]: %xmode |
|
215 | 215 | Exception reporting mode: Verbose |
|
216 | 216 | |
|
217 |
|
|
|
217 | Magics support assignment: | |
|
218 | 218 | |
|
219 | 219 | .. code-block:: ipython |
|
220 | 220 | |
@@ -224,7 +224,7 b' And support assignment:' | |||
|
224 | 224 | In [2]: results |
|
225 | 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 | 229 | .. code-block:: ipython |
|
230 | 230 |
@@ -22,6 +22,47 b' Need to be updated:' | |||
|
22 | 22 | |
|
23 | 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 | 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 | 134 | - The ctrl e, ctrl f, and alt f shortcuts work by default in emacs mode. |
|
94 | 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 | 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 | 168 | For more information please see unit test - |
|
109 | 169 | extensions/tests/test_autoreload.py : 'test_autoload_newly_added_objects' |
|
170 | ======= | |
|
110 | 171 | |
|
111 | 172 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. |
|
112 | 173 |
@@ -2,6 +2,105 b'' | |||
|
2 | 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 | 104 | .. _version 719: |
|
6 | 105 | |
|
7 | 106 | IPython 7.19 |
@@ -171,15 +171,23 b' setuptools_extra_args = {}' | |||
|
171 | 171 | # setuptools requirements |
|
172 | 172 | |
|
173 | 173 | extras_require = dict( |
|
174 |
parallel |
|
|
175 |
qtconsole |
|
|
176 |
doc |
|
|
177 | test = ['nose>=0.10.1', 'requests', 'testpath', 'pygments', 'nbformat', 'ipykernel', 'numpy>=1.14'], | |
|
174 | parallel=["ipyparallel"], | |
|
175 | qtconsole=["qtconsole"], | |
|
176 | doc=["Sphinx>=1.3"], | |
|
177 | test=[ | |
|
178 | "nose>=0.10.1", | |
|
179 | "requests", | |
|
180 | "testpath", | |
|
181 | "pygments", | |
|
182 | "nbformat", | |
|
183 | "ipykernel", | |
|
184 | "numpy>=1.16", | |
|
185 | ], | |
|
178 | 186 |
terminal |
|
179 |
kernel |
|
|
180 |
nbformat |
|
|
181 |
notebook |
|
|
182 |
nbconvert |
|
|
187 | kernel=["ipykernel"], | |
|
188 | nbformat=["nbformat"], | |
|
189 | notebook=["notebook", "ipywidgets"], | |
|
190 | nbconvert=["nbconvert"], | |
|
183 | 191 | ) |
|
184 | 192 | |
|
185 | 193 | install_requires = [ |
General Comments 0
You need to be logged in to leave comments.
Login now