##// END OF EJS Templates
Merge pull request #1 from ipython/master...
Kousik Mitra -
r25329:875db0e2 merge
parent child Browse files
Show More
@@ -0,0 +1,64 b''
1 """
2 Inputhook for running the original asyncio event loop while we're waiting for
3 input.
4
5 By default, in IPython, we run the prompt with a different asyncio event loop,
6 because otherwise we risk that people are freezing the prompt by scheduling bad
7 coroutines. E.g., a coroutine that does a while/true and never yield back
8 control to the loop. We can't cancel that.
9
10 However, sometimes we want the asyncio loop to keep running while waiting for
11 a prompt.
12
13 The following example will print the numbers from 1 to 10 above the prompt,
14 while we are waiting for input. (This works also because we use
15 prompt_toolkit`s `patch_stdout`)::
16
17 In [1]: import asyncio
18
19 In [2]: %gui asyncio
20
21 In [3]: async def f():
22 ...: for i in range(10):
23 ...: await asyncio.sleep(1)
24 ...: print(i)
25
26
27 In [4]: asyncio.ensure_future(f())
28
29 """
30 import asyncio
31 from prompt_toolkit import __version__ as ptk_version
32
33 PTK3 = ptk_version.startswith('3.')
34
35
36 # Keep reference to the original asyncio loop, because getting the event loop
37 # within the input hook would return the other loop.
38 loop = asyncio.get_event_loop()
39
40
41 def inputhook(context):
42 """
43 Inputhook for asyncio event loop integration.
44 """
45 # For prompt_toolkit 3.0, this input hook literally doesn't do anything.
46 # The event loop integration here is implemented in `interactiveshell.py`
47 # by running the prompt itself in the current asyncio loop. The main reason
48 # for this is that nesting asyncio event loops is unreliable.
49 if PTK3:
50 return
51
52 # For prompt_toolkit 2.0, we can run the current asyncio event loop,
53 # because prompt_toolkit 2.0 uses a different event loop internally.
54
55 def stop():
56 loop.stop()
57
58 fileno = context.fileno()
59 loop.add_reader(fileno, stop)
60 try:
61 loop.run_forever()
62 finally:
63 loop.remove_reader(fileno)
64
@@ -0,0 +1,60 b''
1
2 .. _shell_mimerenderer:
3
4
5 Mime Renderer Extensions
6 ========================
7
8 Like it's cousins, Jupyter Notebooks and JupyterLab, Terminal IPython can be
9 thought to render a number of mimetypes in the shell. This can be used to either
10 display inline images if your terminal emulator supports it; or open some
11 display results with external file viewers.
12
13 Registering new mimetype handlers can so far only be done my extensions and
14 requires 4 steps:
15
16 - Define a callable that takes 2 parameters:``data`` and ``metadata``; return
17 value of the callable is so far ignored. This callable is responsible for
18 "displaying" the given mimetype. Which can be sending the right escape
19 sequences and bytes to the current terminal; or open an external program. -
20 - Appending the right mimetype to ``ipython.display_formatter.active_types``
21 for IPython to know it should not ignore those mimetypes.
22 - Enabling the given mimetype: ``ipython.display_formatter.formatters[mime].enabled = True``
23 - Registering above callable with mimetype handler:
24 ``ipython.mime_renderers[mime] = handler``
25
26
27 Here is a complete IPython extension to display images inline and convert math
28 to png, before displaying it inline for iterm2 on macOS ::
29
30
31 from base64 import encodebytes
32 from IPython.lib.latextools import latex_to_png
33
34
35 def mathcat(data, meta):
36 png = latex_to_png(f'$${data}$$'.replace('\displaystyle', '').replace('$$$', '$$'))
37 imcat(png, meta)
38
39 IMAGE_CODE = '\033]1337;File=name=name;inline=true;:{}\a'
40
41 def imcat(image_data, metadata):
42 try:
43 print(IMAGE_CODE.format(encodebytes(image_data).decode()))
44 # bug workaround
45 except:
46 print(IMAGE_CODE.format(image_data))
47
48 def register_mimerenderer(ipython, mime, handler):
49 ipython.display_formatter.active_types.append(mime)
50 ipython.display_formatter.formatters[mime].enabled = True
51 ipython.mime_renderers[mime] = handler
52
53 def load_ipython_extension(ipython):
54 register_mimerenderer(ipython, 'image/png', imcat)
55 register_mimerenderer(ipython, 'image/jpeg', imcat)
56 register_mimerenderer(ipython, 'text/latex', mathcat)
57
58 This example only work for iterm2 on macOS and skip error handling for brevity.
59 One could also invoke an external viewer with ``subprocess.run()`` and a
60 temporary file, which is left as an exercise.
@@ -29,6 +29,8 b' from IPython.core.release import author_email'
29 from IPython.utils.sysinfo import sys_info
29 from IPython.utils.sysinfo import sys_info
30 from IPython.utils.py3compat import input
30 from IPython.utils.py3compat import input
31
31
32 from IPython.core.release import __version__ as version
33
32 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
33 # Code
35 # Code
34 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
@@ -68,7 +70,7 b' To ensure accurate tracking of this issue, please file a report about it at:'
68 """
70 """
69
71
70 _lite_message_template = """
72 _lite_message_template = """
71 If you suspect this is an IPython bug, please report it at:
73 If you suspect this is an IPython {version} bug, please report it at:
72 https://github.com/ipython/ipython/issues
74 https://github.com/ipython/ipython/issues
73 or send an email to the mailing list at {email}
75 or send an email to the mailing list at {email}
74
76
@@ -222,5 +224,5 b' def crash_handler_lite(etype, evalue, tb):'
222 else:
224 else:
223 # we are not in a shell, show generic config
225 # we are not in a shell, show generic config
224 config = "c."
226 config = "c."
225 print(_lite_message_template.format(email=author_email, config=config), file=sys.stderr)
227 print(_lite_message_template.format(email=author_email, config=config, version=version), file=sys.stderr)
226
228
@@ -153,7 +153,7 b' class DisplayHook(Configurable):'
153 # This can be set to True by the write_output_prompt method in a subclass
153 # This can be set to True by the write_output_prompt method in a subclass
154 prompt_end_newline = False
154 prompt_end_newline = False
155
155
156 def write_format_data(self, format_dict, md_dict=None):
156 def write_format_data(self, format_dict, md_dict=None) -> None:
157 """Write the format data dict to the frontend.
157 """Write the format data dict to the frontend.
158
158
159 This default version of this method simply writes the plain text
159 This default version of this method simply writes the plain text
@@ -19,7 +19,7 b' spec.'
19 import sys
19 import sys
20
20
21 from traitlets.config.configurable import Configurable
21 from traitlets.config.configurable import Configurable
22 from traitlets import List
22 from traitlets import List, Dict
23
23
24 # This used to be defined here - it is imported for backwards compatibility
24 # This used to be defined here - it is imported for backwards compatibility
25 from .display import publish_display_data
25 from .display import publish_display_data
@@ -28,6 +28,7 b' from .display import publish_display_data'
28 # Main payload class
28 # Main payload class
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31
31 class DisplayPublisher(Configurable):
32 class DisplayPublisher(Configurable):
32 """A traited class that publishes display data to frontends.
33 """A traited class that publishes display data to frontends.
33
34
@@ -35,6 +36,10 b' class DisplayPublisher(Configurable):'
35 be accessed there.
36 be accessed there.
36 """
37 """
37
38
39 def __init__(self, shell=None, *args, **kwargs):
40 self.shell = shell
41 super().__init__(*args, **kwargs)
42
38 def _validate_data(self, data, metadata=None):
43 def _validate_data(self, data, metadata=None):
39 """Validate the display data.
44 """Validate the display data.
40
45
@@ -53,7 +58,7 b' class DisplayPublisher(Configurable):'
53 raise TypeError('metadata must be a dict, got: %r' % data)
58 raise TypeError('metadata must be a dict, got: %r' % data)
54
59
55 # use * to indicate transient, update are keyword-only
60 # use * to indicate transient, update are keyword-only
56 def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs):
61 def publish(self, data, metadata=None, source=None, *, transient=None, update=False, **kwargs) -> None:
57 """Publish data and metadata to all frontends.
62 """Publish data and metadata to all frontends.
58
63
59 See the ``display_data`` message in the messaging documentation for
64 See the ``display_data`` message in the messaging documentation for
@@ -98,7 +103,15 b' class DisplayPublisher(Configurable):'
98 rather than creating a new output.
103 rather than creating a new output.
99 """
104 """
100
105
101 # The default is to simply write the plain text data using sys.stdout.
106 handlers = {}
107 if self.shell is not None:
108 handlers = getattr(self.shell, 'mime_renderers', {})
109
110 for mime, handler in handlers.items():
111 if mime in data:
112 handler(data[mime], metadata.get(mime, None))
113 return
114
102 if 'text/plain' in data:
115 if 'text/plain' in data:
103 print(data['text/plain'])
116 print(data['text/plain'])
104
117
@@ -857,7 +857,7 b' class InteractiveShell(SingletonConfigurable):'
857 self.configurables.append(self.display_formatter)
857 self.configurables.append(self.display_formatter)
858
858
859 def init_display_pub(self):
859 def init_display_pub(self):
860 self.display_pub = self.display_pub_class(parent=self)
860 self.display_pub = self.display_pub_class(parent=self, shell=self)
861 self.configurables.append(self.display_pub)
861 self.configurables.append(self.display_pub)
862
862
863 def init_data_pub(self):
863 def init_data_pub(self):
@@ -853,6 +853,8 b' python-profiler package from non-free.""")'
853 sys.argv = save_argv
853 sys.argv = save_argv
854 if restore_main:
854 if restore_main:
855 sys.modules['__main__'] = restore_main
855 sys.modules['__main__'] = restore_main
856 if '__mp_main__' in sys.modules:
857 sys.modules['__mp_main__'] = restore_main
856 else:
858 else:
857 # Remove from sys.modules the reference to main_mod we'd
859 # Remove from sys.modules the reference to main_mod we'd
858 # added. Otherwise it will trap references to objects
860 # added. Otherwise it will trap references to objects
@@ -76,7 +76,7 b" info_fields = ['type_name', 'base_class', 'string_form', 'namespace',"
76 'call_def', 'call_docstring',
76 'call_def', 'call_docstring',
77 # These won't be printed but will be used to determine how to
77 # These won't be printed but will be used to determine how to
78 # format the object
78 # format the object
79 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
79 'ismagic', 'isalias', 'isclass', 'found', 'name'
80 ]
80 ]
81
81
82
82
@@ -200,26 +200,39 b' def is_simple_callable(obj):'
200 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
200 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
201 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
201 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
202
202
203
203 @undoc
204 def getargspec(obj):
204 def getargspec(obj):
205 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
205 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
206 :func:inspect.getargspec` on Python 2.
206 :func:inspect.getargspec` on Python 2.
207
207
208 In addition to functions and methods, this can also handle objects with a
208 In addition to functions and methods, this can also handle objects with a
209 ``__call__`` attribute.
209 ``__call__`` attribute.
210
211 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
210 """
212 """
213
214 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
215 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
216
211 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
217 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
212 obj = obj.__call__
218 obj = obj.__call__
213
219
214 return inspect.getfullargspec(obj)
220 return inspect.getfullargspec(obj)
215
221
216
222 @undoc
217 def format_argspec(argspec):
223 def format_argspec(argspec):
218 """Format argspect, convenience wrapper around inspect's.
224 """Format argspect, convenience wrapper around inspect's.
219
225
220 This takes a dict instead of ordered arguments and calls
226 This takes a dict instead of ordered arguments and calls
221 inspect.format_argspec with the arguments in the necessary order.
227 inspect.format_argspec with the arguments in the necessary order.
228
229 DEPRECATED: Do not use; will be removed in future versions.
222 """
230 """
231
232 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
233 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
234
235
223 return inspect.formatargspec(argspec['args'], argspec['varargs'],
236 return inspect.formatargspec(argspec['args'], argspec['varargs'],
224 argspec['varkw'], argspec['defaults'])
237 argspec['varkw'], argspec['defaults'])
225
238
@@ -916,33 +929,6 b' class Inspector(Colorable):'
916 if call_ds:
929 if call_ds:
917 out['call_docstring'] = call_ds
930 out['call_docstring'] = call_ds
918
931
919 # Compute the object's argspec as a callable. The key is to decide
920 # whether to pull it from the object itself, from its __init__ or
921 # from its __call__ method.
922
923 if inspect.isclass(obj):
924 # Old-style classes need not have an __init__
925 callable_obj = getattr(obj, "__init__", None)
926 elif callable(obj):
927 callable_obj = obj
928 else:
929 callable_obj = None
930
931 if callable_obj is not None:
932 try:
933 argspec = getargspec(callable_obj)
934 except Exception:
935 # For extensions/builtins we can't retrieve the argspec
936 pass
937 else:
938 # named tuples' _asdict() method returns an OrderedDict, but we
939 # we want a normal
940 out['argspec'] = argspec_dict = dict(argspec._asdict())
941 # We called this varkw before argspec became a named tuple.
942 # With getfullargspec it's also called varkw.
943 if 'varkw' not in argspec_dict:
944 argspec_dict['varkw'] = argspec_dict.pop('keywords')
945
946 return object_info(**out)
932 return object_info(**out)
947
933
948 @staticmethod
934 @staticmethod
@@ -15,9 +15,11 b' rid of that dependency, we could move it there.'
15
15
16
16
17 import os
17 import os
18 import io
18 import re
19 import re
19 import sys
20 import sys
20 import tempfile
21 import tempfile
22 import subprocess
21
23
22 from io import UnsupportedOperation
24 from io import UnsupportedOperation
23
25
@@ -208,9 +210,13 b' def pager_page(strng, start=0, screen_lines=0, pager_cmd=None):'
208 else:
210 else:
209 try:
211 try:
210 retval = None
212 retval = None
211 # if I use popen4, things hang. No idea why.
213 # Emulate os.popen, but redirect stderr
212 #pager,shell_out = os.popen4(pager_cmd)
214 proc = subprocess.Popen(pager_cmd,
213 pager = os.popen(pager_cmd, 'w')
215 shell=True,
216 stdin=subprocess.PIPE,
217 stderr=subprocess.DEVNULL
218 )
219 pager = os._wrap_close(io.TextIOWrapper(proc.stdin), proc)
214 try:
220 try:
215 pager_encoding = pager.encoding or sys.stdout.encoding
221 pager_encoding = pager.encoding or sys.stdout.encoding
216 pager.write(strng)
222 pager.write(strng)
@@ -20,7 +20,7 b" name = 'ipython'"
20 # release. 'dev' as a _version_extra string means this is a development
20 # release. 'dev' as a _version_extra string means this is a development
21 # version
21 # version
22 _version_major = 7
22 _version_major = 7
23 _version_minor = 10
23 _version_minor = 11
24 _version_patch = 0
24 _version_patch = 0
25 _version_extra = '.dev'
25 _version_extra = '.dev'
26 # _version_extra = 'b1'
26 # _version_extra = 'b1'
@@ -7,7 +7,6 b" with better-isolated tests that don't rely on the global instance in iptest."
7 """
7 """
8 from IPython.core.splitinput import LineInfo
8 from IPython.core.splitinput import LineInfo
9 from IPython.core.prefilter import AutocallChecker
9 from IPython.core.prefilter import AutocallChecker
10 from IPython.utils import py3compat
11
10
12 def doctest_autocall():
11 def doctest_autocall():
13 """
12 """
@@ -49,11 +49,11 b' def test_handlers():'
49 # For many of the below, we're also checking that leading whitespace
49 # For many of the below, we're also checking that leading whitespace
50 # turns off the esc char, which it should unless there is a continuation
50 # turns off the esc char, which it should unless there is a continuation
51 # line.
51 # line.
52 run([(i,py3compat.u_format(o)) for i,o in \
52 run(
53 [('"no change"', '"no change"'), # normal
53 [('"no change"', '"no change"'), # normal
54 (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
54 (u"lsmagic", "get_ipython().run_line_magic('lsmagic', '')"), # magic
55 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
55 #("a = b # PYTHON-MODE", '_i'), # emacs -- avoids _in cache
56 ]])
56 ])
57
57
58 # Objects which are instances of IPyAutocall are *always* autocalled
58 # Objects which are instances of IPyAutocall are *always* autocalled
59 autocallable = Autocallable()
59 autocallable = Autocallable()
@@ -539,6 +539,35 b' def test_run_tb():'
539 del ip.user_ns['bar']
539 del ip.user_ns['bar']
540 del ip.user_ns['foo']
540 del ip.user_ns['foo']
541
541
542
543 def test_multiprocessing_run():
544 """Set we can run mutiprocesgin without messing up up main namespace
545
546 Note that import `nose.tools as nt` mdify the value s
547 sys.module['__mp_main__'] so wee need to temporarily set it to None to test
548 the issue.
549 """
550 with TemporaryDirectory() as td:
551 mpm = sys.modules.get('__mp_main__')
552 assert mpm is not None
553 sys.modules['__mp_main__'] = None
554 try:
555 path = pjoin(td, 'test.py')
556 with open(path, 'w') as f:
557 f.write("import multiprocessing\nprint('hoy')")
558 with capture_output() as io:
559 _ip.run_line_magic('run', path)
560 _ip.run_cell("i_m_undefined")
561 out = io.stdout
562 nt.assert_in("hoy", out)
563 nt.assert_not_in("AttributeError", out)
564 nt.assert_in("NameError", out)
565 nt.assert_equal(out.count("---->"), 1)
566 except:
567 raise
568 finally:
569 sys.modules['__mp_main__'] = mpm
570
542 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
571 @dec.knownfailureif(sys.platform == 'win32', "writes to io.stdout aren't captured on Windows")
543 def test_script_tb():
572 def test_script_tb():
544 """Test traceback offset in `ipython script.py`"""
573 """Test traceback offset in `ipython script.py`"""
@@ -296,6 +296,25 b' except Exception:'
296 tt.AssertPrints("ValueError", suppress=False):
296 tt.AssertPrints("ValueError", suppress=False):
297 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
297 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
298
298
299 def test_plain_direct_cause_error(self):
300 with tt.AssertPrints(["KeyError", "NameError", "direct cause"]):
301 ip.run_cell("%xmode Plain")
302 ip.run_cell(self.DIRECT_CAUSE_ERROR_CODE)
303 ip.run_cell("%xmode Verbose")
304
305 def test_plain_exception_during_handling_error(self):
306 with tt.AssertPrints(["KeyError", "NameError", "During handling"]):
307 ip.run_cell("%xmode Plain")
308 ip.run_cell(self.EXCEPTION_DURING_HANDLING_CODE)
309 ip.run_cell("%xmode Verbose")
310
311 def test_plain_suppress_exception_chaining(self):
312 with tt.AssertNotPrints("ZeroDivisionError"), \
313 tt.AssertPrints("ValueError", suppress=False):
314 ip.run_cell("%xmode Plain")
315 ip.run_cell(self.SUPPRESS_CHAINING_CODE)
316 ip.run_cell("%xmode Verbose")
317
299
318
300 class RecursionTest(unittest.TestCase):
319 class RecursionTest(unittest.TestCase):
301 DEFINITIONS = """
320 DEFINITIONS = """
@@ -530,6 +530,30 b' class TBTools(colorable.Colorable):'
530
530
531 ostream = property(_get_ostream, _set_ostream)
531 ostream = property(_get_ostream, _set_ostream)
532
532
533 def get_parts_of_chained_exception(self, evalue):
534 def get_chained_exception(exception_value):
535 cause = getattr(exception_value, '__cause__', None)
536 if cause:
537 return cause
538 if getattr(exception_value, '__suppress_context__', False):
539 return None
540 return getattr(exception_value, '__context__', None)
541
542 chained_evalue = get_chained_exception(evalue)
543
544 if chained_evalue:
545 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
546
547 def prepare_chained_exception_message(self, cause):
548 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
549 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
550
551 if cause:
552 message = [[direct_cause]]
553 else:
554 message = [[exception_during_handling]]
555 return message
556
533 def set_colors(self, *args, **kw):
557 def set_colors(self, *args, **kw):
534 """Shorthand access to the color table scheme selector method."""
558 """Shorthand access to the color table scheme selector method."""
535
559
@@ -603,7 +627,7 b' class ListTB(TBTools):'
603 self.ostream.write(self.text(etype, value, elist))
627 self.ostream.write(self.text(etype, value, elist))
604 self.ostream.write('\n')
628 self.ostream.write('\n')
605
629
606 def structured_traceback(self, etype, value, elist, tb_offset=None,
630 def structured_traceback(self, etype, evalue, etb=None, tb_offset=None,
607 context=5):
631 context=5):
608 """Return a color formatted string with the traceback info.
632 """Return a color formatted string with the traceback info.
609
633
@@ -612,15 +636,16 b' class ListTB(TBTools):'
612 etype : exception type
636 etype : exception type
613 Type of the exception raised.
637 Type of the exception raised.
614
638
615 value : object
639 evalue : object
616 Data stored in the exception
640 Data stored in the exception
617
641
618 elist : list
642 etb : object
619 List of frames, see class docstring for details.
643 If list: List of frames, see class docstring for details.
644 If Traceback: Traceback of the exception.
620
645
621 tb_offset : int, optional
646 tb_offset : int, optional
622 Number of frames in the traceback to skip. If not given, the
647 Number of frames in the traceback to skip. If not given, the
623 instance value is used (set in constructor).
648 instance evalue is used (set in constructor).
624
649
625 context : int, optional
650 context : int, optional
626 Number of lines of context information to print.
651 Number of lines of context information to print.
@@ -629,6 +654,19 b' class ListTB(TBTools):'
629 -------
654 -------
630 String with formatted exception.
655 String with formatted exception.
631 """
656 """
657 # This is a workaround to get chained_exc_ids in recursive calls
658 # etb should not be a tuple if structured_traceback is not recursive
659 if isinstance(etb, tuple):
660 etb, chained_exc_ids = etb
661 else:
662 chained_exc_ids = set()
663
664 if isinstance(etb, list):
665 elist = etb
666 elif etb is not None:
667 elist = self._extract_tb(etb)
668 else:
669 elist = []
632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
670 tb_offset = self.tb_offset if tb_offset is None else tb_offset
633 Colors = self.Colors
671 Colors = self.Colors
634 out_list = []
672 out_list = []
@@ -641,9 +679,25 b' class ListTB(TBTools):'
641 (Colors.normalEm, Colors.Normal) + '\n')
679 (Colors.normalEm, Colors.Normal) + '\n')
642 out_list.extend(self._format_list(elist))
680 out_list.extend(self._format_list(elist))
643 # The exception info should be a single entry in the list.
681 # The exception info should be a single entry in the list.
644 lines = ''.join(self._format_exception_only(etype, value))
682 lines = ''.join(self._format_exception_only(etype, evalue))
645 out_list.append(lines)
683 out_list.append(lines)
646
684
685 exception = self.get_parts_of_chained_exception(evalue)
686
687 if exception and not id(exception[1]) in chained_exc_ids:
688 chained_exception_message = self.prepare_chained_exception_message(
689 evalue.__cause__)[0]
690 etype, evalue, etb = exception
691 # Trace exception to avoid infinite 'cause' loop
692 chained_exc_ids.add(id(exception[1]))
693 chained_exceptions_tb_offset = 0
694 out_list = (
695 self.structured_traceback(
696 etype, evalue, (etb, chained_exc_ids),
697 chained_exceptions_tb_offset, context)
698 + chained_exception_message
699 + out_list)
700
647 return out_list
701 return out_list
648
702
649 def _format_list(self, extracted_list):
703 def _format_list(self, extracted_list):
@@ -763,7 +817,7 b' class ListTB(TBTools):'
763 etype : exception type
817 etype : exception type
764 value : exception value
818 value : exception value
765 """
819 """
766 return ListTB.structured_traceback(self, etype, value, [])
820 return ListTB.structured_traceback(self, etype, value)
767
821
768 def show_exception_only(self, etype, evalue):
822 def show_exception_only(self, etype, evalue):
769 """Only print the exception type and message, without a traceback.
823 """Only print the exception type and message, without a traceback.
@@ -1013,16 +1067,6 b' class VerboseTB(TBTools):'
1013 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1067 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1014 _line_format)))
1068 _line_format)))
1015
1069
1016 def prepare_chained_exception_message(self, cause):
1017 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1018 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1019
1020 if cause:
1021 message = [[direct_cause]]
1022 else:
1023 message = [[exception_during_handling]]
1024 return message
1025
1026 def prepare_header(self, etype, long_version=False):
1070 def prepare_header(self, etype, long_version=False):
1027 colors = self.Colors # just a shorthand + quicker name lookup
1071 colors = self.Colors # just a shorthand + quicker name lookup
1028 colorsnormal = colors.Normal # used a lot
1072 colorsnormal = colors.Normal # used a lot
@@ -1117,20 +1161,6 b' class VerboseTB(TBTools):'
1117 info('\nUnfortunately, your original traceback can not be constructed.\n')
1161 info('\nUnfortunately, your original traceback can not be constructed.\n')
1118 return None
1162 return None
1119
1163
1120 def get_parts_of_chained_exception(self, evalue):
1121 def get_chained_exception(exception_value):
1122 cause = getattr(exception_value, '__cause__', None)
1123 if cause:
1124 return cause
1125 if getattr(exception_value, '__suppress_context__', False):
1126 return None
1127 return getattr(exception_value, '__context__', None)
1128
1129 chained_evalue = get_chained_exception(evalue)
1130
1131 if chained_evalue:
1132 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1133
1134 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1164 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1135 number_of_lines_of_context=5):
1165 number_of_lines_of_context=5):
1136 """Return a nice text document describing the traceback."""
1166 """Return a nice text document describing the traceback."""
@@ -1294,9 +1324,8 b' class FormattedTB(VerboseTB, ListTB):'
1294 # out-of-date source code.
1324 # out-of-date source code.
1295 self.check_cache()
1325 self.check_cache()
1296 # Now we can extract and format the exception
1326 # Now we can extract and format the exception
1297 elist = self._extract_tb(tb)
1298 return ListTB.structured_traceback(
1327 return ListTB.structured_traceback(
1299 self, etype, value, elist, tb_offset, number_of_lines_of_context
1328 self, etype, value, tb, tb_offset, number_of_lines_of_context
1300 )
1329 )
1301
1330
1302 def stb2text(self, stb):
1331 def stb2text(self, stb):
@@ -32,15 +32,15 b' def win32_clipboard_get():'
32 win32clipboard.CloseClipboard()
32 win32clipboard.CloseClipboard()
33 return text
33 return text
34
34
35 def osx_clipboard_get():
35 def osx_clipboard_get() -> str:
36 """ Get the clipboard's text on OS X.
36 """ Get the clipboard's text on OS X.
37 """
37 """
38 p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
38 p = subprocess.Popen(['pbpaste', '-Prefer', 'ascii'],
39 stdout=subprocess.PIPE)
39 stdout=subprocess.PIPE)
40 text, stderr = p.communicate()
40 bytes_, stderr = p.communicate()
41 # Text comes in with old Mac \r line endings. Change them to \n.
41 # Text comes in with old Mac \r line endings. Change them to \n.
42 text = text.replace(b'\r', b'\n')
42 bytes_ = bytes_.replace(b'\r', b'\n')
43 text = py3compat.cast_unicode(text, py3compat.DEFAULT_ENCODING)
43 text = py3compat.decode(bytes_)
44 return text
44 return text
45
45
46 def tkinter_clipboard_get():
46 def tkinter_clipboard_get():
@@ -97,9 +97,6 b" __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',"
97
97
98
98
99 MAX_SEQ_LENGTH = 1000
99 MAX_SEQ_LENGTH = 1000
100 # The language spec says that dicts preserve order from 3.7, but CPython
101 # does so from 3.6, so it seems likely that people will expect that.
102 DICT_IS_ORDERED = True
103 _re_pattern_type = type(re.compile(''))
100 _re_pattern_type = type(re.compile(''))
104
101
105 def _safe_getattr(obj, attr, default=None):
102 def _safe_getattr(obj, attr, default=None):
@@ -606,11 +603,6 b' def _dict_pprinter_factory(start, end):'
606 step = len(start)
603 step = len(start)
607 p.begin_group(step, start)
604 p.begin_group(step, start)
608 keys = obj.keys()
605 keys = obj.keys()
609 # if dict isn't large enough to be truncated, sort keys before displaying
610 # From Python 3.7, dicts preserve order by definition, so we don't sort.
611 if not DICT_IS_ORDERED \
612 and not (p.max_seq_length and len(obj) >= p.max_seq_length):
613 keys = _sorted_for_pprint(keys)
614 for idx, key in p._enumerate(keys):
606 for idx, key in p._enumerate(keys):
615 if idx:
607 if idx:
616 p.text(',')
608 p.text(',')
@@ -12,7 +12,7 b' from IPython.utils.path import ('
12 ensure_dir_exists, fs_encoding)
12 ensure_dir_exists, fs_encoding)
13 from IPython.utils import py3compat
13 from IPython.utils import py3compat
14
14
15 def get_ipython_dir():
15 def get_ipython_dir() -> str:
16 """Get the IPython directory for this platform and user.
16 """Get the IPython directory for this platform and user.
17
17
18 This uses the logic in `get_home_dir` to find the home directory
18 This uses the logic in `get_home_dir` to find the home directory
@@ -28,10 +28,9 b' def get_ipython_dir():'
28 home_dir = get_home_dir()
28 home_dir = get_home_dir()
29 xdg_dir = get_xdg_dir()
29 xdg_dir = get_xdg_dir()
30
30
31 # import pdb; pdb.set_trace() # dbg
32 if 'IPYTHON_DIR' in env:
31 if 'IPYTHON_DIR' in env:
33 warn('The environment variable IPYTHON_DIR is deprecated. '
32 warn('The environment variable IPYTHON_DIR is deprecated since IPython 3.0. '
34 'Please use IPYTHONDIR instead.')
33 'Please use IPYTHONDIR instead.', DeprecationWarning)
35 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
34 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
36 if ipdir is None:
35 if ipdir is None:
37 # not set explicitly, use ~/.ipython
36 # not set explicitly, use ~/.ipython
@@ -67,11 +66,11 b' def get_ipython_dir():'
67 warn("IPython parent '{0}' is not a writable location,"
66 warn("IPython parent '{0}' is not a writable location,"
68 " using a temp directory.".format(parent))
67 " using a temp directory.".format(parent))
69 ipdir = tempfile.mkdtemp()
68 ipdir = tempfile.mkdtemp()
69 assert isinstance(ipdir, str), "all path manipulation should be str(unicode), but are not."
70 return ipdir
70
71
71 return py3compat.cast_unicode(ipdir, fs_encoding)
72
72
73
73 def get_ipython_cache_dir() -> str:
74 def get_ipython_cache_dir():
75 """Get the cache directory it is created if it does not exist."""
74 """Get the cache directory it is created if it does not exist."""
76 xdgdir = get_xdg_cache_dir()
75 xdgdir = get_xdg_cache_dir()
77 if xdgdir is None:
76 if xdgdir is None:
@@ -82,13 +81,14 b' def get_ipython_cache_dir():'
82 elif not _writable_dir(xdgdir):
81 elif not _writable_dir(xdgdir):
83 return get_ipython_dir()
82 return get_ipython_dir()
84
83
85 return py3compat.cast_unicode(ipdir, fs_encoding)
84 return ipdir
86
85
87
86
88 def get_ipython_package_dir():
87 def get_ipython_package_dir() -> str:
89 """Get the base directory where IPython itself is installed."""
88 """Get the base directory where IPython itself is installed."""
90 ipdir = os.path.dirname(IPython.__file__)
89 ipdir = os.path.dirname(IPython.__file__)
91 return py3compat.cast_unicode(ipdir, fs_encoding)
90 assert isinstance(ipdir, str)
91 return ipdir
92
92
93
93
94 def get_ipython_module_path(module_str):
94 def get_ipython_module_path(module_str):
@@ -17,6 +17,9 b' from prompt_toolkit.shortcuts.prompt import PromptSession'
17 from prompt_toolkit.enums import EditingMode
17 from prompt_toolkit.enums import EditingMode
18 from prompt_toolkit.formatted_text import PygmentsTokens
18 from prompt_toolkit.formatted_text import PygmentsTokens
19
19
20 from prompt_toolkit import __version__ as ptk_version
21 PTK3 = ptk_version.startswith('3.')
22
20
23
21 class TerminalPdb(Pdb):
24 class TerminalPdb(Pdb):
22 """Standalone IPython debugger."""
25 """Standalone IPython debugger."""
@@ -49,20 +52,23 b' class TerminalPdb(Pdb):'
49 & ~cursor_in_leading_ws
52 & ~cursor_in_leading_ws
50 ))(display_completions_like_readline)
53 ))(display_completions_like_readline)
51
54
52 self.pt_app = PromptSession(
55 options = dict(
53 message=(lambda: PygmentsTokens(get_prompt_tokens())),
56 message=(lambda: PygmentsTokens(get_prompt_tokens())),
54 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
57 editing_mode=getattr(EditingMode, self.shell.editing_mode.upper()),
55 key_bindings=kb,
58 key_bindings=kb,
56 history=self.shell.debugger_history,
59 history=self.shell.debugger_history,
57 completer=self._ptcomp,
60 completer=self._ptcomp,
58 enable_history_search=True,
61 enable_history_search=True,
59 mouse_support=self.shell.mouse_support,
62 mouse_support=self.shell.mouse_support,
60 complete_style=self.shell.pt_complete_style,
63 complete_style=self.shell.pt_complete_style,
61 style=self.shell.style,
64 style=self.shell.style,
62 inputhook=self.shell.inputhook,
65 color_depth=self.shell.color_depth,
63 color_depth=self.shell.color_depth,
64 )
66 )
65
67
68 if not PTK3:
69 options['inputhook'] = self.shell.inputhook
70 self.pt_app = PromptSession(**options)
71
66 def cmdloop(self, intro=None):
72 def cmdloop(self, intro=None):
67 """Repeatedly issue a prompt, accept input, parse an initial prefix
73 """Repeatedly issue a prompt, accept input, parse an initial prefix
68 off the received input, and dispatch to action methods, passing them
74 off the received input, and dispatch to action methods, passing them
@@ -1,5 +1,6 b''
1 """IPython terminal interface using prompt_toolkit"""
1 """IPython terminal interface using prompt_toolkit"""
2
2
3 import asyncio
3 import os
4 import os
4 import sys
5 import sys
5 import warnings
6 import warnings
@@ -25,6 +26,7 b' from prompt_toolkit.patch_stdout import patch_stdout'
25 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
26 from prompt_toolkit.shortcuts import PromptSession, CompleteStyle, print_formatted_text
26 from prompt_toolkit.styles import DynamicStyle, merge_styles
27 from prompt_toolkit.styles import DynamicStyle, merge_styles
27 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
28 from prompt_toolkit.styles.pygments import style_from_pygments_cls, style_from_pygments_dict
29 from prompt_toolkit import __version__ as ptk_version
28
30
29 from pygments.styles import get_style_by_name
31 from pygments.styles import get_style_by_name
30 from pygments.style import Style
32 from pygments.style import Style
@@ -38,6 +40,7 b' from .ptutils import IPythonPTCompleter, IPythonPTLexer'
38 from .shortcuts import create_ipython_shortcuts
40 from .shortcuts import create_ipython_shortcuts
39
41
40 DISPLAY_BANNER_DEPRECATED = object()
42 DISPLAY_BANNER_DEPRECATED = object()
43 PTK3 = ptk_version.startswith('3.')
41
44
42
45
43 class _NoStyle(Style): pass
46 class _NoStyle(Style): pass
@@ -87,7 +90,17 b' else:'
87
90
88 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
91 _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty)
89
92
93 def black_reformat_handler(text_before_cursor):
94 import black
95 formatted_text = black.format_str(text_before_cursor, mode=black.FileMode())
96 if not text_before_cursor.endswith('\n') and formatted_text.endswith('\n'):
97 formatted_text = formatted_text[:-1]
98 return formatted_text
99
100
90 class TerminalInteractiveShell(InteractiveShell):
101 class TerminalInteractiveShell(InteractiveShell):
102 mime_renderers = Dict().tag(config=True)
103
91 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
104 space_for_menu = Integer(6, help='Number of line at the bottom of the screen '
92 'to reserve for the completion menu'
105 'to reserve for the completion menu'
93 ).tag(config=True)
106 ).tag(config=True)
@@ -120,6 +133,11 b' class TerminalInteractiveShell(InteractiveShell):'
120 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
133 help="Shortcut style to use at the prompt. 'vi' or 'emacs'.",
121 ).tag(config=True)
134 ).tag(config=True)
122
135
136 autoformatter = Unicode(None,
137 help="Autoformatter to reformat Terminal code. Can be `'black'` or `None`",
138 allow_none=True
139 ).tag(config=True)
140
123 mouse_support = Bool(False,
141 mouse_support = Bool(False,
124 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
142 help="Enable mouse support in the prompt\n(Note: prevents selecting text with the mouse)"
125 ).tag(config=True)
143 ).tag(config=True)
@@ -150,6 +168,16 b' class TerminalInteractiveShell(InteractiveShell):'
150 if self.pt_app:
168 if self.pt_app:
151 self.pt_app.editing_mode = u_mode
169 self.pt_app.editing_mode = u_mode
152
170
171 @observe('autoformatter')
172 def _autoformatter_changed(self, change):
173 formatter = change.new
174 if formatter is None:
175 self.reformat_handler = lambda x:x
176 elif formatter == 'black':
177 self.reformat_handler = black_reformat_handler
178 else:
179 raise ValueError
180
153 @observe('highlighting_style')
181 @observe('highlighting_style')
154 @observe('colors')
182 @observe('colors')
155 def _highlighting_style_changed(self, change):
183 def _highlighting_style_changed(self, change):
@@ -282,6 +310,7 b' class TerminalInteractiveShell(InteractiveShell):'
282
310
283 editing_mode = getattr(EditingMode, self.editing_mode.upper())
311 editing_mode = getattr(EditingMode, self.editing_mode.upper())
284
312
313 self.pt_loop = asyncio.new_event_loop()
285 self.pt_app = PromptSession(
314 self.pt_app = PromptSession(
286 editing_mode=editing_mode,
315 editing_mode=editing_mode,
287 key_bindings=key_bindings,
316 key_bindings=key_bindings,
@@ -390,7 +419,7 b' class TerminalInteractiveShell(InteractiveShell):'
390 # work around this.
419 # work around this.
391 get_message = get_message()
420 get_message = get_message()
392
421
393 return {
422 options = {
394 'complete_in_thread': False,
423 'complete_in_thread': False,
395 'lexer':IPythonPTLexer(),
424 'lexer':IPythonPTLexer(),
396 'reserve_space_for_menu':self.space_for_menu,
425 'reserve_space_for_menu':self.space_for_menu,
@@ -407,8 +436,11 b' class TerminalInteractiveShell(InteractiveShell):'
407 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
436 processor=HighlightMatchingBracketProcessor(chars='[](){}'),
408 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
437 filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() &
409 Condition(lambda: self.highlight_matching_brackets))],
438 Condition(lambda: self.highlight_matching_brackets))],
410 'inputhook': self.inputhook,
411 }
439 }
440 if not PTK3:
441 options['inputhook'] = self.inputhook
442
443 return options
412
444
413 def prompt_for_code(self):
445 def prompt_for_code(self):
414 if self.rl_next_input:
446 if self.rl_next_input:
@@ -417,11 +449,28 b' class TerminalInteractiveShell(InteractiveShell):'
417 else:
449 else:
418 default = ''
450 default = ''
419
451
420 with patch_stdout(raw=True):
452 # In order to make sure that asyncio code written in the
421 text = self.pt_app.prompt(
453 # interactive shell doesn't interfere with the prompt, we run the
422 default=default,
454 # prompt in a different event loop.
423 # pre_run=self.pre_prompt,# reset_current_buffer=True,
455 # If we don't do this, people could spawn coroutine with a
424 **self._extra_prompt_options())
456 # while/true inside which will freeze the prompt.
457
458 try:
459 old_loop = asyncio.get_event_loop()
460 except RuntimeError:
461 # This happens when the user used `asyncio.run()`.
462 old_loop = None
463
464 asyncio.set_event_loop(self.pt_loop)
465 try:
466 with patch_stdout(raw=True):
467 text = self.pt_app.prompt(
468 default=default,
469 **self._extra_prompt_options())
470 finally:
471 # Restore the original event loop.
472 asyncio.set_event_loop(old_loop)
473
425 return text
474 return text
426
475
427 def enable_win_unicode_console(self):
476 def enable_win_unicode_console(self):
@@ -528,12 +577,33 b' class TerminalInteractiveShell(InteractiveShell):'
528
577
529 active_eventloop = None
578 active_eventloop = None
530 def enable_gui(self, gui=None):
579 def enable_gui(self, gui=None):
531 if gui:
580 if gui and (gui != 'inline') :
532 self.active_eventloop, self._inputhook =\
581 self.active_eventloop, self._inputhook =\
533 get_inputhook_name_and_func(gui)
582 get_inputhook_name_and_func(gui)
534 else:
583 else:
535 self.active_eventloop = self._inputhook = None
584 self.active_eventloop = self._inputhook = None
536
585
586 # For prompt_toolkit 3.0. We have to create an asyncio event loop with
587 # this inputhook.
588 if PTK3:
589 import asyncio
590 from prompt_toolkit.eventloop import new_eventloop_with_inputhook
591
592 if gui == 'asyncio':
593 # When we integrate the asyncio event loop, run the UI in the
594 # same event loop as the rest of the code. don't use an actual
595 # input hook. (Asyncio is not made for nesting event loops.)
596 self.pt_loop = asyncio.get_event_loop()
597
598 elif self._inputhook:
599 # If an inputhook was set, create a new asyncio event loop with
600 # this inputhook for the prompt.
601 self.pt_loop = new_eventloop_with_inputhook(self._inputhook)
602 else:
603 # When there's no inputhook, run the prompt in a separate
604 # asyncio event loop.
605 self.pt_loop = asyncio.new_event_loop()
606
537 # Run !system commands directly, not through pipes, so terminal programs
607 # Run !system commands directly, not through pipes, so terminal programs
538 # work correctly.
608 # work correctly.
539 system = InteractiveShell.system_raw
609 system = InteractiveShell.system_raw
@@ -89,3 +89,14 b' class RichPromptDisplayHook(DisplayHook):'
89 )
89 )
90 else:
90 else:
91 sys.stdout.write(prompt_txt)
91 sys.stdout.write(prompt_txt)
92
93 def write_format_data(self, format_dict, md_dict=None) -> None:
94 if self.shell.mime_renderers:
95
96 for mime, handler in self.shell.mime_renderers.items():
97 if mime in format_dict:
98 handler(format_dict[mime], None)
99 return
100
101 super().write_format_data(format_dict, md_dict)
102
@@ -13,6 +13,7 b' backends = ['
13 'wx',
13 'wx',
14 'pyglet', 'glut',
14 'pyglet', 'glut',
15 'osx',
15 'osx',
16 'asyncio'
16 ]
17 ]
17
18
18 registered = {}
19 registered = {}
@@ -44,6 +44,15 b' def create_ipython_shortcuts(shell):'
44 & insert_mode
44 & insert_mode
45 ))(return_handler)
45 ))(return_handler)
46
46
47 def reformat_and_execute(event):
48 reformat_text_before_cursor(event.current_buffer, event.current_buffer.document, shell)
49 event.current_buffer.validate_and_handle()
50
51 kb.add('escape', 'enter', filter=(has_focus(DEFAULT_BUFFER)
52 & ~has_selection
53 & insert_mode
54 ))(reformat_and_execute)
55
47 kb.add('c-\\')(force_exit)
56 kb.add('c-\\')(force_exit)
48
57
49 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
58 kb.add('c-p', filter=(vi_insert_mode & has_focus(DEFAULT_BUFFER))
@@ -86,7 +95,17 b' def create_ipython_shortcuts(shell):'
86 return kb
95 return kb
87
96
88
97
98 def reformat_text_before_cursor(buffer, document, shell):
99 text = buffer.delete_before_cursor(len(document.text[:document.cursor_position]))
100 try:
101 formatted_text = shell.reformat_handler(text)
102 buffer.insert_text(formatted_text)
103 except Exception as e:
104 buffer.insert_text(text)
105
106
89 def newline_or_execute_outer(shell):
107 def newline_or_execute_outer(shell):
108
90 def newline_or_execute(event):
109 def newline_or_execute(event):
91 """When the user presses return, insert a newline or execute the code."""
110 """When the user presses return, insert a newline or execute the code."""
92 b = event.current_buffer
111 b = event.current_buffer
@@ -107,7 +126,12 b' def newline_or_execute_outer(shell):'
107 else:
126 else:
108 check_text = d.text[:d.cursor_position]
127 check_text = d.text[:d.cursor_position]
109 status, indent = shell.check_complete(check_text)
128 status, indent = shell.check_complete(check_text)
110
129
130 # if all we have after the cursor is whitespace: reformat current text
131 # before cursor
132 after_cursor = d.text[d.cursor_position:]
133 if not after_cursor.strip():
134 reformat_text_before_cursor(b, d, shell)
111 if not (d.on_last_line or
135 if not (d.on_last_line or
112 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
136 d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
113 ):
137 ):
@@ -118,6 +142,7 b' def newline_or_execute_outer(shell):'
118 return
142 return
119
143
120 if (status != 'incomplete') and b.accept_handler:
144 if (status != 'incomplete') and b.accept_handler:
145 reformat_text_before_cursor(b, d, shell)
121 b.validate_and_handle()
146 b.validate_and_handle()
122 else:
147 else:
123 if shell.autoindent:
148 if shell.autoindent:
@@ -169,7 +169,7 b' class HomeDirError(Exception):'
169 pass
169 pass
170
170
171
171
172 def get_home_dir(require_writable=False):
172 def get_home_dir(require_writable=False) -> str:
173 """Return the 'home' directory, as a unicode string.
173 """Return the 'home' directory, as a unicode string.
174
174
175 Uses os.path.expanduser('~'), and checks for writability.
175 Uses os.path.expanduser('~'), and checks for writability.
@@ -197,21 +197,18 b' def get_home_dir(require_writable=False):'
197 if not _writable_dir(homedir) and os.name == 'nt':
197 if not _writable_dir(homedir) and os.name == 'nt':
198 # expanduser failed, use the registry to get the 'My Documents' folder.
198 # expanduser failed, use the registry to get the 'My Documents' folder.
199 try:
199 try:
200 try:
200 import winreg as wreg
201 import winreg as wreg # Py 3
201 with wreg.OpenKey(
202 except ImportError:
203 import _winreg as wreg # Py 2
204 key = wreg.OpenKey(
205 wreg.HKEY_CURRENT_USER,
202 wreg.HKEY_CURRENT_USER,
206 r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
203 r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
207 )
204 ) as key:
208 homedir = wreg.QueryValueEx(key,'Personal')[0]
205 homedir = wreg.QueryValueEx(key,'Personal')[0]
209 key.Close()
210 except:
206 except:
211 pass
207 pass
212
208
213 if (not require_writable) or _writable_dir(homedir):
209 if (not require_writable) or _writable_dir(homedir):
214 return py3compat.cast_unicode(homedir, fs_encoding)
210 assert isinstance(homedir, str), "Homedir shoudl be unicode not bytes"
211 return homedir
215 else:
212 else:
216 raise HomeDirError('%s is not a writable dir, '
213 raise HomeDirError('%s is not a writable dir, '
217 'set $HOME environment variable to override' % homedir)
214 'set $HOME environment variable to override' % homedir)
@@ -254,31 +251,31 b' def get_xdg_cache_dir():'
254
251
255 @undoc
252 @undoc
256 def get_ipython_dir():
253 def get_ipython_dir():
257 warn("get_ipython_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2)
254 warn("get_ipython_dir has moved to the IPython.paths module since IPython 4.0.", DeprecationWarning, stacklevel=2)
258 from IPython.paths import get_ipython_dir
255 from IPython.paths import get_ipython_dir
259 return get_ipython_dir()
256 return get_ipython_dir()
260
257
261 @undoc
258 @undoc
262 def get_ipython_cache_dir():
259 def get_ipython_cache_dir():
263 warn("get_ipython_cache_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2)
260 warn("get_ipython_cache_dir has moved to the IPython.paths module since IPython 4.0.", DeprecationWarning, stacklevel=2)
264 from IPython.paths import get_ipython_cache_dir
261 from IPython.paths import get_ipython_cache_dir
265 return get_ipython_cache_dir()
262 return get_ipython_cache_dir()
266
263
267 @undoc
264 @undoc
268 def get_ipython_package_dir():
265 def get_ipython_package_dir():
269 warn("get_ipython_package_dir has moved to the IPython.paths module since IPython 4.0.", stacklevel=2)
266 warn("get_ipython_package_dir has moved to the IPython.paths module since IPython 4.0.", DeprecationWarning, stacklevel=2)
270 from IPython.paths import get_ipython_package_dir
267 from IPython.paths import get_ipython_package_dir
271 return get_ipython_package_dir()
268 return get_ipython_package_dir()
272
269
273 @undoc
270 @undoc
274 def get_ipython_module_path(module_str):
271 def get_ipython_module_path(module_str):
275 warn("get_ipython_module_path has moved to the IPython.paths module since IPython 4.0.", stacklevel=2)
272 warn("get_ipython_module_path has moved to the IPython.paths module since IPython 4.0.", DeprecationWarning, stacklevel=2)
276 from IPython.paths import get_ipython_module_path
273 from IPython.paths import get_ipython_module_path
277 return get_ipython_module_path(module_str)
274 return get_ipython_module_path(module_str)
278
275
279 @undoc
276 @undoc
280 def locate_profile(profile='default'):
277 def locate_profile(profile='default'):
281 warn("locate_profile has moved to the IPython.paths module since IPython 4.0.", stacklevel=2)
278 warn("locate_profile has moved to the IPython.paths module since IPython 4.0.", DeprecationWarning, stacklevel=2)
282 from IPython.paths import locate_profile
279 from IPython.paths import locate_profile
283 return locate_profile(profile=profile)
280 return locate_profile(profile=profile)
284
281
@@ -171,8 +171,12 b' def test_get_home_dir_8():'
171 env.pop(key, None)
171 env.pop(key, None)
172
172
173 class key:
173 class key:
174 def __enter__(self):
175 pass
174 def Close(self):
176 def Close(self):
175 pass
177 pass
178 def __exit__(*args, **kwargs):
179 pass
176
180
177 with patch.object(wreg, 'OpenKey', return_value=key()), \
181 with patch.object(wreg, 'OpenKey', return_value=key()), \
178 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
182 patch.object(wreg, 'QueryValueEx', return_value=[abspath(HOME_TEST_DIR)]):
@@ -117,3 +117,15 b' version::'
117 ...
117 ...
118 install_requires=install_req
118 install_requires=install_req
119 )
119 )
120
121 Alternatives to IPython
122 =======================
123
124 IPython may not be to your taste; if that's the case there might be similar
125 project that you might want to use:
126
127 - the classic Python REPL.
128 - `bpython <https://bpython-interpreter.org/>`_
129 - `mypython <https://www.asmeurer.com/mypython/>`_
130 - `ptpython and ptipython <https://pypi.org/project/ptpython/>`
131 - `xonsh <https://xon.sh/>`
@@ -29,6 +29,7 b' Extending and integrating with IPython'
29 extensions/index
29 extensions/index
30 integrating
30 integrating
31 custommagics
31 custommagics
32 shell_mimerenderer
32 inputtransforms
33 inputtransforms
33 callbacks
34 callbacks
34 eventloops
35 eventloops
@@ -1,13 +1,14 b''
1 .. _execution_semantics:
1 .. _execution_semantics:
2
2
3 Execution semantics in the IPython kernel
3 Execution of cells in the IPython kernel
4 =========================================
4 ========================================
5
5
6 The execution of user code consists of the following phases:
6 When IPython kernel receives `execute_request <https://jupyter-client.readthedocs.io/en/latest/messaging.html#execute>`_
7 with user code, it processes the message in the following phases:
7
8
8 1. Fire the ``pre_execute`` event.
9 1. Fire the ``pre_execute`` event.
9 2. Fire the ``pre_run_cell`` event unless silent is ``True``.
10 2. Fire the ``pre_run_cell`` event unless silent is ``True``.
10 3. Execute the ``code`` field, see below for details.
11 3. Execute ``run_cell`` method to preprocess ``code``, compile and run it, see below for details.
11 4. If execution succeeds, expressions in ``user_expressions`` are computed.
12 4. If execution succeeds, expressions in ``user_expressions`` are computed.
12 This ensures that any error in the expressions don't affect the main code execution.
13 This ensures that any error in the expressions don't affect the main code execution.
13 5. Fire the ``post_execute`` event.
14 5. Fire the ``post_execute`` event.
@@ -18,9 +19,15 b' The execution of user code consists of the following phases:'
18 :doc:`/config/callbacks`
19 :doc:`/config/callbacks`
19
20
20
21
21 To understand how the ``code`` field is executed, one must know that Python
22 Running user ``code``
22 code can be compiled in one of three modes (controlled by the ``mode`` argument
23 =====================
23 to the :func:`compile` builtin):
24
25 First, the ``code`` cell is transformed to expand ``%magic`` and ``!system``
26 commands by ``IPython.core.inputtransformer2``. Then expanded cell is compiled
27 using standard Python :func:`compile` function and executed.
28
29 Python :func:`compile` function provides ``mode`` argument to select one
30 of three ways of compiling code:
24
31
25 *single*
32 *single*
26 Valid for a single interactive statement (though the source can contain
33 Valid for a single interactive statement (though the source can contain
@@ -50,16 +57,16 b" execution in 'single' mode, and then:"
50
57
51 - If there is more than one block:
58 - If there is more than one block:
52
59
53 * if the last one is a single line long, run all but the last in 'exec' mode
60 * if the last block is a single line long, run all but the last in 'exec' mode
54 and the very last one in 'single' mode. This makes it easy to type simple
61 and the very last one in 'single' mode. This makes it easy to type simple
55 expressions at the end to see computed values.
62 expressions at the end to see computed values.
56
63
57 * if the last one is no more than two lines long, run all but the last in
64 * if the last block is no more than two lines long, run all but the last in
58 'exec' mode and the very last one in 'single' mode. This makes it easy to
65 'exec' mode and the very last one in 'single' mode. This makes it easy to
59 type simple expressions at the end to see computed values. - otherwise
66 type simple expressions at the end to see computed values. - otherwise
60 (last one is also multiline), run all in 'exec' mode
67 (last one is also multiline), run all in 'exec' mode
61
68
62 * otherwise (last one is also multiline), run all in 'exec' mode as a single
69 * otherwise (last block is also multiline), run all in 'exec' mode as a single
63 unit.
70 unit.
64
71
65
72
@@ -11,7 +11,7 b' This document describes in-flight development work.'
11 `docs/source/whatsnew/pr` folder
11 `docs/source/whatsnew/pr` folder
12
12
13
13
14 Released .... ...., 2017
14 Released .... ...., 2019
15
15
16
16
17 Need to be updated:
17 Need to be updated:
@@ -22,8 +22,6 b' Need to be updated:'
22
22
23 pr/*
23 pr/*
24
24
25
26
27 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
25 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
28
26
29
27
@@ -1,6 +1,48 b''
1 Issues closed in the 7.x development cycle
1 Issues closed in the 7.x development cycle
2 ==========================================
2 ==========================================
3
3
4 Issues closed in 7.10.1
5 -----------------------
6
7 GitHub stats for 2019/11/27 - 2019/12/01 (tag: 7.10.0)
8
9 These lists are automatically generated, and may be incomplete or contain duplicates.
10
11 We closed 5 issues and merged 7 pull requests.
12 The full list can be seen `on GitHub <https://github.com/ipython/ipython/issues?q=milestone%3A7.10.1>`__
13
14 The following 2 authors contributed 14 commits.
15
16 * Jonathan Slenders
17 * Matthias Bussonnier
18
19 Issues closed in 7.10
20 ---------------------
21
22 GitHub stats for 2019/10/25 - 2019/11/27 (tag: 7.9.0)
23
24 These lists are automatically generated, and may be incomplete or contain duplicates.
25
26 We closed 4 issues and merged 22 pull requests.
27 The full list can be seen `on GitHub <https://github.com/ipython/ipython/issues?q=milestone%3A7.10>`__
28
29 The following 15 authors contributed 101 commits.
30
31 * anatoly techtonik
32 * Ben Lewis
33 * Benjamin Ragan-Kelley
34 * Gerrit Buss
35 * grey275
36 * Gökcen Eraslan
37 * Jonathan Slenders
38 * Joris Van den Bossche
39 * kousik
40 * Matthias Bussonnier
41 * Nicholas Bollweg
42 * Paul McCarthy
43 * Srinivas Reddy Thatiparthy
44 * Timo Kaufmann
45 * Tony Fast
4
46
5 Issues closed in 7.9
47 Issues closed in 7.9
6 --------------------
48 --------------------
@@ -2,8 +2,156 b''
2 7.x Series
2 7.x Series
3 ============
3 ============
4
4
5 .. _version 7101:
6
7 IPython 7.10.1
8 ==============
9
10 IPython 7.10.1 fix a couple of incompatibilities with Prompt toolkit 3 (please
11 update Prompt toolkit to 3.0.2 at least), and fixes some interaction with
12 headless IPython.
13
14 .. _version 7100:
15
16 IPython 7.10.0
17 ==============
18
19 IPython 7.10 is the first double digit minor release in the last decade, and
20 first since the release of IPython 1.0, previous double digit minor release was
21 in August 2009.
22
23 We've been trying to give you regular release on the last Friday of every month
24 for a guaranty of rapid access to bug fixes and new features.
25
26 Unlike the previous first few releases that have seen only a couple of code
27 changes, 7.10 bring a number of changes, new features and bugfixes.
28
29 Stop Support for Python 3.5 – Adopt NEP 29
30 ------------------------------------------
31
32 IPython has decided to follow the informational `NEP 29
33 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`_ which layout a clear
34 policy as to which version of (C)Python and NumPy are supported.
35
36 We thus dropped support for Python 3.5, and cleaned up a number of code path
37 that were Python-version dependant. If you are on 3.5 or earlier pip should
38 automatically give you the latest compatible version of IPython so you do not
39 need to pin to a given version.
40
41 Support for Prompt Toolkit 3.0
42 ------------------------------
43
44 Prompt Toolkit 3.0 was release a week before IPython 7.10 and introduces a few
45 breaking changes. We believe IPython 7.10 should be compatible with both Prompt
46 Toolkit 2.x and 3.x, though it has not been extensively tested with 3.x so
47 please report any issues.
48
49
50 Prompt Rendering Performance improvements
51 -----------------------------------------
52
53 Pull Request :ghpull:`11933` introduced an optimisation in the prompt rendering
54 logic that should decrease the resource usage of IPython when using the
55 _default_ configuration but could potentially introduce a regression of
56 functionalities if you are using a custom prompt.
57
58 We know assume if you haven't changed the default keybindings that the prompt
59 **will not change** during the duration of your input – which is for example
60 not true when using vi insert mode that switches between `[ins]` and `[nor]`
61 for the current mode.
62
63 If you are experiencing any issue let us know.
64
65 Code autoformatting
66 -------------------
67
68 The IPython terminal can now auto format your code just before entering a new
69 line or executing a command. To do so use the
70 ``--TerminalInteractiveShell.autoformatter`` option and set it to ``'black'``;
71 if black is installed IPython will use black to format your code when possible.
72
73 IPython cannot always properly format your code; in particular it will
74 auto formatting with *black* will only work if:
75
76 - Your code does not contains magics or special python syntax.
77
78 - There is no code after your cursor.
79
80 The Black API is also still in motion; so this may not work with all versions of
81 black.
82
83 It should be possible to register custom formatter, though the API is till in
84 flux.
85
86 Arbitrary Mimetypes Handing in Terminal (Aka inline images in terminal)
87 -----------------------------------------------------------------------
88
89 When using IPython terminal it is now possible to register function to handle
90 arbitrary mimetypes. While rendering non-text based representation was possible in
91 many jupyter frontend; it was not possible in terminal IPython, as usually
92 terminal are limited to displaying text. As many terminal these days provide
93 escape sequences to display non-text; bringing this loved feature to IPython CLI
94 made a lot of sens. This functionality will not only allow inline images; but
95 allow opening of external program; for example ``mplayer`` to "display" sound
96 files.
97
98 So far only the hooks necessary for this are in place, but no default mime
99 renderers added; so inline images will only be available via extensions. We will
100 progressively enable these features by default in the next few releases, and
101 contribution is welcomed.
102
103 We welcome any feedback on the API. See :ref:`shell_mimerenderer` for more
104 informations.
105
106 This is originally based on work form in :ghpull:`10610` from @stephanh42
107 started over two years ago, and still a lot need to be done.
108
109 MISC
110 ----
111
112 - Completions can define their own ordering :ghpull:`11855`
113 - Enable Plotting in the same cell than the one that import matplotlib
114 :ghpull:`11916`
115 - Allow to store and restore multiple variables at once :ghpull:`11930`
116
117 You can see `all pull-requests <https://github.com/ipython/ipython/pulls?q=is%3Apr+milestone%3A7.10+is%3Aclosed>`_ for this release.
118
119 API Changes
120 -----------
121
122 Change of API and exposed objects automatically detected using `frappuccino <https://pypi.org/project/frappuccino/>`_ (still in beta):
123
124 The following items are new in IPython 7.10::
125
126 + IPython.terminal.shortcuts.reformat_text_before_cursor(buffer, document, shell)
127 + IPython.terminal.interactiveshell.PTK3
128 + IPython.terminal.interactiveshell.black_reformat_handler(text_before_cursor)
129 + IPython.terminal.prompts.RichPromptDisplayHook.write_format_data(self, format_dict, md_dict='None')
130
131 The following items have been removed in 7.10::
132
133 - IPython.lib.pretty.DICT_IS_ORDERED
134
135 The following signatures differ between versions::
136
137 - IPython.extensions.storemagic.restore_aliases(ip)
138 + IPython.extensions.storemagic.restore_aliases(ip, alias='None')
139
140 Special Thanks
141 --------------
142
143 - @stephanh42 who started the work on inline images in terminal 2 years ago
144 - @augustogoulart who spent a lot of time triaging issues and responding to
145 users.
146 - @con-f-use who is my (@Carreau) first sponsor on GitHub, as a reminder if you
147 like IPython, Jupyter and many other library of the SciPy stack you can
148 donate to numfocus.org non profit
149
5 .. _version 790:
150 .. _version 790:
6
151
152 IPython 7.9.0
153 =============
154
7 IPython 7.9 is a small release with a couple of improvement and bug fixes.
155 IPython 7.9 is a small release with a couple of improvement and bug fixes.
8
156
9 - Xterm terminal title should be restored on exit :ghpull:`11910`
157 - Xterm terminal title should be restored on exit :ghpull:`11910`
@@ -13,12 +161,12 b' IPython 7.9 is a small release with a couple of improvement and bug fixes.'
13 find all objects needing reload. This should avoid large objects traversal
161 find all objects needing reload. This should avoid large objects traversal
14 like pandas dataframes. :ghpull:`11876`
162 like pandas dataframes. :ghpull:`11876`
15 - Get ready for Python 4. :ghpull:`11874`
163 - Get ready for Python 4. :ghpull:`11874`
16 - `%env` Magic nonw has euristic to hide potentially sensitive values :ghpull:`11896`
164 - `%env` Magic now has heuristic to hide potentially sensitive values :ghpull:`11896`
17
165
18 This is a small release despite a number of Pull Request Pending that need to
166 This is a small release despite a number of Pull Request Pending that need to
19 be reviewed/worked on. Many of the core developers have been busy outside of
167 be reviewed/worked on. Many of the core developers have been busy outside of
20 IPython/Jupyter and we thanks all contributor for their patience; we'll work on
168 IPython/Jupyter and we thanks all contributor for their patience; we'll work on
21 these as soon as we have time.
169 these as soon as we have time.
22
170
23
171
24 .. _version780:
172 .. _version780:
@@ -190,7 +190,7 b' install_requires = ['
190 'decorator',
190 'decorator',
191 'pickleshare',
191 'pickleshare',
192 'traitlets>=4.2',
192 'traitlets>=4.2',
193 'prompt_toolkit>=2.0.0,<2.1.0',
193 'prompt_toolkit>=2.0.0,<3.1.0,!=3.0.0,!=3.0.1',
194 'pygments',
194 'pygments',
195 'backcall',
195 'backcall',
196 ]
196 ]
@@ -1,5 +1,5 b''
1 # Simple tool to help for release
1 # Simple tool to help for release
2 # when releasing with bash, simplei source it to get asked questions.
2 # when releasing with bash, simple source it to get asked questions.
3
3
4 # misc check before starting
4 # misc check before starting
5
5
@@ -9,14 +9,6 b" python -c 'import sphinx'"
9 python -c 'import sphinx_rtd_theme'
9 python -c 'import sphinx_rtd_theme'
10 python -c 'import nose'
10 python -c 'import nose'
11
11
12 echo -n 'PREV_RELEASE (X.y.z):'
13 read PREV_RELEASE
14 echo -n 'MILESTONE (X.y):'
15 read MILESTONE
16 echo -n 'VERSION (X.y.z):'
17 read VERSION
18 echo -n 'branch (master|X.y):'
19 read branch
20
12
21 BLACK=$(tput setaf 1)
13 BLACK=$(tput setaf 1)
22 RED=$(tput setaf 1)
14 RED=$(tput setaf 1)
@@ -28,30 +20,66 b' CYAN=$(tput setaf 6)'
28 WHITE=$(tput setaf 7)
20 WHITE=$(tput setaf 7)
29 NOR=$(tput sgr0)
21 NOR=$(tput sgr0)
30
22
31 echo
32 echo $BLUE"Updating what's new with informations from docs/source/whatsnew/pr"$NOR
33 python tools/update_whatsnew.py
34
23
35 echo
24 echo -n "PREV_RELEASE (X.y.z) [$PREV_RELEASE]: "
36 echo $BLUE"please move the contents of "docs/source/whatsnew/development.rst" to version-X.rst"$NOR
25 read input
37 echo $GREEN"Press enter to continue"$NOR
26 PREV_RELEASE=${input:-$PREV_RELEASE}
38 read
27 echo -n "MILESTONE (X.y) [$MILESTONE]: "
28 read input
29 MILESTONE=${input:-$MILESTONE}
30 echo -n "VERSION (X.y.z) [$VERSION]:"
31 read input
32 VERSION=${input:-$VERSION}
33 echo -n "BRANCH (master|X.y) [$BRANCH]:"
34 read input
35 BRANCH=${input:-$BRANCH}
36
37 ask_section(){
38 echo
39 echo $BLUE"$1"$NOR
40 echo -n $GREEN"Press Enter to continue, S to skip: "$GREEN
41 read -n1 value
42 echo
43 if [ -z $value ] || [ $value = 'y' ] ; then
44 return 0
45 fi
46 return 1
47 }
48
39
49
40 echo
41 echo $BLUE"here are all the authors that contributed to this release:"$NOR
42 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
43
50
44 echo
51 echo
45 echo $BLUE"If you see any duplicates cancel (Ctrl-C), then edit .mailmap."$GREEN"Press enter to continue:"$NOR
52 if ask_section "Updating what's new with informations from docs/source/whatsnew/pr"
46 read
53 then
54 python tools/update_whatsnew.py
47
55
48 echo $BLUE"generating stats"$NOR
56 echo
49 python tools/github_stats.py --milestone $MILESTONE > stats.rst
57 echo $BLUE"please move the contents of "docs/source/whatsnew/development.rst" to version-X.rst"$NOR
58 echo $GREEN"Press enter to continue"$NOR
59 read
60 fi
50
61
51 echo $BLUE"stats.rst files generated."$NOR
62 if ask_section "Gen Stats, and authors"
52 echo $GREEN"Please merge it with the right file (github-stats-X.rst) and commit."$NOR
63 then
53 echo $GREEN"press enter to continue."$NOR
64
54 read
65 echo
66 echo $BLUE"here are all the authors that contributed to this release:"$NOR
67 git log --format="%aN <%aE>" $PREV_RELEASE... | sort -u -f
68
69 echo
70 echo $BLUE"If you see any duplicates cancel (Ctrl-C), then edit .mailmap."
71 echo $GREEN"Press enter to continue:"$NOR
72 read
73
74 echo $BLUE"generating stats"$NOR
75 python tools/github_stats.py --milestone $MILESTONE > stats.rst
76
77 echo $BLUE"stats.rst files generated."$NOR
78 echo $GREEN"Please merge it with the right file (github-stats-X.rst) and commit."$NOR
79 echo $GREEN"press enter to continue."$NOR
80 read
81
82 fi
55
83
56 echo "Cleaning repository"
84 echo "Cleaning repository"
57 git clean -xfdi
85 git clean -xfdi
@@ -61,30 +89,81 b' echo $GREEN"please update version number in ${RED}IPython/core/release.py${NOR} '
61 echo $GREEN"Press enter to continue"$NOR
89 echo $GREEN"Press enter to continue"$NOR
62 read
90 read
63
91
64 echo
92 if ask_section "Build the documentation ?"
65 echo "Attempting to build the docs.."
93 then
66 make html -C docs
94 make html -C docs
95 echo
96 echo $GREEN"Check the docs, press enter to continue"$NOR
97 read
67
98
68 echo
99 fi
69 echo $GREEN"Check the docs, press enter to continue"$NOR
70 read
71
100
72 echo
101 echo
73 echo $BLUE"Attempting to build package..."$NOR
102 echo $BLUE"Attempting to build package..."$NOR
74
103
75 tools/build_release
104 tools/build_release
76
105 rm dist/*
77 echo
106
78 echo "Let\'s commit : git commit -am \"release $VERSION\" -S"
107 if ask_section "Should we commit, tag, push... etc ? "
79 echo $GREEN"Press enter to continue"$NOR
108 then
80 read
109 echo
81 git commit -am "release $VERSION" -S
110 echo "Let's commit : git commit -am \"release $VERSION\" -S"
82
111 echo $GREEN"Press enter to commit"$NOR
83 echo
112 read
84 echo "git push origin \$BRANCH ?"
113 git commit -am "release $VERSION" -S
85 echo "Press enter to continue"
114
86 read
115 echo
87 git push origin $BRANCH
116 echo $BLUE"git push origin \$BRANCH ($BRANCH)?"$NOR
88 # git tag -am "release $VERSION" "$VERSION" -s
117 echo $GREEN"Make sure you can push"$NOR
89 # git push origin $VERSION
118 echo $GREEN"Press enter to continue"$NOR
90
119 read
120 git push origin $BRANCH
121
122 echo
123 echo "Let's tag : git tag -am \"release $VERSION\" \"$VERSION\" -s"
124 echo $GREEN"Press enter to tag commit"$NOR
125 read
126 git tag -am "release $VERSION" "$VERSION" -s
127
128 echo
129 echo $BLUE"And push the tag: git push origin \$VERSION ?"$NOR
130 echo $GREEN"Press enter to continue"$NOR
131 read
132 git push origin $VERSION
133
134
135 echo $GREEN"please update version number and back to .dev in ${RED}IPython/core/release.py"
136 echo ${BLUE}"Do not commit yet – we'll do it later."$NOR
137
138 echo $GREEN"Press enter to continue"$NOR
139 read
140
141 echo
142 echo "Let's commit : git commit -am \"back to dev\" -S"
143 echo $GREEN"Press enter to commit"$NOR
144 read
145 git commit -am "back to dev" -S
146
147 echo
148 echo $BLUE"let's : git checkout $VERSION"$NOR
149 echo $GREEN"Press enter to continue"$NOR
150 read
151 git checkout $VERSION
152 fi
153
154 if ask_section "Should we build and release ?"
155 then
156
157 echo
158 echo $BLUE"Attempting to build package..."$NOR
159
160 tools/build_release
161
162 echo '$ shasum -a 256 dist/*'
163 shasum -a 256 dist/*
164
165 if ask_section "upload packages ?"
166 then
167 tools/build_release upload
168 fi
169 fi
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now