Show More
@@ -1,393 +1,392 b'' | |||||
1 | # encoding: utf-8 |
|
1 | # encoding: utf-8 | |
2 | """ |
|
2 | """ | |
3 | An embedded IPython shell. |
|
3 | An embedded IPython shell. | |
4 | """ |
|
4 | """ | |
5 | # Copyright (c) IPython Development Team. |
|
5 | # Copyright (c) IPython Development Team. | |
6 | # Distributed under the terms of the Modified BSD License. |
|
6 | # Distributed under the terms of the Modified BSD License. | |
7 |
|
7 | |||
8 |
|
8 | |||
9 | import sys |
|
9 | import sys | |
10 | import warnings |
|
10 | import warnings | |
11 |
|
11 | |||
12 | from IPython.core import ultratb, compilerop |
|
12 | from IPython.core import ultratb, compilerop | |
13 | from IPython.core import magic_arguments |
|
13 | from IPython.core import magic_arguments | |
14 | from IPython.core.magic import Magics, magics_class, line_magic |
|
14 | from IPython.core.magic import Magics, magics_class, line_magic | |
15 | from IPython.core.interactiveshell import DummyMod, InteractiveShell |
|
15 | from IPython.core.interactiveshell import DummyMod, InteractiveShell | |
16 | from IPython.terminal.interactiveshell import TerminalInteractiveShell |
|
16 | from IPython.terminal.interactiveshell import TerminalInteractiveShell | |
17 | from IPython.terminal.ipapp import load_default_config |
|
17 | from IPython.terminal.ipapp import load_default_config | |
18 |
|
18 | |||
19 | from traitlets import Bool, CBool, Unicode |
|
19 | from traitlets import Bool, CBool, Unicode | |
20 | from IPython.utils.io import ask_yes_no |
|
20 | from IPython.utils.io import ask_yes_no | |
21 |
|
21 | |||
22 | class KillEmbeded(Exception):pass |
|
22 | class KillEmbeded(Exception):pass | |
23 |
|
23 | |||
24 | # This is an additional magic that is exposed in embedded shells. |
|
24 | # This is an additional magic that is exposed in embedded shells. | |
25 | @magics_class |
|
25 | @magics_class | |
26 | class EmbeddedMagics(Magics): |
|
26 | class EmbeddedMagics(Magics): | |
27 |
|
27 | |||
28 | @line_magic |
|
28 | @line_magic | |
29 | @magic_arguments.magic_arguments() |
|
29 | @magic_arguments.magic_arguments() | |
30 | @magic_arguments.argument('-i', '--instance', action='store_true', |
|
30 | @magic_arguments.argument('-i', '--instance', action='store_true', | |
31 | help='Kill instance instead of call location') |
|
31 | help='Kill instance instead of call location') | |
32 | @magic_arguments.argument('-x', '--exit', action='store_true', |
|
32 | @magic_arguments.argument('-x', '--exit', action='store_true', | |
33 | help='Also exit the current session') |
|
33 | help='Also exit the current session') | |
34 | @magic_arguments.argument('-y', '--yes', action='store_true', |
|
34 | @magic_arguments.argument('-y', '--yes', action='store_true', | |
35 | help='Do not ask confirmation') |
|
35 | help='Do not ask confirmation') | |
36 | def kill_embedded(self, parameter_s=''): |
|
36 | def kill_embedded(self, parameter_s=''): | |
37 | """%kill_embedded : deactivate for good the current embedded IPython |
|
37 | """%kill_embedded : deactivate for good the current embedded IPython | |
38 |
|
38 | |||
39 | This function (after asking for confirmation) sets an internal flag so |
|
39 | This function (after asking for confirmation) sets an internal flag so | |
40 | that an embedded IPython will never activate again for the given call |
|
40 | that an embedded IPython will never activate again for the given call | |
41 | location. This is useful to permanently disable a shell that is being |
|
41 | location. This is useful to permanently disable a shell that is being | |
42 | called inside a loop: once you've figured out what you needed from it, |
|
42 | called inside a loop: once you've figured out what you needed from it, | |
43 | you may then kill it and the program will then continue to run without |
|
43 | you may then kill it and the program will then continue to run without | |
44 | the interactive shell interfering again. |
|
44 | the interactive shell interfering again. | |
45 |
|
45 | |||
46 |
|
46 | |||
47 | Kill Instance Option |
|
47 | Kill Instance Option: | |
48 | -------------------- |
|
48 | ||
49 |
|
49 | If for some reasons you need to kill the location where the instance | ||
50 | If for some reasons you need to kill the location where the instance is |
|
50 | is created and not called, for example if you create a single | |
51 | created and not called, for example if you create a single instance in |
|
51 | instance in one place and debug in many locations, you can use the | |
52 | one place and debug in many locations, you can use the ``--instance`` |
|
52 | ``--instance`` option to kill this specific instance. Like for the | |
53 | option to kill this specific instance. Like for the ``call location`` |
|
53 | ``call location`` killing an "instance" should work even if it is | |
54 | killing an "instance" should work even if it is recreated within a |
|
54 | recreated within a loop. | |
55 | loop. |
|
|||
56 |
|
55 | |||
57 | .. note:: |
|
56 | .. note:: | |
58 |
|
57 | |||
59 | This was the default behavior before IPython 5.2 |
|
58 | This was the default behavior before IPython 5.2 | |
60 |
|
59 | |||
61 | """ |
|
60 | """ | |
62 |
|
61 | |||
63 | args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s) |
|
62 | args = magic_arguments.parse_argstring(self.kill_embedded, parameter_s) | |
64 | print(args) |
|
63 | print(args) | |
65 | if args.instance: |
|
64 | if args.instance: | |
66 | # let no ask |
|
65 | # let no ask | |
67 | if not args.yes: |
|
66 | if not args.yes: | |
68 | kill = ask_yes_no( |
|
67 | kill = ask_yes_no( | |
69 | "Are you sure you want to kill this embedded instance? [y/N] ", 'n') |
|
68 | "Are you sure you want to kill this embedded instance? [y/N] ", 'n') | |
70 | else: |
|
69 | else: | |
71 | kill = True |
|
70 | kill = True | |
72 | if kill: |
|
71 | if kill: | |
73 | self.shell._disable_init_location() |
|
72 | self.shell._disable_init_location() | |
74 | print("This embedded IPython instance will not reactivate anymore " |
|
73 | print("This embedded IPython instance will not reactivate anymore " | |
75 | "once you exit.") |
|
74 | "once you exit.") | |
76 | else: |
|
75 | else: | |
77 | if not args.yes: |
|
76 | if not args.yes: | |
78 | kill = ask_yes_no( |
|
77 | kill = ask_yes_no( | |
79 | "Are you sure you want to kill this embedded call_location? [y/N] ", 'n') |
|
78 | "Are you sure you want to kill this embedded call_location? [y/N] ", 'n') | |
80 | else: |
|
79 | else: | |
81 | kill = True |
|
80 | kill = True | |
82 | if kill: |
|
81 | if kill: | |
83 | self.shell.embedded_active = False |
|
82 | self.shell.embedded_active = False | |
84 | print("This embedded IPython call location will not reactivate anymore " |
|
83 | print("This embedded IPython call location will not reactivate anymore " | |
85 | "once you exit.") |
|
84 | "once you exit.") | |
86 |
|
85 | |||
87 | if args.exit: |
|
86 | if args.exit: | |
88 | # Ask-exit does not really ask, it just set internals flags to exit |
|
87 | # Ask-exit does not really ask, it just set internals flags to exit | |
89 | # on next loop. |
|
88 | # on next loop. | |
90 | self.shell.ask_exit() |
|
89 | self.shell.ask_exit() | |
91 |
|
90 | |||
92 |
|
91 | |||
93 | @line_magic |
|
92 | @line_magic | |
94 | def exit_raise(self, parameter_s=''): |
|
93 | def exit_raise(self, parameter_s=''): | |
95 | """%exit_raise Make the current embedded kernel exit and raise and exception. |
|
94 | """%exit_raise Make the current embedded kernel exit and raise and exception. | |
96 |
|
95 | |||
97 | This function sets an internal flag so that an embedded IPython will |
|
96 | This function sets an internal flag so that an embedded IPython will | |
98 | raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is |
|
97 | raise a `IPython.terminal.embed.KillEmbeded` Exception on exit, and then exit the current I. This is | |
99 | useful to permanently exit a loop that create IPython embed instance. |
|
98 | useful to permanently exit a loop that create IPython embed instance. | |
100 | """ |
|
99 | """ | |
101 |
|
100 | |||
102 | self.shell.should_raise = True |
|
101 | self.shell.should_raise = True | |
103 | self.shell.ask_exit() |
|
102 | self.shell.ask_exit() | |
104 |
|
103 | |||
105 |
|
104 | |||
106 |
|
105 | |||
107 | class InteractiveShellEmbed(TerminalInteractiveShell): |
|
106 | class InteractiveShellEmbed(TerminalInteractiveShell): | |
108 |
|
107 | |||
109 | dummy_mode = Bool(False) |
|
108 | dummy_mode = Bool(False) | |
110 | exit_msg = Unicode('') |
|
109 | exit_msg = Unicode('') | |
111 | embedded = CBool(True) |
|
110 | embedded = CBool(True) | |
112 | should_raise = CBool(False) |
|
111 | should_raise = CBool(False) | |
113 | # Like the base class display_banner is not configurable, but here it |
|
112 | # Like the base class display_banner is not configurable, but here it | |
114 | # is True by default. |
|
113 | # is True by default. | |
115 | display_banner = CBool(True) |
|
114 | display_banner = CBool(True) | |
116 | exit_msg = Unicode() |
|
115 | exit_msg = Unicode() | |
117 |
|
116 | |||
118 | # When embedding, by default we don't change the terminal title |
|
117 | # When embedding, by default we don't change the terminal title | |
119 | term_title = Bool(False, |
|
118 | term_title = Bool(False, | |
120 | help="Automatically set the terminal title" |
|
119 | help="Automatically set the terminal title" | |
121 | ).tag(config=True) |
|
120 | ).tag(config=True) | |
122 |
|
121 | |||
123 | _inactive_locations = set() |
|
122 | _inactive_locations = set() | |
124 |
|
123 | |||
125 | @property |
|
124 | @property | |
126 | def embedded_active(self): |
|
125 | def embedded_active(self): | |
127 | return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\ |
|
126 | return (self._call_location_id not in InteractiveShellEmbed._inactive_locations)\ | |
128 | and (self._init_location_id not in InteractiveShellEmbed._inactive_locations) |
|
127 | and (self._init_location_id not in InteractiveShellEmbed._inactive_locations) | |
129 |
|
128 | |||
130 | def _disable_init_location(self): |
|
129 | def _disable_init_location(self): | |
131 | """Disable the current Instance creation location""" |
|
130 | """Disable the current Instance creation location""" | |
132 | InteractiveShellEmbed._inactive_locations.add(self._init_location_id) |
|
131 | InteractiveShellEmbed._inactive_locations.add(self._init_location_id) | |
133 |
|
132 | |||
134 | @embedded_active.setter |
|
133 | @embedded_active.setter | |
135 | def embedded_active(self, value): |
|
134 | def embedded_active(self, value): | |
136 | if value: |
|
135 | if value: | |
137 | InteractiveShellEmbed._inactive_locations.discard( |
|
136 | InteractiveShellEmbed._inactive_locations.discard( | |
138 | self._call_location_id) |
|
137 | self._call_location_id) | |
139 | InteractiveShellEmbed._inactive_locations.discard( |
|
138 | InteractiveShellEmbed._inactive_locations.discard( | |
140 | self._init_location_id) |
|
139 | self._init_location_id) | |
141 | else: |
|
140 | else: | |
142 | InteractiveShellEmbed._inactive_locations.add( |
|
141 | InteractiveShellEmbed._inactive_locations.add( | |
143 | self._call_location_id) |
|
142 | self._call_location_id) | |
144 |
|
143 | |||
145 | def __init__(self, **kw): |
|
144 | def __init__(self, **kw): | |
146 | if kw.get('user_global_ns', None) is not None: |
|
145 | if kw.get('user_global_ns', None) is not None: | |
147 | raise DeprecationWarning( |
|
146 | raise DeprecationWarning( | |
148 | "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") |
|
147 | "Key word argument `user_global_ns` has been replaced by `user_module` since IPython 4.0.") | |
149 |
|
148 | |||
150 | clid = kw.pop('_init_location_id', None) |
|
149 | clid = kw.pop('_init_location_id', None) | |
151 | if not clid: |
|
150 | if not clid: | |
152 | frame = sys._getframe(1) |
|
151 | frame = sys._getframe(1) | |
153 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) |
|
152 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) | |
154 | self._init_location_id = clid |
|
153 | self._init_location_id = clid | |
155 |
|
154 | |||
156 | super(InteractiveShellEmbed,self).__init__(**kw) |
|
155 | super(InteractiveShellEmbed,self).__init__(**kw) | |
157 |
|
156 | |||
158 | # don't use the ipython crash handler so that user exceptions aren't |
|
157 | # don't use the ipython crash handler so that user exceptions aren't | |
159 | # trapped |
|
158 | # trapped | |
160 | sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, |
|
159 | sys.excepthook = ultratb.FormattedTB(color_scheme=self.colors, | |
161 | mode=self.xmode, |
|
160 | mode=self.xmode, | |
162 | call_pdb=self.pdb) |
|
161 | call_pdb=self.pdb) | |
163 |
|
162 | |||
164 | def init_sys_modules(self): |
|
163 | def init_sys_modules(self): | |
165 | """ |
|
164 | """ | |
166 | Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing. |
|
165 | Explicitly overwrite :mod:`IPython.core.interactiveshell` to do nothing. | |
167 | """ |
|
166 | """ | |
168 | pass |
|
167 | pass | |
169 |
|
168 | |||
170 | def init_magics(self): |
|
169 | def init_magics(self): | |
171 | super(InteractiveShellEmbed, self).init_magics() |
|
170 | super(InteractiveShellEmbed, self).init_magics() | |
172 | self.register_magics(EmbeddedMagics) |
|
171 | self.register_magics(EmbeddedMagics) | |
173 |
|
172 | |||
174 | def __call__(self, header='', local_ns=None, module=None, dummy=None, |
|
173 | def __call__(self, header='', local_ns=None, module=None, dummy=None, | |
175 | stack_depth=1, global_ns=None, compile_flags=None, **kw): |
|
174 | stack_depth=1, global_ns=None, compile_flags=None, **kw): | |
176 | """Activate the interactive interpreter. |
|
175 | """Activate the interactive interpreter. | |
177 |
|
176 | |||
178 | __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start |
|
177 | __call__(self,header='',local_ns=None,module=None,dummy=None) -> Start | |
179 | the interpreter shell with the given local and global namespaces, and |
|
178 | the interpreter shell with the given local and global namespaces, and | |
180 | optionally print a header string at startup. |
|
179 | optionally print a header string at startup. | |
181 |
|
180 | |||
182 | The shell can be globally activated/deactivated using the |
|
181 | The shell can be globally activated/deactivated using the | |
183 | dummy_mode attribute. This allows you to turn off a shell used |
|
182 | dummy_mode attribute. This allows you to turn off a shell used | |
184 | for debugging globally. |
|
183 | for debugging globally. | |
185 |
|
184 | |||
186 | However, *each* time you call the shell you can override the current |
|
185 | However, *each* time you call the shell you can override the current | |
187 | state of dummy_mode with the optional keyword parameter 'dummy'. For |
|
186 | state of dummy_mode with the optional keyword parameter 'dummy'. For | |
188 | example, if you set dummy mode on with IPShell.dummy_mode = True, you |
|
187 | example, if you set dummy mode on with IPShell.dummy_mode = True, you | |
189 | can still have a specific call work by making it as IPShell(dummy=False). |
|
188 | can still have a specific call work by making it as IPShell(dummy=False). | |
190 | """ |
|
189 | """ | |
191 |
|
190 | |||
192 | # we are called, set the underlying interactiveshell not to exit. |
|
191 | # we are called, set the underlying interactiveshell not to exit. | |
193 | self.keep_running = True |
|
192 | self.keep_running = True | |
194 |
|
193 | |||
195 | # If the user has turned it off, go away |
|
194 | # If the user has turned it off, go away | |
196 | clid = kw.pop('_call_location_id', None) |
|
195 | clid = kw.pop('_call_location_id', None) | |
197 | if not clid: |
|
196 | if not clid: | |
198 | frame = sys._getframe(1) |
|
197 | frame = sys._getframe(1) | |
199 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) |
|
198 | clid = '%s:%s' % (frame.f_code.co_filename, frame.f_lineno) | |
200 | self._call_location_id = clid |
|
199 | self._call_location_id = clid | |
201 |
|
200 | |||
202 | if not self.embedded_active: |
|
201 | if not self.embedded_active: | |
203 | return |
|
202 | return | |
204 |
|
203 | |||
205 | # Normal exits from interactive mode set this flag, so the shell can't |
|
204 | # Normal exits from interactive mode set this flag, so the shell can't | |
206 | # re-enter (it checks this variable at the start of interactive mode). |
|
205 | # re-enter (it checks this variable at the start of interactive mode). | |
207 | self.exit_now = False |
|
206 | self.exit_now = False | |
208 |
|
207 | |||
209 | # Allow the dummy parameter to override the global __dummy_mode |
|
208 | # Allow the dummy parameter to override the global __dummy_mode | |
210 | if dummy or (dummy != 0 and self.dummy_mode): |
|
209 | if dummy or (dummy != 0 and self.dummy_mode): | |
211 | return |
|
210 | return | |
212 |
|
211 | |||
213 | # self.banner is auto computed |
|
212 | # self.banner is auto computed | |
214 | if header: |
|
213 | if header: | |
215 | self.old_banner2 = self.banner2 |
|
214 | self.old_banner2 = self.banner2 | |
216 | self.banner2 = self.banner2 + '\n' + header + '\n' |
|
215 | self.banner2 = self.banner2 + '\n' + header + '\n' | |
217 | else: |
|
216 | else: | |
218 | self.old_banner2 = '' |
|
217 | self.old_banner2 = '' | |
219 |
|
218 | |||
220 | if self.display_banner: |
|
219 | if self.display_banner: | |
221 | self.show_banner() |
|
220 | self.show_banner() | |
222 |
|
221 | |||
223 | # Call the embedding code with a stack depth of 1 so it can skip over |
|
222 | # Call the embedding code with a stack depth of 1 so it can skip over | |
224 | # our call and get the original caller's namespaces. |
|
223 | # our call and get the original caller's namespaces. | |
225 | self.mainloop(local_ns, module, stack_depth=stack_depth, |
|
224 | self.mainloop(local_ns, module, stack_depth=stack_depth, | |
226 | global_ns=global_ns, compile_flags=compile_flags) |
|
225 | global_ns=global_ns, compile_flags=compile_flags) | |
227 |
|
226 | |||
228 | self.banner2 = self.old_banner2 |
|
227 | self.banner2 = self.old_banner2 | |
229 |
|
228 | |||
230 | if self.exit_msg is not None: |
|
229 | if self.exit_msg is not None: | |
231 | print(self.exit_msg) |
|
230 | print(self.exit_msg) | |
232 |
|
231 | |||
233 | if self.should_raise: |
|
232 | if self.should_raise: | |
234 | raise KillEmbeded('Embedded IPython raising error, as user requested.') |
|
233 | raise KillEmbeded('Embedded IPython raising error, as user requested.') | |
235 |
|
234 | |||
236 |
|
235 | |||
237 | def mainloop(self, local_ns=None, module=None, stack_depth=0, |
|
236 | def mainloop(self, local_ns=None, module=None, stack_depth=0, | |
238 | display_banner=None, global_ns=None, compile_flags=None): |
|
237 | display_banner=None, global_ns=None, compile_flags=None): | |
239 | """Embeds IPython into a running python program. |
|
238 | """Embeds IPython into a running python program. | |
240 |
|
239 | |||
241 | Parameters |
|
240 | Parameters | |
242 | ---------- |
|
241 | ---------- | |
243 |
|
242 | |||
244 | local_ns, module |
|
243 | local_ns, module | |
245 | Working local namespace (a dict) and module (a module or similar |
|
244 | Working local namespace (a dict) and module (a module or similar | |
246 | object). If given as None, they are automatically taken from the scope |
|
245 | object). If given as None, they are automatically taken from the scope | |
247 | where the shell was called, so that program variables become visible. |
|
246 | where the shell was called, so that program variables become visible. | |
248 |
|
247 | |||
249 | stack_depth : int |
|
248 | stack_depth : int | |
250 | How many levels in the stack to go to looking for namespaces (when |
|
249 | How many levels in the stack to go to looking for namespaces (when | |
251 | local_ns or module is None). This allows an intermediate caller to |
|
250 | local_ns or module is None). This allows an intermediate caller to | |
252 | make sure that this function gets the namespace from the intended |
|
251 | make sure that this function gets the namespace from the intended | |
253 | level in the stack. By default (0) it will get its locals and globals |
|
252 | level in the stack. By default (0) it will get its locals and globals | |
254 | from the immediate caller. |
|
253 | from the immediate caller. | |
255 |
|
254 | |||
256 | compile_flags |
|
255 | compile_flags | |
257 | A bit field identifying the __future__ features |
|
256 | A bit field identifying the __future__ features | |
258 | that are enabled, as passed to the builtin :func:`compile` function. |
|
257 | that are enabled, as passed to the builtin :func:`compile` function. | |
259 | If given as None, they are automatically taken from the scope where |
|
258 | If given as None, they are automatically taken from the scope where | |
260 | the shell was called. |
|
259 | the shell was called. | |
261 |
|
260 | |||
262 | """ |
|
261 | """ | |
263 |
|
262 | |||
264 | if (global_ns is not None) and (module is None): |
|
263 | if (global_ns is not None) and (module is None): | |
265 | raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") |
|
264 | raise DeprecationWarning("'global_ns' keyword argument is deprecated, and has been removed in IPython 5.0 use `module` keyword argument instead.") | |
266 |
|
265 | |||
267 | if (display_banner is not None): |
|
266 | if (display_banner is not None): | |
268 | warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) |
|
267 | warnings.warn("The display_banner parameter is deprecated since IPython 4.0", DeprecationWarning) | |
269 |
|
268 | |||
270 | # Get locals and globals from caller |
|
269 | # Get locals and globals from caller | |
271 | if ((local_ns is None or module is None or compile_flags is None) |
|
270 | if ((local_ns is None or module is None or compile_flags is None) | |
272 | and self.default_user_namespaces): |
|
271 | and self.default_user_namespaces): | |
273 | call_frame = sys._getframe(stack_depth).f_back |
|
272 | call_frame = sys._getframe(stack_depth).f_back | |
274 |
|
273 | |||
275 | if local_ns is None: |
|
274 | if local_ns is None: | |
276 | local_ns = call_frame.f_locals |
|
275 | local_ns = call_frame.f_locals | |
277 | if module is None: |
|
276 | if module is None: | |
278 | global_ns = call_frame.f_globals |
|
277 | global_ns = call_frame.f_globals | |
279 | try: |
|
278 | try: | |
280 | module = sys.modules[global_ns['__name__']] |
|
279 | module = sys.modules[global_ns['__name__']] | |
281 | except KeyError: |
|
280 | except KeyError: | |
282 | warnings.warn("Failed to get module %s" % \ |
|
281 | warnings.warn("Failed to get module %s" % \ | |
283 | global_ns.get('__name__', 'unknown module') |
|
282 | global_ns.get('__name__', 'unknown module') | |
284 | ) |
|
283 | ) | |
285 | module = DummyMod() |
|
284 | module = DummyMod() | |
286 | module.__dict__ = global_ns |
|
285 | module.__dict__ = global_ns | |
287 | if compile_flags is None: |
|
286 | if compile_flags is None: | |
288 | compile_flags = (call_frame.f_code.co_flags & |
|
287 | compile_flags = (call_frame.f_code.co_flags & | |
289 | compilerop.PyCF_MASK) |
|
288 | compilerop.PyCF_MASK) | |
290 |
|
289 | |||
291 | # Save original namespace and module so we can restore them after |
|
290 | # Save original namespace and module so we can restore them after | |
292 | # embedding; otherwise the shell doesn't shut down correctly. |
|
291 | # embedding; otherwise the shell doesn't shut down correctly. | |
293 | orig_user_module = self.user_module |
|
292 | orig_user_module = self.user_module | |
294 | orig_user_ns = self.user_ns |
|
293 | orig_user_ns = self.user_ns | |
295 | orig_compile_flags = self.compile.flags |
|
294 | orig_compile_flags = self.compile.flags | |
296 |
|
295 | |||
297 | # Update namespaces and fire up interpreter |
|
296 | # Update namespaces and fire up interpreter | |
298 |
|
297 | |||
299 | # The global one is easy, we can just throw it in |
|
298 | # The global one is easy, we can just throw it in | |
300 | if module is not None: |
|
299 | if module is not None: | |
301 | self.user_module = module |
|
300 | self.user_module = module | |
302 |
|
301 | |||
303 | # But the user/local one is tricky: ipython needs it to store internal |
|
302 | # But the user/local one is tricky: ipython needs it to store internal | |
304 | # data, but we also need the locals. We'll throw our hidden variables |
|
303 | # data, but we also need the locals. We'll throw our hidden variables | |
305 | # like _ih and get_ipython() into the local namespace, but delete them |
|
304 | # like _ih and get_ipython() into the local namespace, but delete them | |
306 | # later. |
|
305 | # later. | |
307 | if local_ns is not None: |
|
306 | if local_ns is not None: | |
308 | reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()} |
|
307 | reentrant_local_ns = {k: v for (k, v) in local_ns.items() if k not in self.user_ns_hidden.keys()} | |
309 | self.user_ns = reentrant_local_ns |
|
308 | self.user_ns = reentrant_local_ns | |
310 | self.init_user_ns() |
|
309 | self.init_user_ns() | |
311 |
|
310 | |||
312 | # Compiler flags |
|
311 | # Compiler flags | |
313 | if compile_flags is not None: |
|
312 | if compile_flags is not None: | |
314 | self.compile.flags = compile_flags |
|
313 | self.compile.flags = compile_flags | |
315 |
|
314 | |||
316 | # make sure the tab-completer has the correct frame information, so it |
|
315 | # make sure the tab-completer has the correct frame information, so it | |
317 | # actually completes using the frame's locals/globals |
|
316 | # actually completes using the frame's locals/globals | |
318 | self.set_completer_frame() |
|
317 | self.set_completer_frame() | |
319 |
|
318 | |||
320 | with self.builtin_trap, self.display_trap: |
|
319 | with self.builtin_trap, self.display_trap: | |
321 | self.interact() |
|
320 | self.interact() | |
322 |
|
321 | |||
323 | # now, purge out the local namespace of IPython's hidden variables. |
|
322 | # now, purge out the local namespace of IPython's hidden variables. | |
324 | if local_ns is not None: |
|
323 | if local_ns is not None: | |
325 | local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()}) |
|
324 | local_ns.update({k: v for (k, v) in self.user_ns.items() if k not in self.user_ns_hidden.keys()}) | |
326 |
|
325 | |||
327 |
|
326 | |||
328 | # Restore original namespace so shell can shut down when we exit. |
|
327 | # Restore original namespace so shell can shut down when we exit. | |
329 | self.user_module = orig_user_module |
|
328 | self.user_module = orig_user_module | |
330 | self.user_ns = orig_user_ns |
|
329 | self.user_ns = orig_user_ns | |
331 | self.compile.flags = orig_compile_flags |
|
330 | self.compile.flags = orig_compile_flags | |
332 |
|
331 | |||
333 |
|
332 | |||
334 | def embed(**kwargs): |
|
333 | def embed(**kwargs): | |
335 | """Call this to embed IPython at the current point in your program. |
|
334 | """Call this to embed IPython at the current point in your program. | |
336 |
|
335 | |||
337 | The first invocation of this will create an :class:`InteractiveShellEmbed` |
|
336 | The first invocation of this will create an :class:`InteractiveShellEmbed` | |
338 | instance and then call it. Consecutive calls just call the already |
|
337 | instance and then call it. Consecutive calls just call the already | |
339 | created instance. |
|
338 | created instance. | |
340 |
|
339 | |||
341 | If you don't want the kernel to initialize the namespace |
|
340 | If you don't want the kernel to initialize the namespace | |
342 | from the scope of the surrounding function, |
|
341 | from the scope of the surrounding function, | |
343 | and/or you want to load full IPython configuration, |
|
342 | and/or you want to load full IPython configuration, | |
344 | you probably want `IPython.start_ipython()` instead. |
|
343 | you probably want `IPython.start_ipython()` instead. | |
345 |
|
344 | |||
346 | Here is a simple example:: |
|
345 | Here is a simple example:: | |
347 |
|
346 | |||
348 | from IPython import embed |
|
347 | from IPython import embed | |
349 | a = 10 |
|
348 | a = 10 | |
350 | b = 20 |
|
349 | b = 20 | |
351 | embed(header='First time') |
|
350 | embed(header='First time') | |
352 | c = 30 |
|
351 | c = 30 | |
353 | d = 40 |
|
352 | d = 40 | |
354 | embed() |
|
353 | embed() | |
355 |
|
354 | |||
356 | Full customization can be done by passing a :class:`Config` in as the |
|
355 | Full customization can be done by passing a :class:`Config` in as the | |
357 | config argument. |
|
356 | config argument. | |
358 | """ |
|
357 | """ | |
359 | config = kwargs.get('config') |
|
358 | config = kwargs.get('config') | |
360 | header = kwargs.pop('header', u'') |
|
359 | header = kwargs.pop('header', u'') | |
361 | compile_flags = kwargs.pop('compile_flags', None) |
|
360 | compile_flags = kwargs.pop('compile_flags', None) | |
362 | if config is None: |
|
361 | if config is None: | |
363 | config = load_default_config() |
|
362 | config = load_default_config() | |
364 | config.InteractiveShellEmbed = config.TerminalInteractiveShell |
|
363 | config.InteractiveShellEmbed = config.TerminalInteractiveShell | |
365 | kwargs['config'] = config |
|
364 | kwargs['config'] = config | |
366 | #save ps1/ps2 if defined |
|
365 | #save ps1/ps2 if defined | |
367 | ps1 = None |
|
366 | ps1 = None | |
368 | ps2 = None |
|
367 | ps2 = None | |
369 | try: |
|
368 | try: | |
370 | ps1 = sys.ps1 |
|
369 | ps1 = sys.ps1 | |
371 | ps2 = sys.ps2 |
|
370 | ps2 = sys.ps2 | |
372 | except AttributeError: |
|
371 | except AttributeError: | |
373 | pass |
|
372 | pass | |
374 | #save previous instance |
|
373 | #save previous instance | |
375 | saved_shell_instance = InteractiveShell._instance |
|
374 | saved_shell_instance = InteractiveShell._instance | |
376 | if saved_shell_instance is not None: |
|
375 | if saved_shell_instance is not None: | |
377 | cls = type(saved_shell_instance) |
|
376 | cls = type(saved_shell_instance) | |
378 | cls.clear_instance() |
|
377 | cls.clear_instance() | |
379 | frame = sys._getframe(1) |
|
378 | frame = sys._getframe(1) | |
380 | shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % ( |
|
379 | shell = InteractiveShellEmbed.instance(_init_location_id='%s:%s' % ( | |
381 | frame.f_code.co_filename, frame.f_lineno), **kwargs) |
|
380 | frame.f_code.co_filename, frame.f_lineno), **kwargs) | |
382 | shell(header=header, stack_depth=2, compile_flags=compile_flags, |
|
381 | shell(header=header, stack_depth=2, compile_flags=compile_flags, | |
383 | _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno)) |
|
382 | _call_location_id='%s:%s' % (frame.f_code.co_filename, frame.f_lineno)) | |
384 | InteractiveShellEmbed.clear_instance() |
|
383 | InteractiveShellEmbed.clear_instance() | |
385 | #restore previous instance |
|
384 | #restore previous instance | |
386 | if saved_shell_instance is not None: |
|
385 | if saved_shell_instance is not None: | |
387 | cls = type(saved_shell_instance) |
|
386 | cls = type(saved_shell_instance) | |
388 | cls.clear_instance() |
|
387 | cls.clear_instance() | |
389 | for subclass in cls._walk_mro(): |
|
388 | for subclass in cls._walk_mro(): | |
390 | subclass._instance = saved_shell_instance |
|
389 | subclass._instance = saved_shell_instance | |
391 | if ps1 is not None: |
|
390 | if ps1 is not None: | |
392 | sys.ps1 = ps1 |
|
391 | sys.ps1 = ps1 | |
393 | sys.ps2 = ps2 |
|
392 | sys.ps2 = ps2 |
@@ -1,518 +1,516 b'' | |||||
1 | """IPython terminal interface using prompt_toolkit""" |
|
1 | """IPython terminal interface using prompt_toolkit""" | |
2 |
|
2 | |||
3 | import os |
|
3 | import os | |
4 | import sys |
|
4 | import sys | |
5 | import warnings |
|
5 | import warnings | |
6 | from warnings import warn |
|
6 | from warnings import warn | |
7 |
|
7 | |||
8 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC |
|
8 | from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC | |
9 | from IPython.utils import io |
|
9 | from IPython.utils import io | |
10 | from IPython.utils.py3compat import cast_unicode_py2, input |
|
10 | from IPython.utils.py3compat import cast_unicode_py2, input | |
11 | from IPython.utils.terminal import toggle_set_term_title, set_term_title |
|
11 | from IPython.utils.terminal import toggle_set_term_title, set_term_title | |
12 | from IPython.utils.process import abbrev_cwd |
|
12 | from IPython.utils.process import abbrev_cwd | |
13 | from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union |
|
13 | from traitlets import Bool, Unicode, Dict, Integer, observe, Instance, Type, default, Enum, Union | |
14 |
|
14 | |||
15 | from prompt_toolkit.document import Document |
|
15 | from prompt_toolkit.document import Document | |
16 | from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode |
|
16 | from prompt_toolkit.enums import DEFAULT_BUFFER, EditingMode | |
17 | from prompt_toolkit.filters import (HasFocus, Condition, IsDone) |
|
17 | from prompt_toolkit.filters import (HasFocus, Condition, IsDone) | |
18 | from prompt_toolkit.history import InMemoryHistory |
|
18 | from prompt_toolkit.history import InMemoryHistory | |
19 | from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output |
|
19 | from prompt_toolkit.shortcuts import create_prompt_application, create_eventloop, create_prompt_layout, create_output | |
20 | from prompt_toolkit.interface import CommandLineInterface |
|
20 | from prompt_toolkit.interface import CommandLineInterface | |
21 | from prompt_toolkit.key_binding.manager import KeyBindingManager |
|
21 | from prompt_toolkit.key_binding.manager import KeyBindingManager | |
22 | from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor |
|
22 | from prompt_toolkit.layout.processors import ConditionalProcessor, HighlightMatchingBracketProcessor | |
23 | from prompt_toolkit.styles import PygmentsStyle, DynamicStyle |
|
23 | from prompt_toolkit.styles import PygmentsStyle, DynamicStyle | |
24 |
|
24 | |||
25 | from pygments.styles import get_style_by_name, get_all_styles |
|
25 | from pygments.styles import get_style_by_name, get_all_styles | |
26 | from pygments.style import Style |
|
26 | from pygments.style import Style | |
27 | from pygments.token import Token |
|
27 | from pygments.token import Token | |
28 |
|
28 | |||
29 | from .debugger import TerminalPdb, Pdb |
|
29 | from .debugger import TerminalPdb, Pdb | |
30 | from .magics import TerminalMagics |
|
30 | from .magics import TerminalMagics | |
31 | from .pt_inputhooks import get_inputhook_name_and_func |
|
31 | from .pt_inputhooks import get_inputhook_name_and_func | |
32 | from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook |
|
32 | from .prompts import Prompts, ClassicPrompts, RichPromptDisplayHook | |
33 | from .ptutils import IPythonPTCompleter, IPythonPTLexer |
|
33 | from .ptutils import IPythonPTCompleter, IPythonPTLexer | |
34 | from .shortcuts import register_ipython_shortcuts |
|
34 | from .shortcuts import register_ipython_shortcuts | |
35 |
|
35 | |||
36 | DISPLAY_BANNER_DEPRECATED = object() |
|
36 | DISPLAY_BANNER_DEPRECATED = object() | |
37 |
|
37 | |||
38 |
|
38 | |||
39 | class _NoStyle(Style): pass |
|
39 | class _NoStyle(Style): pass | |
40 |
|
40 | |||
41 |
|
41 | |||
42 |
|
42 | |||
43 | _style_overrides_light_bg = { |
|
43 | _style_overrides_light_bg = { | |
44 | Token.Prompt: '#0000ff', |
|
44 | Token.Prompt: '#0000ff', | |
45 | Token.PromptNum: '#0000ee bold', |
|
45 | Token.PromptNum: '#0000ee bold', | |
46 | Token.OutPrompt: '#cc0000', |
|
46 | Token.OutPrompt: '#cc0000', | |
47 | Token.OutPromptNum: '#bb0000 bold', |
|
47 | Token.OutPromptNum: '#bb0000 bold', | |
48 | } |
|
48 | } | |
49 |
|
49 | |||
50 | _style_overrides_linux = { |
|
50 | _style_overrides_linux = { | |
51 | Token.Prompt: '#00cc00', |
|
51 | Token.Prompt: '#00cc00', | |
52 | Token.PromptNum: '#00bb00 bold', |
|
52 | Token.PromptNum: '#00bb00 bold', | |
53 | Token.OutPrompt: '#cc0000', |
|
53 | Token.OutPrompt: '#cc0000', | |
54 | Token.OutPromptNum: '#bb0000 bold', |
|
54 | Token.OutPromptNum: '#bb0000 bold', | |
55 | } |
|
55 | } | |
56 |
|
56 | |||
57 |
|
57 | |||
58 |
|
58 | |||
59 | def get_default_editor(): |
|
59 | def get_default_editor(): | |
60 | try: |
|
60 | try: | |
61 | return os.environ['EDITOR'] |
|
61 | return os.environ['EDITOR'] | |
62 | except KeyError: |
|
62 | except KeyError: | |
63 | pass |
|
63 | pass | |
64 | except UnicodeError: |
|
64 | except UnicodeError: | |
65 | warn("$EDITOR environment variable is not pure ASCII. Using platform " |
|
65 | warn("$EDITOR environment variable is not pure ASCII. Using platform " | |
66 | "default editor.") |
|
66 | "default editor.") | |
67 |
|
67 | |||
68 | if os.name == 'posix': |
|
68 | if os.name == 'posix': | |
69 | return 'vi' # the only one guaranteed to be there! |
|
69 | return 'vi' # the only one guaranteed to be there! | |
70 | else: |
|
70 | else: | |
71 | return 'notepad' # same in Windows! |
|
71 | return 'notepad' # same in Windows! | |
72 |
|
72 | |||
73 | # conservatively check for tty |
|
73 | # conservatively check for tty | |
74 | # overridden streams can result in things like: |
|
74 | # overridden streams can result in things like: | |
75 | # - sys.stdin = None |
|
75 | # - sys.stdin = None | |
76 | # - no isatty method |
|
76 | # - no isatty method | |
77 | for _name in ('stdin', 'stdout', 'stderr'): |
|
77 | for _name in ('stdin', 'stdout', 'stderr'): | |
78 | _stream = getattr(sys, _name) |
|
78 | _stream = getattr(sys, _name) | |
79 | if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty(): |
|
79 | if not _stream or not hasattr(_stream, 'isatty') or not _stream.isatty(): | |
80 | _is_tty = False |
|
80 | _is_tty = False | |
81 | break |
|
81 | break | |
82 | else: |
|
82 | else: | |
83 | _is_tty = True |
|
83 | _is_tty = True | |
84 |
|
84 | |||
85 |
|
85 | |||
86 | _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) |
|
86 | _use_simple_prompt = ('IPY_TEST_SIMPLE_PROMPT' in os.environ) or (not _is_tty) | |
87 |
|
87 | |||
88 | class TerminalInteractiveShell(InteractiveShell): |
|
88 | class TerminalInteractiveShell(InteractiveShell): | |
89 | space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' |
|
89 | space_for_menu = Integer(6, help='Number of line at the bottom of the screen ' | |
90 | 'to reserve for the completion menu' |
|
90 | 'to reserve for the completion menu' | |
91 | ).tag(config=True) |
|
91 | ).tag(config=True) | |
92 |
|
92 | |||
93 | def _space_for_menu_changed(self, old, new): |
|
93 | def _space_for_menu_changed(self, old, new): | |
94 | self._update_layout() |
|
94 | self._update_layout() | |
95 |
|
95 | |||
96 | pt_cli = None |
|
96 | pt_cli = None | |
97 | debugger_history = None |
|
97 | debugger_history = None | |
98 | _pt_app = None |
|
98 | _pt_app = None | |
99 |
|
99 | |||
100 | simple_prompt = Bool(_use_simple_prompt, |
|
100 | simple_prompt = Bool(_use_simple_prompt, | |
101 | help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. |
|
101 | help="""Use `raw_input` for the REPL, without completion, multiline input, and prompt colors. | |
102 |
|
102 | |||
103 | Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: |
|
103 | Useful when controlling IPython as a subprocess, and piping STDIN/OUT/ERR. Known usage are: | |
104 | IPython own testing machinery, and emacs inferior-shell integration through elpy. |
|
104 | IPython own testing machinery, and emacs inferior-shell integration through elpy. | |
105 |
|
105 | |||
106 | This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` |
|
106 | This mode default to `True` if the `IPY_TEST_SIMPLE_PROMPT` | |
107 | environment variable is set, or the current terminal is not a tty. |
|
107 | environment variable is set, or the current terminal is not a tty.""" | |
108 |
|
||||
109 | """ |
|
|||
110 | ).tag(config=True) |
|
108 | ).tag(config=True) | |
111 |
|
109 | |||
112 | @property |
|
110 | @property | |
113 | def debugger_cls(self): |
|
111 | def debugger_cls(self): | |
114 | return Pdb if self.simple_prompt else TerminalPdb |
|
112 | return Pdb if self.simple_prompt else TerminalPdb | |
115 |
|
113 | |||
116 | confirm_exit = Bool(True, |
|
114 | confirm_exit = Bool(True, | |
117 | help=""" |
|
115 | help=""" | |
118 | Set to confirm when you try to exit IPython with an EOF (Control-D |
|
116 | Set to confirm when you try to exit IPython with an EOF (Control-D | |
119 | in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', |
|
117 | in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit', | |
120 | you can force a direct exit without any confirmation.""", |
|
118 | you can force a direct exit without any confirmation.""", | |
121 | ).tag(config=True) |
|
119 | ).tag(config=True) | |
122 |
|
120 | |||
123 | editing_mode = Unicode('emacs', |
|
121 | editing_mode = Unicode('emacs', | |
124 | help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", |
|
122 | help="Shortcut style to use at the prompt. 'vi' or 'emacs'.", | |
125 | ).tag(config=True) |
|
123 | ).tag(config=True) | |
126 |
|
124 | |||
127 | mouse_support = Bool(False, |
|
125 | mouse_support = Bool(False, | |
128 | help="Enable mouse support in the prompt" |
|
126 | help="Enable mouse support in the prompt" | |
129 | ).tag(config=True) |
|
127 | ).tag(config=True) | |
130 |
|
128 | |||
131 | highlighting_style = Union([Unicode('legacy'), Type(klass=Style)], |
|
129 | highlighting_style = Union([Unicode('legacy'), Type(klass=Style)], | |
132 | help="""The name or class of a Pygments style to use for syntax |
|
130 | help="""The name or class of a Pygments style to use for syntax | |
133 | highlighting: \n %s""" % ', '.join(get_all_styles()) |
|
131 | highlighting: \n %s""" % ', '.join(get_all_styles()) | |
134 | ).tag(config=True) |
|
132 | ).tag(config=True) | |
135 |
|
133 | |||
136 |
|
134 | |||
137 | @observe('highlighting_style') |
|
135 | @observe('highlighting_style') | |
138 | @observe('colors') |
|
136 | @observe('colors') | |
139 | def _highlighting_style_changed(self, change): |
|
137 | def _highlighting_style_changed(self, change): | |
140 | self.refresh_style() |
|
138 | self.refresh_style() | |
141 |
|
139 | |||
142 | def refresh_style(self): |
|
140 | def refresh_style(self): | |
143 | self._style = self._make_style_from_name_or_cls(self.highlighting_style) |
|
141 | self._style = self._make_style_from_name_or_cls(self.highlighting_style) | |
144 |
|
142 | |||
145 |
|
143 | |||
146 | highlighting_style_overrides = Dict( |
|
144 | highlighting_style_overrides = Dict( | |
147 | help="Override highlighting format for specific tokens" |
|
145 | help="Override highlighting format for specific tokens" | |
148 | ).tag(config=True) |
|
146 | ).tag(config=True) | |
149 |
|
147 | |||
150 | true_color = Bool(False, |
|
148 | true_color = Bool(False, | |
151 | help=("Use 24bit colors instead of 256 colors in prompt highlighting. " |
|
149 | help=("Use 24bit colors instead of 256 colors in prompt highlighting. " | |
152 | "If your terminal supports true color, the following command " |
|
150 | "If your terminal supports true color, the following command " | |
153 | "should print 'TRUECOLOR' in orange: " |
|
151 | "should print 'TRUECOLOR' in orange: " | |
154 | "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"") |
|
152 | "printf \"\\x1b[38;2;255;100;0mTRUECOLOR\\x1b[0m\\n\"") | |
155 | ).tag(config=True) |
|
153 | ).tag(config=True) | |
156 |
|
154 | |||
157 | editor = Unicode(get_default_editor(), |
|
155 | editor = Unicode(get_default_editor(), | |
158 | help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." |
|
156 | help="Set the editor used by IPython (default to $EDITOR/vi/notepad)." | |
159 | ).tag(config=True) |
|
157 | ).tag(config=True) | |
160 |
|
158 | |||
161 | prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True) |
|
159 | prompts_class = Type(Prompts, help='Class used to generate Prompt token for prompt_toolkit').tag(config=True) | |
162 |
|
160 | |||
163 | prompts = Instance(Prompts) |
|
161 | prompts = Instance(Prompts) | |
164 |
|
162 | |||
165 | @default('prompts') |
|
163 | @default('prompts') | |
166 | def _prompts_default(self): |
|
164 | def _prompts_default(self): | |
167 | return self.prompts_class(self) |
|
165 | return self.prompts_class(self) | |
168 |
|
166 | |||
169 | @observe('prompts') |
|
167 | @observe('prompts') | |
170 | def _(self, change): |
|
168 | def _(self, change): | |
171 | self._update_layout() |
|
169 | self._update_layout() | |
172 |
|
170 | |||
173 | @default('displayhook_class') |
|
171 | @default('displayhook_class') | |
174 | def _displayhook_class_default(self): |
|
172 | def _displayhook_class_default(self): | |
175 | return RichPromptDisplayHook |
|
173 | return RichPromptDisplayHook | |
176 |
|
174 | |||
177 | term_title = Bool(True, |
|
175 | term_title = Bool(True, | |
178 | help="Automatically set the terminal title" |
|
176 | help="Automatically set the terminal title" | |
179 | ).tag(config=True) |
|
177 | ).tag(config=True) | |
180 |
|
178 | |||
181 | display_completions = Enum(('column', 'multicolumn','readlinelike'), |
|
179 | display_completions = Enum(('column', 'multicolumn','readlinelike'), | |
182 | help= ( "Options for displaying tab completions, 'column', 'multicolumn', and " |
|
180 | help= ( "Options for displaying tab completions, 'column', 'multicolumn', and " | |
183 | "'readlinelike'. These options are for `prompt_toolkit`, see " |
|
181 | "'readlinelike'. These options are for `prompt_toolkit`, see " | |
184 | "`prompt_toolkit` documentation for more information." |
|
182 | "`prompt_toolkit` documentation for more information." | |
185 | ), |
|
183 | ), | |
186 | default_value='multicolumn').tag(config=True) |
|
184 | default_value='multicolumn').tag(config=True) | |
187 |
|
185 | |||
188 | highlight_matching_brackets = Bool(True, |
|
186 | highlight_matching_brackets = Bool(True, | |
189 | help="Highlight matching brackets.", |
|
187 | help="Highlight matching brackets.", | |
190 | ).tag(config=True) |
|
188 | ).tag(config=True) | |
191 |
|
189 | |||
192 | extra_open_editor_shortcuts = Bool(False, |
|
190 | extra_open_editor_shortcuts = Bool(False, | |
193 | help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. " |
|
191 | help="Enable vi (v) or Emacs (C-X C-E) shortcuts to open an external editor. " | |
194 | "This is in addition to the F2 binding, which is always enabled." |
|
192 | "This is in addition to the F2 binding, which is always enabled." | |
195 | ).tag(config=True) |
|
193 | ).tag(config=True) | |
196 |
|
194 | |||
197 | @observe('term_title') |
|
195 | @observe('term_title') | |
198 | def init_term_title(self, change=None): |
|
196 | def init_term_title(self, change=None): | |
199 | # Enable or disable the terminal title. |
|
197 | # Enable or disable the terminal title. | |
200 | if self.term_title: |
|
198 | if self.term_title: | |
201 | toggle_set_term_title(True) |
|
199 | toggle_set_term_title(True) | |
202 | set_term_title('IPython: ' + abbrev_cwd()) |
|
200 | set_term_title('IPython: ' + abbrev_cwd()) | |
203 | else: |
|
201 | else: | |
204 | toggle_set_term_title(False) |
|
202 | toggle_set_term_title(False) | |
205 |
|
203 | |||
206 | def init_display_formatter(self): |
|
204 | def init_display_formatter(self): | |
207 | super(TerminalInteractiveShell, self).init_display_formatter() |
|
205 | super(TerminalInteractiveShell, self).init_display_formatter() | |
208 | # terminal only supports plain text |
|
206 | # terminal only supports plain text | |
209 | self.display_formatter.active_types = ['text/plain'] |
|
207 | self.display_formatter.active_types = ['text/plain'] | |
210 | # disable `_ipython_display_` |
|
208 | # disable `_ipython_display_` | |
211 | self.display_formatter.ipython_display_formatter.enabled = False |
|
209 | self.display_formatter.ipython_display_formatter.enabled = False | |
212 |
|
210 | |||
213 | def init_prompt_toolkit_cli(self): |
|
211 | def init_prompt_toolkit_cli(self): | |
214 | if self.simple_prompt: |
|
212 | if self.simple_prompt: | |
215 | # Fall back to plain non-interactive output for tests. |
|
213 | # Fall back to plain non-interactive output for tests. | |
216 | # This is very limited, and only accepts a single line. |
|
214 | # This is very limited, and only accepts a single line. | |
217 | def prompt(): |
|
215 | def prompt(): | |
218 | return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) |
|
216 | return cast_unicode_py2(input('In [%d]: ' % self.execution_count)) | |
219 | self.prompt_for_code = prompt |
|
217 | self.prompt_for_code = prompt | |
220 | return |
|
218 | return | |
221 |
|
219 | |||
222 | # Set up keyboard shortcuts |
|
220 | # Set up keyboard shortcuts | |
223 | kbmanager = KeyBindingManager.for_prompt( |
|
221 | kbmanager = KeyBindingManager.for_prompt( | |
224 | enable_open_in_editor=self.extra_open_editor_shortcuts, |
|
222 | enable_open_in_editor=self.extra_open_editor_shortcuts, | |
225 | ) |
|
223 | ) | |
226 | register_ipython_shortcuts(kbmanager.registry, self) |
|
224 | register_ipython_shortcuts(kbmanager.registry, self) | |
227 |
|
225 | |||
228 | # Pre-populate history from IPython's history database |
|
226 | # Pre-populate history from IPython's history database | |
229 | history = InMemoryHistory() |
|
227 | history = InMemoryHistory() | |
230 | last_cell = u"" |
|
228 | last_cell = u"" | |
231 | for __, ___, cell in self.history_manager.get_tail(self.history_load_length, |
|
229 | for __, ___, cell in self.history_manager.get_tail(self.history_load_length, | |
232 | include_latest=True): |
|
230 | include_latest=True): | |
233 | # Ignore blank lines and consecutive duplicates |
|
231 | # Ignore blank lines and consecutive duplicates | |
234 | cell = cell.rstrip() |
|
232 | cell = cell.rstrip() | |
235 | if cell and (cell != last_cell): |
|
233 | if cell and (cell != last_cell): | |
236 | history.append(cell) |
|
234 | history.append(cell) | |
237 | last_cell = cell |
|
235 | last_cell = cell | |
238 |
|
236 | |||
239 | self._style = self._make_style_from_name_or_cls(self.highlighting_style) |
|
237 | self._style = self._make_style_from_name_or_cls(self.highlighting_style) | |
240 | style = DynamicStyle(lambda: self._style) |
|
238 | style = DynamicStyle(lambda: self._style) | |
241 |
|
239 | |||
242 | editing_mode = getattr(EditingMode, self.editing_mode.upper()) |
|
240 | editing_mode = getattr(EditingMode, self.editing_mode.upper()) | |
243 |
|
241 | |||
244 | def patch_stdout(**kwargs): |
|
242 | def patch_stdout(**kwargs): | |
245 | return self.pt_cli.patch_stdout_context(**kwargs) |
|
243 | return self.pt_cli.patch_stdout_context(**kwargs) | |
246 |
|
244 | |||
247 | self._pt_app = create_prompt_application( |
|
245 | self._pt_app = create_prompt_application( | |
248 | editing_mode=editing_mode, |
|
246 | editing_mode=editing_mode, | |
249 | key_bindings_registry=kbmanager.registry, |
|
247 | key_bindings_registry=kbmanager.registry, | |
250 | history=history, |
|
248 | history=history, | |
251 | completer=IPythonPTCompleter(shell=self, |
|
249 | completer=IPythonPTCompleter(shell=self, | |
252 | patch_stdout=patch_stdout), |
|
250 | patch_stdout=patch_stdout), | |
253 | enable_history_search=True, |
|
251 | enable_history_search=True, | |
254 | style=style, |
|
252 | style=style, | |
255 | mouse_support=self.mouse_support, |
|
253 | mouse_support=self.mouse_support, | |
256 | **self._layout_options() |
|
254 | **self._layout_options() | |
257 | ) |
|
255 | ) | |
258 | self._eventloop = create_eventloop(self.inputhook) |
|
256 | self._eventloop = create_eventloop(self.inputhook) | |
259 | self.pt_cli = CommandLineInterface( |
|
257 | self.pt_cli = CommandLineInterface( | |
260 | self._pt_app, eventloop=self._eventloop, |
|
258 | self._pt_app, eventloop=self._eventloop, | |
261 | output=create_output(true_color=self.true_color)) |
|
259 | output=create_output(true_color=self.true_color)) | |
262 |
|
260 | |||
263 | def _make_style_from_name_or_cls(self, name_or_cls): |
|
261 | def _make_style_from_name_or_cls(self, name_or_cls): | |
264 | """ |
|
262 | """ | |
265 | Small wrapper that make an IPython compatible style from a style name |
|
263 | Small wrapper that make an IPython compatible style from a style name | |
266 |
|
264 | |||
267 | We need that to add style for prompt ... etc. |
|
265 | We need that to add style for prompt ... etc. | |
268 | """ |
|
266 | """ | |
269 | style_overrides = {} |
|
267 | style_overrides = {} | |
270 | if name_or_cls == 'legacy': |
|
268 | if name_or_cls == 'legacy': | |
271 | legacy = self.colors.lower() |
|
269 | legacy = self.colors.lower() | |
272 | if legacy == 'linux': |
|
270 | if legacy == 'linux': | |
273 | style_cls = get_style_by_name('monokai') |
|
271 | style_cls = get_style_by_name('monokai') | |
274 | style_overrides = _style_overrides_linux |
|
272 | style_overrides = _style_overrides_linux | |
275 | elif legacy == 'lightbg': |
|
273 | elif legacy == 'lightbg': | |
276 | style_overrides = _style_overrides_light_bg |
|
274 | style_overrides = _style_overrides_light_bg | |
277 | style_cls = get_style_by_name('pastie') |
|
275 | style_cls = get_style_by_name('pastie') | |
278 | elif legacy == 'neutral': |
|
276 | elif legacy == 'neutral': | |
279 | # The default theme needs to be visible on both a dark background |
|
277 | # The default theme needs to be visible on both a dark background | |
280 | # and a light background, because we can't tell what the terminal |
|
278 | # and a light background, because we can't tell what the terminal | |
281 | # looks like. These tweaks to the default theme help with that. |
|
279 | # looks like. These tweaks to the default theme help with that. | |
282 | style_cls = get_style_by_name('default') |
|
280 | style_cls = get_style_by_name('default') | |
283 | style_overrides.update({ |
|
281 | style_overrides.update({ | |
284 | Token.Number: '#007700', |
|
282 | Token.Number: '#007700', | |
285 | Token.Operator: 'noinherit', |
|
283 | Token.Operator: 'noinherit', | |
286 | Token.String: '#BB6622', |
|
284 | Token.String: '#BB6622', | |
287 | Token.Name.Function: '#2080D0', |
|
285 | Token.Name.Function: '#2080D0', | |
288 | Token.Name.Class: 'bold #2080D0', |
|
286 | Token.Name.Class: 'bold #2080D0', | |
289 | Token.Name.Namespace: 'bold #2080D0', |
|
287 | Token.Name.Namespace: 'bold #2080D0', | |
290 | Token.Prompt: '#009900', |
|
288 | Token.Prompt: '#009900', | |
291 | Token.PromptNum: '#00ff00 bold', |
|
289 | Token.PromptNum: '#00ff00 bold', | |
292 | Token.OutPrompt: '#990000', |
|
290 | Token.OutPrompt: '#990000', | |
293 | Token.OutPromptNum: '#ff0000 bold', |
|
291 | Token.OutPromptNum: '#ff0000 bold', | |
294 | }) |
|
292 | }) | |
295 |
|
293 | |||
296 | # Hack: Due to limited color support on the Windows console |
|
294 | # Hack: Due to limited color support on the Windows console | |
297 | # the prompt colors will be wrong without this |
|
295 | # the prompt colors will be wrong without this | |
298 | if os.name == 'nt': |
|
296 | if os.name == 'nt': | |
299 | style_overrides.update({ |
|
297 | style_overrides.update({ | |
300 | Token.Prompt: '#ansidarkgreen', |
|
298 | Token.Prompt: '#ansidarkgreen', | |
301 | Token.PromptNum: '#ansigreen bold', |
|
299 | Token.PromptNum: '#ansigreen bold', | |
302 | Token.OutPrompt: '#ansidarkred', |
|
300 | Token.OutPrompt: '#ansidarkred', | |
303 | Token.OutPromptNum: '#ansired bold', |
|
301 | Token.OutPromptNum: '#ansired bold', | |
304 | }) |
|
302 | }) | |
305 | elif legacy =='nocolor': |
|
303 | elif legacy =='nocolor': | |
306 | style_cls=_NoStyle |
|
304 | style_cls=_NoStyle | |
307 | style_overrides = {} |
|
305 | style_overrides = {} | |
308 | else : |
|
306 | else : | |
309 | raise ValueError('Got unknown colors: ', legacy) |
|
307 | raise ValueError('Got unknown colors: ', legacy) | |
310 | else : |
|
308 | else : | |
311 | if isinstance(name_or_cls, str): |
|
309 | if isinstance(name_or_cls, str): | |
312 | style_cls = get_style_by_name(name_or_cls) |
|
310 | style_cls = get_style_by_name(name_or_cls) | |
313 | else: |
|
311 | else: | |
314 | style_cls = name_or_cls |
|
312 | style_cls = name_or_cls | |
315 | style_overrides = { |
|
313 | style_overrides = { | |
316 | Token.Prompt: '#009900', |
|
314 | Token.Prompt: '#009900', | |
317 | Token.PromptNum: '#00ff00 bold', |
|
315 | Token.PromptNum: '#00ff00 bold', | |
318 | Token.OutPrompt: '#990000', |
|
316 | Token.OutPrompt: '#990000', | |
319 | Token.OutPromptNum: '#ff0000 bold', |
|
317 | Token.OutPromptNum: '#ff0000 bold', | |
320 | } |
|
318 | } | |
321 | style_overrides.update(self.highlighting_style_overrides) |
|
319 | style_overrides.update(self.highlighting_style_overrides) | |
322 | style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, |
|
320 | style = PygmentsStyle.from_defaults(pygments_style_cls=style_cls, | |
323 | style_dict=style_overrides) |
|
321 | style_dict=style_overrides) | |
324 |
|
322 | |||
325 | return style |
|
323 | return style | |
326 |
|
324 | |||
327 | def _layout_options(self): |
|
325 | def _layout_options(self): | |
328 | """ |
|
326 | """ | |
329 | Return the current layout option for the current Terminal InteractiveShell |
|
327 | Return the current layout option for the current Terminal InteractiveShell | |
330 | """ |
|
328 | """ | |
331 | return { |
|
329 | return { | |
332 | 'lexer':IPythonPTLexer(), |
|
330 | 'lexer':IPythonPTLexer(), | |
333 | 'reserve_space_for_menu':self.space_for_menu, |
|
331 | 'reserve_space_for_menu':self.space_for_menu, | |
334 | 'get_prompt_tokens':self.prompts.in_prompt_tokens, |
|
332 | 'get_prompt_tokens':self.prompts.in_prompt_tokens, | |
335 | 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, |
|
333 | 'get_continuation_tokens':self.prompts.continuation_prompt_tokens, | |
336 | 'multiline':True, |
|
334 | 'multiline':True, | |
337 | 'display_completions_in_columns': (self.display_completions == 'multicolumn'), |
|
335 | 'display_completions_in_columns': (self.display_completions == 'multicolumn'), | |
338 |
|
336 | |||
339 | # Highlight matching brackets, but only when this setting is |
|
337 | # Highlight matching brackets, but only when this setting is | |
340 | # enabled, and only when the DEFAULT_BUFFER has the focus. |
|
338 | # enabled, and only when the DEFAULT_BUFFER has the focus. | |
341 | 'extra_input_processors': [ConditionalProcessor( |
|
339 | 'extra_input_processors': [ConditionalProcessor( | |
342 | processor=HighlightMatchingBracketProcessor(chars='[](){}'), |
|
340 | processor=HighlightMatchingBracketProcessor(chars='[](){}'), | |
343 | filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & |
|
341 | filter=HasFocus(DEFAULT_BUFFER) & ~IsDone() & | |
344 | Condition(lambda cli: self.highlight_matching_brackets))], |
|
342 | Condition(lambda cli: self.highlight_matching_brackets))], | |
345 | } |
|
343 | } | |
346 |
|
344 | |||
347 | def _update_layout(self): |
|
345 | def _update_layout(self): | |
348 | """ |
|
346 | """ | |
349 | Ask for a re computation of the application layout, if for example , |
|
347 | Ask for a re computation of the application layout, if for example , | |
350 | some configuration options have changed. |
|
348 | some configuration options have changed. | |
351 | """ |
|
349 | """ | |
352 | if self._pt_app: |
|
350 | if self._pt_app: | |
353 | self._pt_app.layout = create_prompt_layout(**self._layout_options()) |
|
351 | self._pt_app.layout = create_prompt_layout(**self._layout_options()) | |
354 |
|
352 | |||
355 | def prompt_for_code(self): |
|
353 | def prompt_for_code(self): | |
356 | document = self.pt_cli.run( |
|
354 | document = self.pt_cli.run( | |
357 | pre_run=self.pre_prompt, reset_current_buffer=True) |
|
355 | pre_run=self.pre_prompt, reset_current_buffer=True) | |
358 | return document.text |
|
356 | return document.text | |
359 |
|
357 | |||
360 | def enable_win_unicode_console(self): |
|
358 | def enable_win_unicode_console(self): | |
361 | if sys.version_info >= (3, 6): |
|
359 | if sys.version_info >= (3, 6): | |
362 | # Since PEP 528, Python uses the unicode APIs for the Windows |
|
360 | # Since PEP 528, Python uses the unicode APIs for the Windows | |
363 | # console by default, so WUC shouldn't be needed. |
|
361 | # console by default, so WUC shouldn't be needed. | |
364 | return |
|
362 | return | |
365 |
|
363 | |||
366 | import win_unicode_console |
|
364 | import win_unicode_console | |
367 | win_unicode_console.enable() |
|
365 | win_unicode_console.enable() | |
368 |
|
366 | |||
369 | def init_io(self): |
|
367 | def init_io(self): | |
370 | if sys.platform not in {'win32', 'cli'}: |
|
368 | if sys.platform not in {'win32', 'cli'}: | |
371 | return |
|
369 | return | |
372 |
|
370 | |||
373 | self.enable_win_unicode_console() |
|
371 | self.enable_win_unicode_console() | |
374 |
|
372 | |||
375 | import colorama |
|
373 | import colorama | |
376 | colorama.init() |
|
374 | colorama.init() | |
377 |
|
375 | |||
378 | # For some reason we make these wrappers around stdout/stderr. |
|
376 | # For some reason we make these wrappers around stdout/stderr. | |
379 | # For now, we need to reset them so all output gets coloured. |
|
377 | # For now, we need to reset them so all output gets coloured. | |
380 | # https://github.com/ipython/ipython/issues/8669 |
|
378 | # https://github.com/ipython/ipython/issues/8669 | |
381 | # io.std* are deprecated, but don't show our own deprecation warnings |
|
379 | # io.std* are deprecated, but don't show our own deprecation warnings | |
382 | # during initialization of the deprecated API. |
|
380 | # during initialization of the deprecated API. | |
383 | with warnings.catch_warnings(): |
|
381 | with warnings.catch_warnings(): | |
384 | warnings.simplefilter('ignore', DeprecationWarning) |
|
382 | warnings.simplefilter('ignore', DeprecationWarning) | |
385 | io.stdout = io.IOStream(sys.stdout) |
|
383 | io.stdout = io.IOStream(sys.stdout) | |
386 | io.stderr = io.IOStream(sys.stderr) |
|
384 | io.stderr = io.IOStream(sys.stderr) | |
387 |
|
385 | |||
388 | def init_magics(self): |
|
386 | def init_magics(self): | |
389 | super(TerminalInteractiveShell, self).init_magics() |
|
387 | super(TerminalInteractiveShell, self).init_magics() | |
390 | self.register_magics(TerminalMagics) |
|
388 | self.register_magics(TerminalMagics) | |
391 |
|
389 | |||
392 | def init_alias(self): |
|
390 | def init_alias(self): | |
393 | # The parent class defines aliases that can be safely used with any |
|
391 | # The parent class defines aliases that can be safely used with any | |
394 | # frontend. |
|
392 | # frontend. | |
395 | super(TerminalInteractiveShell, self).init_alias() |
|
393 | super(TerminalInteractiveShell, self).init_alias() | |
396 |
|
394 | |||
397 | # Now define aliases that only make sense on the terminal, because they |
|
395 | # Now define aliases that only make sense on the terminal, because they | |
398 | # need direct access to the console in a way that we can't emulate in |
|
396 | # need direct access to the console in a way that we can't emulate in | |
399 | # GUI or web frontend |
|
397 | # GUI or web frontend | |
400 | if os.name == 'posix': |
|
398 | if os.name == 'posix': | |
401 | for cmd in ['clear', 'more', 'less', 'man']: |
|
399 | for cmd in ['clear', 'more', 'less', 'man']: | |
402 | self.alias_manager.soft_define_alias(cmd, cmd) |
|
400 | self.alias_manager.soft_define_alias(cmd, cmd) | |
403 |
|
401 | |||
404 |
|
402 | |||
405 | def __init__(self, *args, **kwargs): |
|
403 | def __init__(self, *args, **kwargs): | |
406 | super(TerminalInteractiveShell, self).__init__(*args, **kwargs) |
|
404 | super(TerminalInteractiveShell, self).__init__(*args, **kwargs) | |
407 | self.init_prompt_toolkit_cli() |
|
405 | self.init_prompt_toolkit_cli() | |
408 | self.init_term_title() |
|
406 | self.init_term_title() | |
409 | self.keep_running = True |
|
407 | self.keep_running = True | |
410 |
|
408 | |||
411 | self.debugger_history = InMemoryHistory() |
|
409 | self.debugger_history = InMemoryHistory() | |
412 |
|
410 | |||
413 | def ask_exit(self): |
|
411 | def ask_exit(self): | |
414 | self.keep_running = False |
|
412 | self.keep_running = False | |
415 |
|
413 | |||
416 | rl_next_input = None |
|
414 | rl_next_input = None | |
417 |
|
415 | |||
418 | def pre_prompt(self): |
|
416 | def pre_prompt(self): | |
419 | if self.rl_next_input: |
|
417 | if self.rl_next_input: | |
420 | # We can't set the buffer here, because it will be reset just after |
|
418 | # We can't set the buffer here, because it will be reset just after | |
421 | # this. Adding a callable to pre_run_callables does what we need |
|
419 | # this. Adding a callable to pre_run_callables does what we need | |
422 | # after the buffer is reset. |
|
420 | # after the buffer is reset. | |
423 | s = cast_unicode_py2(self.rl_next_input) |
|
421 | s = cast_unicode_py2(self.rl_next_input) | |
424 | def set_doc(): |
|
422 | def set_doc(): | |
425 | self.pt_cli.application.buffer.document = Document(s) |
|
423 | self.pt_cli.application.buffer.document = Document(s) | |
426 | if hasattr(self.pt_cli, 'pre_run_callables'): |
|
424 | if hasattr(self.pt_cli, 'pre_run_callables'): | |
427 | self.pt_cli.pre_run_callables.append(set_doc) |
|
425 | self.pt_cli.pre_run_callables.append(set_doc) | |
428 | else: |
|
426 | else: | |
429 | # Older version of prompt_toolkit; it's OK to set the document |
|
427 | # Older version of prompt_toolkit; it's OK to set the document | |
430 | # directly here. |
|
428 | # directly here. | |
431 | set_doc() |
|
429 | set_doc() | |
432 | self.rl_next_input = None |
|
430 | self.rl_next_input = None | |
433 |
|
431 | |||
434 | def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED): |
|
432 | def interact(self, display_banner=DISPLAY_BANNER_DEPRECATED): | |
435 |
|
433 | |||
436 | if display_banner is not DISPLAY_BANNER_DEPRECATED: |
|
434 | if display_banner is not DISPLAY_BANNER_DEPRECATED: | |
437 | warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) |
|
435 | warn('interact `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) | |
438 |
|
436 | |||
439 | self.keep_running = True |
|
437 | self.keep_running = True | |
440 | while self.keep_running: |
|
438 | while self.keep_running: | |
441 | print(self.separate_in, end='') |
|
439 | print(self.separate_in, end='') | |
442 |
|
440 | |||
443 | try: |
|
441 | try: | |
444 | code = self.prompt_for_code() |
|
442 | code = self.prompt_for_code() | |
445 | except EOFError: |
|
443 | except EOFError: | |
446 | if (not self.confirm_exit) \ |
|
444 | if (not self.confirm_exit) \ | |
447 | or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): |
|
445 | or self.ask_yes_no('Do you really want to exit ([y]/n)?','y','n'): | |
448 | self.ask_exit() |
|
446 | self.ask_exit() | |
449 |
|
447 | |||
450 | else: |
|
448 | else: | |
451 | if code: |
|
449 | if code: | |
452 | self.run_cell(code, store_history=True) |
|
450 | self.run_cell(code, store_history=True) | |
453 |
|
451 | |||
454 | def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED): |
|
452 | def mainloop(self, display_banner=DISPLAY_BANNER_DEPRECATED): | |
455 | # An extra layer of protection in case someone mashing Ctrl-C breaks |
|
453 | # An extra layer of protection in case someone mashing Ctrl-C breaks | |
456 | # out of our internal code. |
|
454 | # out of our internal code. | |
457 | if display_banner is not DISPLAY_BANNER_DEPRECATED: |
|
455 | if display_banner is not DISPLAY_BANNER_DEPRECATED: | |
458 | warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) |
|
456 | warn('mainloop `display_banner` argument is deprecated since IPython 5.0. Call `show_banner()` if needed.', DeprecationWarning, stacklevel=2) | |
459 | while True: |
|
457 | while True: | |
460 | try: |
|
458 | try: | |
461 | self.interact() |
|
459 | self.interact() | |
462 | break |
|
460 | break | |
463 | except KeyboardInterrupt as e: |
|
461 | except KeyboardInterrupt as e: | |
464 | print("\n%s escaped interact()\n" % type(e).__name__) |
|
462 | print("\n%s escaped interact()\n" % type(e).__name__) | |
465 | finally: |
|
463 | finally: | |
466 | # An interrupt during the eventloop will mess up the |
|
464 | # An interrupt during the eventloop will mess up the | |
467 | # internal state of the prompt_toolkit library. |
|
465 | # internal state of the prompt_toolkit library. | |
468 | # Stopping the eventloop fixes this, see |
|
466 | # Stopping the eventloop fixes this, see | |
469 | # https://github.com/ipython/ipython/pull/9867 |
|
467 | # https://github.com/ipython/ipython/pull/9867 | |
470 | if hasattr(self, '_eventloop'): |
|
468 | if hasattr(self, '_eventloop'): | |
471 | self._eventloop.stop() |
|
469 | self._eventloop.stop() | |
472 |
|
470 | |||
473 | _inputhook = None |
|
471 | _inputhook = None | |
474 | def inputhook(self, context): |
|
472 | def inputhook(self, context): | |
475 | if self._inputhook is not None: |
|
473 | if self._inputhook is not None: | |
476 | self._inputhook(context) |
|
474 | self._inputhook(context) | |
477 |
|
475 | |||
478 | active_eventloop = None |
|
476 | active_eventloop = None | |
479 | def enable_gui(self, gui=None): |
|
477 | def enable_gui(self, gui=None): | |
480 | if gui: |
|
478 | if gui: | |
481 | self.active_eventloop, self._inputhook =\ |
|
479 | self.active_eventloop, self._inputhook =\ | |
482 | get_inputhook_name_and_func(gui) |
|
480 | get_inputhook_name_and_func(gui) | |
483 | else: |
|
481 | else: | |
484 | self.active_eventloop = self._inputhook = None |
|
482 | self.active_eventloop = self._inputhook = None | |
485 |
|
483 | |||
486 | # Run !system commands directly, not through pipes, so terminal programs |
|
484 | # Run !system commands directly, not through pipes, so terminal programs | |
487 | # work correctly. |
|
485 | # work correctly. | |
488 | system = InteractiveShell.system_raw |
|
486 | system = InteractiveShell.system_raw | |
489 |
|
487 | |||
490 | def auto_rewrite_input(self, cmd): |
|
488 | def auto_rewrite_input(self, cmd): | |
491 | """Overridden from the parent class to use fancy rewriting prompt""" |
|
489 | """Overridden from the parent class to use fancy rewriting prompt""" | |
492 | if not self.show_rewritten_input: |
|
490 | if not self.show_rewritten_input: | |
493 | return |
|
491 | return | |
494 |
|
492 | |||
495 | tokens = self.prompts.rewrite_prompt_tokens() |
|
493 | tokens = self.prompts.rewrite_prompt_tokens() | |
496 | if self.pt_cli: |
|
494 | if self.pt_cli: | |
497 | self.pt_cli.print_tokens(tokens) |
|
495 | self.pt_cli.print_tokens(tokens) | |
498 | print(cmd) |
|
496 | print(cmd) | |
499 | else: |
|
497 | else: | |
500 | prompt = ''.join(s for t, s in tokens) |
|
498 | prompt = ''.join(s for t, s in tokens) | |
501 | print(prompt, cmd, sep='') |
|
499 | print(prompt, cmd, sep='') | |
502 |
|
500 | |||
503 | _prompts_before = None |
|
501 | _prompts_before = None | |
504 | def switch_doctest_mode(self, mode): |
|
502 | def switch_doctest_mode(self, mode): | |
505 | """Switch prompts to classic for %doctest_mode""" |
|
503 | """Switch prompts to classic for %doctest_mode""" | |
506 | if mode: |
|
504 | if mode: | |
507 | self._prompts_before = self.prompts |
|
505 | self._prompts_before = self.prompts | |
508 | self.prompts = ClassicPrompts(self) |
|
506 | self.prompts = ClassicPrompts(self) | |
509 | elif self._prompts_before: |
|
507 | elif self._prompts_before: | |
510 | self.prompts = self._prompts_before |
|
508 | self.prompts = self._prompts_before | |
511 | self._prompts_before = None |
|
509 | self._prompts_before = None | |
512 | self._update_layout() |
|
510 | self._update_layout() | |
513 |
|
511 | |||
514 |
|
512 | |||
515 | InteractiveShellABC.register(TerminalInteractiveShell) |
|
513 | InteractiveShellABC.register(TerminalInteractiveShell) | |
516 |
|
514 | |||
517 | if __name__ == '__main__': |
|
515 | if __name__ == '__main__': | |
518 | TerminalInteractiveShell.instance().interact() |
|
516 | TerminalInteractiveShell.instance().interact() |
@@ -1,594 +1,595 b'' | |||||
1 | """Patched version of standard library tokenize, to deal with various bugs. |
|
1 | """Patched version of standard library tokenize, to deal with various bugs. | |
2 |
|
2 | |||
3 | Based on Python 3.2 code. |
|
3 | Based on Python 3.2 code. | |
4 |
|
4 | |||
5 | Patches: |
|
5 | Patches: | |
6 |
|
6 | |||
7 | - Gareth Rees' patch for Python issue #12691 (untokenizing) |
|
7 | - Gareth Rees' patch for Python issue #12691 (untokenizing) | |
8 | - Except we don't encode the output of untokenize |
|
8 | - Except we don't encode the output of untokenize | |
9 | - Python 2 compatible syntax, so that it can be byte-compiled at installation |
|
9 | - Python 2 compatible syntax, so that it can be byte-compiled at installation | |
10 | - Newlines in comments and blank lines should be either NL or NEWLINE, depending |
|
10 | - Newlines in comments and blank lines should be either NL or NEWLINE, depending | |
11 | on whether they are in a multi-line statement. Filed as Python issue #17061. |
|
11 | on whether they are in a multi-line statement. Filed as Python issue #17061. | |
12 | - Export generate_tokens & TokenError |
|
12 | - Export generate_tokens & TokenError | |
13 | - u and rb literals are allowed under Python 3.3 and above. |
|
13 | - u and rb literals are allowed under Python 3.3 and above. | |
14 |
|
14 | |||
15 | ------------------------------------------------------------------------------ |
|
15 | ------------------------------------------------------------------------------ | |
16 | Tokenization help for Python programs. |
|
16 | Tokenization help for Python programs. | |
17 |
|
17 | |||
18 | tokenize(readline) is a generator that breaks a stream of bytes into |
|
18 | tokenize(readline) is a generator that breaks a stream of bytes into | |
19 | Python tokens. It decodes the bytes according to PEP-0263 for |
|
19 | Python tokens. It decodes the bytes according to PEP-0263 for | |
20 | determining source file encoding. |
|
20 | determining source file encoding. | |
21 |
|
21 | |||
22 | It accepts a readline-like method which is called repeatedly to get the |
|
22 | It accepts a readline-like method which is called repeatedly to get the | |
23 | next line of input (or b"" for EOF). It generates 5-tuples with these |
|
23 | next line of input (or b"" for EOF). It generates 5-tuples with these | |
24 | members: |
|
24 | members: | |
25 |
|
25 | |||
26 | the token type (see token.py) |
|
26 | the token type (see token.py) | |
27 | the token (a string) |
|
27 | the token (a string) | |
28 | the starting (row, column) indices of the token (a 2-tuple of ints) |
|
28 | the starting (row, column) indices of the token (a 2-tuple of ints) | |
29 | the ending (row, column) indices of the token (a 2-tuple of ints) |
|
29 | the ending (row, column) indices of the token (a 2-tuple of ints) | |
30 | the original line (string) |
|
30 | the original line (string) | |
31 |
|
31 | |||
32 | It is designed to match the working of the Python tokenizer exactly, except |
|
32 | It is designed to match the working of the Python tokenizer exactly, except | |
33 | that it produces COMMENT tokens for comments and gives type OP for all |
|
33 | that it produces COMMENT tokens for comments and gives type OP for all | |
34 | operators. Additionally, all token lists start with an ENCODING token |
|
34 | operators. Additionally, all token lists start with an ENCODING token | |
35 | which tells you which encoding was used to decode the bytes stream. |
|
35 | which tells you which encoding was used to decode the bytes stream. | |
36 | """ |
|
36 | """ | |
37 |
|
37 | |||
38 | __author__ = 'Ka-Ping Yee <ping@lfw.org>' |
|
38 | __author__ = 'Ka-Ping Yee <ping@lfw.org>' | |
39 | __credits__ = ('GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, ' |
|
39 | __credits__ = ('GvR, ESR, Tim Peters, Thomas Wouters, Fred Drake, ' | |
40 | 'Skip Montanaro, Raymond Hettinger, Trent Nelson, ' |
|
40 | 'Skip Montanaro, Raymond Hettinger, Trent Nelson, ' | |
41 | 'Michael Foord') |
|
41 | 'Michael Foord') | |
42 | import builtins |
|
42 | import builtins | |
43 | import re |
|
43 | import re | |
44 | import sys |
|
44 | import sys | |
45 | from token import * |
|
45 | from token import * | |
46 | from codecs import lookup, BOM_UTF8 |
|
46 | from codecs import lookup, BOM_UTF8 | |
47 | import collections |
|
47 | import collections | |
48 | from io import TextIOWrapper |
|
48 | from io import TextIOWrapper | |
49 | cookie_re = re.compile("coding[:=]\s*([-\w.]+)") |
|
49 | cookie_re = re.compile("coding[:=]\s*([-\w.]+)") | |
50 |
|
50 | |||
51 | import token |
|
51 | import token | |
52 | __all__ = token.__all__ + ["COMMENT", "tokenize", "detect_encoding", |
|
52 | __all__ = token.__all__ + ["COMMENT", "tokenize", "detect_encoding", | |
53 | "NL", "untokenize", "ENCODING", "TokenInfo"] |
|
53 | "NL", "untokenize", "ENCODING", "TokenInfo"] | |
54 | del token |
|
54 | del token | |
55 |
|
55 | |||
56 | __all__ += ["generate_tokens", "TokenError"] |
|
56 | __all__ += ["generate_tokens", "TokenError"] | |
57 |
|
57 | |||
58 | COMMENT = N_TOKENS |
|
58 | COMMENT = N_TOKENS | |
59 | tok_name[COMMENT] = 'COMMENT' |
|
59 | tok_name[COMMENT] = 'COMMENT' | |
60 | NL = N_TOKENS + 1 |
|
60 | NL = N_TOKENS + 1 | |
61 | tok_name[NL] = 'NL' |
|
61 | tok_name[NL] = 'NL' | |
62 | ENCODING = N_TOKENS + 2 |
|
62 | ENCODING = N_TOKENS + 2 | |
63 | tok_name[ENCODING] = 'ENCODING' |
|
63 | tok_name[ENCODING] = 'ENCODING' | |
64 | N_TOKENS += 3 |
|
64 | N_TOKENS += 3 | |
65 |
|
65 | |||
66 | class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')): |
|
66 | class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')): | |
67 | def __repr__(self): |
|
67 | def __repr__(self): | |
68 | annotated_type = '%d (%s)' % (self.type, tok_name[self.type]) |
|
68 | annotated_type = '%d (%s)' % (self.type, tok_name[self.type]) | |
69 | return ('TokenInfo(type=%s, string=%r, start=%r, end=%r, line=%r)' % |
|
69 | return ('TokenInfo(type=%s, string=%r, start=%r, end=%r, line=%r)' % | |
70 | self._replace(type=annotated_type)) |
|
70 | self._replace(type=annotated_type)) | |
71 |
|
71 | |||
72 | def group(*choices): return '(' + '|'.join(choices) + ')' |
|
72 | def group(*choices): return '(' + '|'.join(choices) + ')' | |
73 | def any(*choices): return group(*choices) + '*' |
|
73 | def any(*choices): return group(*choices) + '*' | |
74 | def maybe(*choices): return group(*choices) + '?' |
|
74 | def maybe(*choices): return group(*choices) + '?' | |
75 |
|
75 | |||
76 | # Note: we use unicode matching for names ("\w") but ascii matching for |
|
76 | # Note: we use unicode matching for names ("\w") but ascii matching for | |
77 | # number literals. |
|
77 | # number literals. | |
78 | Whitespace = r'[ \f\t]*' |
|
78 | Whitespace = r'[ \f\t]*' | |
79 | Comment = r'#[^\r\n]*' |
|
79 | Comment = r'#[^\r\n]*' | |
80 | Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) |
|
80 | Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) | |
81 | Name = r'\w+' |
|
81 | Name = r'\w+' | |
82 |
|
82 | |||
83 | Hexnumber = r'0[xX][0-9a-fA-F]+' |
|
83 | Hexnumber = r'0[xX][0-9a-fA-F]+' | |
84 | Binnumber = r'0[bB][01]+' |
|
84 | Binnumber = r'0[bB][01]+' | |
85 | Octnumber = r'0[oO][0-7]+' |
|
85 | Octnumber = r'0[oO][0-7]+' | |
86 | Decnumber = r'(?:0+|[1-9][0-9]*)' |
|
86 | Decnumber = r'(?:0+|[1-9][0-9]*)' | |
87 | Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber) |
|
87 | Intnumber = group(Hexnumber, Binnumber, Octnumber, Decnumber) | |
88 | Exponent = r'[eE][-+]?[0-9]+' |
|
88 | Exponent = r'[eE][-+]?[0-9]+' | |
89 | Pointfloat = group(r'[0-9]+\.[0-9]*', r'\.[0-9]+') + maybe(Exponent) |
|
89 | Pointfloat = group(r'[0-9]+\.[0-9]*', r'\.[0-9]+') + maybe(Exponent) | |
90 | Expfloat = r'[0-9]+' + Exponent |
|
90 | Expfloat = r'[0-9]+' + Exponent | |
91 | Floatnumber = group(Pointfloat, Expfloat) |
|
91 | Floatnumber = group(Pointfloat, Expfloat) | |
92 | Imagnumber = group(r'[0-9]+[jJ]', Floatnumber + r'[jJ]') |
|
92 | Imagnumber = group(r'[0-9]+[jJ]', Floatnumber + r'[jJ]') | |
93 | Number = group(Imagnumber, Floatnumber, Intnumber) |
|
93 | Number = group(Imagnumber, Floatnumber, Intnumber) | |
94 |
|
94 | |||
95 | if sys.version_info.minor >= 3: |
|
95 | if sys.version_info.minor >= 3: | |
96 | StringPrefix = r'(?:[bB][rR]?|[rR][bB]?|[uU])?' |
|
96 | StringPrefix = r'(?:[bB][rR]?|[rR][bB]?|[uU])?' | |
97 | else: |
|
97 | else: | |
98 | StringPrefix = r'(?:[bB]?[rR]?)?' |
|
98 | StringPrefix = r'(?:[bB]?[rR]?)?' | |
99 |
|
99 | |||
100 | # Tail end of ' string. |
|
100 | # Tail end of ' string. | |
101 | Single = r"[^'\\]*(?:\\.[^'\\]*)*'" |
|
101 | Single = r"[^'\\]*(?:\\.[^'\\]*)*'" | |
102 | # Tail end of " string. |
|
102 | # Tail end of " string. | |
103 | Double = r'[^"\\]*(?:\\.[^"\\]*)*"' |
|
103 | Double = r'[^"\\]*(?:\\.[^"\\]*)*"' | |
104 | # Tail end of ''' string. |
|
104 | # Tail end of ''' string. | |
105 | Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" |
|
105 | Single3 = r"[^'\\]*(?:(?:\\.|'(?!''))[^'\\]*)*'''" | |
106 | # Tail end of """ string. |
|
106 | # Tail end of """ string. | |
107 | Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' |
|
107 | Double3 = r'[^"\\]*(?:(?:\\.|"(?!""))[^"\\]*)*"""' | |
108 | Triple = group(StringPrefix + "'''", StringPrefix + '"""') |
|
108 | Triple = group(StringPrefix + "'''", StringPrefix + '"""') | |
109 | # Single-line ' or " string. |
|
109 | # Single-line ' or " string. | |
110 | String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", |
|
110 | String = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*'", | |
111 | StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') |
|
111 | StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*"') | |
112 |
|
112 | |||
113 | # Because of leftmost-then-longest match semantics, be sure to put the |
|
113 | # Because of leftmost-then-longest match semantics, be sure to put the | |
114 | # longest operators first (e.g., if = came before ==, == would get |
|
114 | # longest operators first (e.g., if = came before ==, == would get | |
115 | # recognized as two instances of =). |
|
115 | # recognized as two instances of =). | |
116 | Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"!=", |
|
116 | Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"!=", | |
117 | r"//=?", r"->", |
|
117 | r"//=?", r"->", | |
118 | r"[+\-*/%&|^=<>]=?", |
|
118 | r"[+\-*/%&|^=<>]=?", | |
119 | r"~") |
|
119 | r"~") | |
120 |
|
120 | |||
121 | Bracket = '[][(){}]' |
|
121 | Bracket = '[][(){}]' | |
122 | Special = group(r'\r?\n', r'\.\.\.', r'[:;.,@]') |
|
122 | Special = group(r'\r?\n', r'\.\.\.', r'[:;.,@]') | |
123 | Funny = group(Operator, Bracket, Special) |
|
123 | Funny = group(Operator, Bracket, Special) | |
124 |
|
124 | |||
125 | PlainToken = group(Number, Funny, String, Name) |
|
125 | PlainToken = group(Number, Funny, String, Name) | |
126 | Token = Ignore + PlainToken |
|
126 | Token = Ignore + PlainToken | |
127 |
|
127 | |||
128 | # First (or only) line of ' or " string. |
|
128 | # First (or only) line of ' or " string. | |
129 | ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + |
|
129 | ContStr = group(StringPrefix + r"'[^\n'\\]*(?:\\.[^\n'\\]*)*" + | |
130 | group("'", r'\\\r?\n'), |
|
130 | group("'", r'\\\r?\n'), | |
131 | StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + |
|
131 | StringPrefix + r'"[^\n"\\]*(?:\\.[^\n"\\]*)*' + | |
132 | group('"', r'\\\r?\n')) |
|
132 | group('"', r'\\\r?\n')) | |
133 | PseudoExtras = group(r'\\\r?\n', Comment, Triple) |
|
133 | PseudoExtras = group(r'\\\r?\n', Comment, Triple) | |
134 | PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) |
|
134 | PseudoToken = Whitespace + group(PseudoExtras, Number, Funny, ContStr, Name) | |
135 |
|
135 | |||
136 | def _compile(expr): |
|
136 | def _compile(expr): | |
137 | return re.compile(expr, re.UNICODE) |
|
137 | return re.compile(expr, re.UNICODE) | |
138 |
|
138 | |||
139 | tokenprog, pseudoprog, single3prog, double3prog = map( |
|
139 | tokenprog, pseudoprog, single3prog, double3prog = map( | |
140 | _compile, (Token, PseudoToken, Single3, Double3)) |
|
140 | _compile, (Token, PseudoToken, Single3, Double3)) | |
141 | endprogs = {"'": _compile(Single), '"': _compile(Double), |
|
141 | endprogs = {"'": _compile(Single), '"': _compile(Double), | |
142 | "'''": single3prog, '"""': double3prog, |
|
142 | "'''": single3prog, '"""': double3prog, | |
143 | "r'''": single3prog, 'r"""': double3prog, |
|
143 | "r'''": single3prog, 'r"""': double3prog, | |
144 | "b'''": single3prog, 'b"""': double3prog, |
|
144 | "b'''": single3prog, 'b"""': double3prog, | |
145 | "R'''": single3prog, 'R"""': double3prog, |
|
145 | "R'''": single3prog, 'R"""': double3prog, | |
146 | "B'''": single3prog, 'B"""': double3prog, |
|
146 | "B'''": single3prog, 'B"""': double3prog, | |
147 | "br'''": single3prog, 'br"""': double3prog, |
|
147 | "br'''": single3prog, 'br"""': double3prog, | |
148 | "bR'''": single3prog, 'bR"""': double3prog, |
|
148 | "bR'''": single3prog, 'bR"""': double3prog, | |
149 | "Br'''": single3prog, 'Br"""': double3prog, |
|
149 | "Br'''": single3prog, 'Br"""': double3prog, | |
150 | "BR'''": single3prog, 'BR"""': double3prog, |
|
150 | "BR'''": single3prog, 'BR"""': double3prog, | |
151 | 'r': None, 'R': None, 'b': None, 'B': None} |
|
151 | 'r': None, 'R': None, 'b': None, 'B': None} | |
152 |
|
152 | |||
153 | triple_quoted = {} |
|
153 | triple_quoted = {} | |
154 | for t in ("'''", '"""', |
|
154 | for t in ("'''", '"""', | |
155 | "r'''", 'r"""', "R'''", 'R"""', |
|
155 | "r'''", 'r"""', "R'''", 'R"""', | |
156 | "b'''", 'b"""', "B'''", 'B"""', |
|
156 | "b'''", 'b"""', "B'''", 'B"""', | |
157 | "br'''", 'br"""', "Br'''", 'Br"""', |
|
157 | "br'''", 'br"""', "Br'''", 'Br"""', | |
158 | "bR'''", 'bR"""', "BR'''", 'BR"""'): |
|
158 | "bR'''", 'bR"""', "BR'''", 'BR"""'): | |
159 | triple_quoted[t] = t |
|
159 | triple_quoted[t] = t | |
160 | single_quoted = {} |
|
160 | single_quoted = {} | |
161 | for t in ("'", '"', |
|
161 | for t in ("'", '"', | |
162 | "r'", 'r"', "R'", 'R"', |
|
162 | "r'", 'r"', "R'", 'R"', | |
163 | "b'", 'b"', "B'", 'B"', |
|
163 | "b'", 'b"', "B'", 'B"', | |
164 | "br'", 'br"', "Br'", 'Br"', |
|
164 | "br'", 'br"', "Br'", 'Br"', | |
165 | "bR'", 'bR"', "BR'", 'BR"' ): |
|
165 | "bR'", 'bR"', "BR'", 'BR"' ): | |
166 | single_quoted[t] = t |
|
166 | single_quoted[t] = t | |
167 |
|
167 | |||
168 | if sys.version_info.minor >= 3: |
|
168 | if sys.version_info.minor >= 3: | |
169 | # Python 3.3 |
|
169 | # Python 3.3 | |
170 | for _prefix in ['rb', 'rB', 'Rb', 'RB', 'u', 'U']: |
|
170 | for _prefix in ['rb', 'rB', 'Rb', 'RB', 'u', 'U']: | |
171 | _t2 = _prefix+'"""' |
|
171 | _t2 = _prefix+'"""' | |
172 | endprogs[_t2] = double3prog |
|
172 | endprogs[_t2] = double3prog | |
173 | triple_quoted[_t2] = _t2 |
|
173 | triple_quoted[_t2] = _t2 | |
174 | _t1 = _prefix + "'''" |
|
174 | _t1 = _prefix + "'''" | |
175 | endprogs[_t1] = single3prog |
|
175 | endprogs[_t1] = single3prog | |
176 | triple_quoted[_t1] = _t1 |
|
176 | triple_quoted[_t1] = _t1 | |
177 | single_quoted[_prefix+'"'] = _prefix+'"' |
|
177 | single_quoted[_prefix+'"'] = _prefix+'"' | |
178 | single_quoted[_prefix+"'"] = _prefix+"'" |
|
178 | single_quoted[_prefix+"'"] = _prefix+"'" | |
179 | del _prefix, _t2, _t1 |
|
179 | del _prefix, _t2, _t1 | |
180 | endprogs['u'] = None |
|
180 | endprogs['u'] = None | |
181 | endprogs['U'] = None |
|
181 | endprogs['U'] = None | |
182 |
|
182 | |||
183 | del _compile |
|
183 | del _compile | |
184 |
|
184 | |||
185 | tabsize = 8 |
|
185 | tabsize = 8 | |
186 |
|
186 | |||
187 | class TokenError(Exception): pass |
|
187 | class TokenError(Exception): pass | |
188 |
|
188 | |||
189 | class StopTokenizing(Exception): pass |
|
189 | class StopTokenizing(Exception): pass | |
190 |
|
190 | |||
191 |
|
191 | |||
192 | class Untokenizer: |
|
192 | class Untokenizer: | |
193 |
|
193 | |||
194 | def __init__(self): |
|
194 | def __init__(self): | |
195 | self.tokens = [] |
|
195 | self.tokens = [] | |
196 | self.prev_row = 1 |
|
196 | self.prev_row = 1 | |
197 | self.prev_col = 0 |
|
197 | self.prev_col = 0 | |
198 | self.encoding = 'utf-8' |
|
198 | self.encoding = 'utf-8' | |
199 |
|
199 | |||
200 | def add_whitespace(self, tok_type, start): |
|
200 | def add_whitespace(self, tok_type, start): | |
201 | row, col = start |
|
201 | row, col = start | |
202 | assert row >= self.prev_row |
|
202 | assert row >= self.prev_row | |
203 | col_offset = col - self.prev_col |
|
203 | col_offset = col - self.prev_col | |
204 | if col_offset > 0: |
|
204 | if col_offset > 0: | |
205 | self.tokens.append(" " * col_offset) |
|
205 | self.tokens.append(" " * col_offset) | |
206 | elif row > self.prev_row and tok_type not in (NEWLINE, NL, ENDMARKER): |
|
206 | elif row > self.prev_row and tok_type not in (NEWLINE, NL, ENDMARKER): | |
207 | # Line was backslash-continued. |
|
207 | # Line was backslash-continued. | |
208 | self.tokens.append(" ") |
|
208 | self.tokens.append(" ") | |
209 |
|
209 | |||
210 | def untokenize(self, tokens): |
|
210 | def untokenize(self, tokens): | |
211 | iterable = iter(tokens) |
|
211 | iterable = iter(tokens) | |
212 | for t in iterable: |
|
212 | for t in iterable: | |
213 | if len(t) == 2: |
|
213 | if len(t) == 2: | |
214 | self.compat(t, iterable) |
|
214 | self.compat(t, iterable) | |
215 | break |
|
215 | break | |
216 | tok_type, token, start, end = t[:4] |
|
216 | tok_type, token, start, end = t[:4] | |
217 | if tok_type == ENCODING: |
|
217 | if tok_type == ENCODING: | |
218 | self.encoding = token |
|
218 | self.encoding = token | |
219 | continue |
|
219 | continue | |
220 | self.add_whitespace(tok_type, start) |
|
220 | self.add_whitespace(tok_type, start) | |
221 | self.tokens.append(token) |
|
221 | self.tokens.append(token) | |
222 | self.prev_row, self.prev_col = end |
|
222 | self.prev_row, self.prev_col = end | |
223 | if tok_type in (NEWLINE, NL): |
|
223 | if tok_type in (NEWLINE, NL): | |
224 | self.prev_row += 1 |
|
224 | self.prev_row += 1 | |
225 | self.prev_col = 0 |
|
225 | self.prev_col = 0 | |
226 | return "".join(self.tokens) |
|
226 | return "".join(self.tokens) | |
227 |
|
227 | |||
228 | def compat(self, token, iterable): |
|
228 | def compat(self, token, iterable): | |
229 | # This import is here to avoid problems when the itertools |
|
229 | # This import is here to avoid problems when the itertools | |
230 | # module is not built yet and tokenize is imported. |
|
230 | # module is not built yet and tokenize is imported. | |
231 | from itertools import chain |
|
231 | from itertools import chain | |
232 | startline = False |
|
232 | startline = False | |
233 | prevstring = False |
|
233 | prevstring = False | |
234 | indents = [] |
|
234 | indents = [] | |
235 | toks_append = self.tokens.append |
|
235 | toks_append = self.tokens.append | |
236 |
|
236 | |||
237 | for tok in chain([token], iterable): |
|
237 | for tok in chain([token], iterable): | |
238 | toknum, tokval = tok[:2] |
|
238 | toknum, tokval = tok[:2] | |
239 | if toknum == ENCODING: |
|
239 | if toknum == ENCODING: | |
240 | self.encoding = tokval |
|
240 | self.encoding = tokval | |
241 | continue |
|
241 | continue | |
242 |
|
242 | |||
243 | if toknum in (NAME, NUMBER): |
|
243 | if toknum in (NAME, NUMBER): | |
244 | tokval += ' ' |
|
244 | tokval += ' ' | |
245 |
|
245 | |||
246 | # Insert a space between two consecutive strings |
|
246 | # Insert a space between two consecutive strings | |
247 | if toknum == STRING: |
|
247 | if toknum == STRING: | |
248 | if prevstring: |
|
248 | if prevstring: | |
249 | tokval = ' ' + tokval |
|
249 | tokval = ' ' + tokval | |
250 | prevstring = True |
|
250 | prevstring = True | |
251 | else: |
|
251 | else: | |
252 | prevstring = False |
|
252 | prevstring = False | |
253 |
|
253 | |||
254 | if toknum == INDENT: |
|
254 | if toknum == INDENT: | |
255 | indents.append(tokval) |
|
255 | indents.append(tokval) | |
256 | continue |
|
256 | continue | |
257 | elif toknum == DEDENT: |
|
257 | elif toknum == DEDENT: | |
258 | indents.pop() |
|
258 | indents.pop() | |
259 | continue |
|
259 | continue | |
260 | elif toknum in (NEWLINE, NL): |
|
260 | elif toknum in (NEWLINE, NL): | |
261 | startline = True |
|
261 | startline = True | |
262 | elif startline and indents: |
|
262 | elif startline and indents: | |
263 | toks_append(indents[-1]) |
|
263 | toks_append(indents[-1]) | |
264 | startline = False |
|
264 | startline = False | |
265 | toks_append(tokval) |
|
265 | toks_append(tokval) | |
266 |
|
266 | |||
267 |
|
267 | |||
268 | def untokenize(tokens): |
|
268 | def untokenize(tokens): | |
269 | """ |
|
269 | """ | |
270 | Convert ``tokens`` (an iterable) back into Python source code. Return |
|
270 | Convert ``tokens`` (an iterable) back into Python source code. Return | |
271 | a bytes object, encoded using the encoding specified by the last |
|
271 | a bytes object, encoded using the encoding specified by the last | |
272 | ENCODING token in ``tokens``, or UTF-8 if no ENCODING token is found. |
|
272 | ENCODING token in ``tokens``, or UTF-8 if no ENCODING token is found. | |
273 |
|
273 | |||
274 | The result is guaranteed to tokenize back to match the input so that |
|
274 | The result is guaranteed to tokenize back to match the input so that | |
275 | the conversion is lossless and round-trips are assured. The |
|
275 | the conversion is lossless and round-trips are assured. The | |
276 | guarantee applies only to the token type and token string as the |
|
276 | guarantee applies only to the token type and token string as the | |
277 | spacing between tokens (column positions) may change. |
|
277 | spacing between tokens (column positions) may change. | |
278 |
|
278 | |||
279 | :func:`untokenize` has two modes. If the input tokens are sequences |
|
279 | :func:`untokenize` has two modes. If the input tokens are sequences | |
280 | of length 2 (``type``, ``string``) then spaces are added as necessary to |
|
280 | of length 2 (``type``, ``string``) then spaces are added as necessary to | |
281 | preserve the round-trip property. |
|
281 | preserve the round-trip property. | |
282 |
|
282 | |||
283 | If the input tokens are sequences of length 4 or more (``type``, |
|
283 | If the input tokens are sequences of length 4 or more (``type``, | |
284 | ``string``, ``start``, ``end``), as returned by :func:`tokenize`, then |
|
284 | ``string``, ``start``, ``end``), as returned by :func:`tokenize`, then | |
285 | spaces are added so that each token appears in the result at the |
|
285 | spaces are added so that each token appears in the result at the | |
286 | position indicated by ``start`` and ``end``, if possible. |
|
286 | position indicated by ``start`` and ``end``, if possible. | |
287 | """ |
|
287 | """ | |
288 | return Untokenizer().untokenize(tokens) |
|
288 | return Untokenizer().untokenize(tokens) | |
289 |
|
289 | |||
290 |
|
290 | |||
291 | def _get_normal_name(orig_enc): |
|
291 | def _get_normal_name(orig_enc): | |
292 | """Imitates get_normal_name in tokenizer.c.""" |
|
292 | """Imitates get_normal_name in tokenizer.c.""" | |
293 | # Only care about the first 12 characters. |
|
293 | # Only care about the first 12 characters. | |
294 | enc = orig_enc[:12].lower().replace("_", "-") |
|
294 | enc = orig_enc[:12].lower().replace("_", "-") | |
295 | if enc == "utf-8" or enc.startswith("utf-8-"): |
|
295 | if enc == "utf-8" or enc.startswith("utf-8-"): | |
296 | return "utf-8" |
|
296 | return "utf-8" | |
297 | if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ |
|
297 | if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ | |
298 | enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): |
|
298 | enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): | |
299 | return "iso-8859-1" |
|
299 | return "iso-8859-1" | |
300 | return orig_enc |
|
300 | return orig_enc | |
301 |
|
301 | |||
302 | def detect_encoding(readline): |
|
302 | def detect_encoding(readline): | |
303 | """ |
|
303 | """ | |
304 | The detect_encoding() function is used to detect the encoding that should |
|
304 | The detect_encoding() function is used to detect the encoding that should | |
305 | be used to decode a Python source file. It requires one argment, readline, |
|
305 | be used to decode a Python source file. It requires one argment, readline, | |
306 | in the same way as the tokenize() generator. |
|
306 | in the same way as the tokenize() generator. | |
307 |
|
307 | |||
308 | It will call readline a maximum of twice, and return the encoding used |
|
308 | It will call readline a maximum of twice, and return the encoding used | |
309 | (as a string) and a list of any lines (left as bytes) it has read in. |
|
309 | (as a string) and a list of any lines (left as bytes) it has read in. | |
310 |
|
310 | |||
311 | It detects the encoding from the presence of a utf-8 bom or an encoding |
|
311 | It detects the encoding from the presence of a utf-8 bom or an encoding | |
312 | cookie as specified in pep-0263. If both a bom and a cookie are present, |
|
312 | cookie as specified in pep-0263. If both a bom and a cookie are present, | |
313 | but disagree, a SyntaxError will be raised. If the encoding cookie is an |
|
313 | but disagree, a SyntaxError will be raised. If the encoding cookie is an | |
314 | invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, |
|
314 | invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, | |
315 | 'utf-8-sig' is returned. |
|
315 | 'utf-8-sig' is returned. | |
316 |
|
316 | |||
317 | If no encoding is specified, then the default of 'utf-8' will be returned. |
|
317 | If no encoding is specified, then the default of 'utf-8' will be returned. | |
318 | """ |
|
318 | """ | |
319 | bom_found = False |
|
319 | bom_found = False | |
320 | encoding = None |
|
320 | encoding = None | |
321 | default = 'utf-8' |
|
321 | default = 'utf-8' | |
322 | def read_or_stop(): |
|
322 | def read_or_stop(): | |
323 | try: |
|
323 | try: | |
324 | return readline() |
|
324 | return readline() | |
325 | except StopIteration: |
|
325 | except StopIteration: | |
326 | return b'' |
|
326 | return b'' | |
327 |
|
327 | |||
328 | def find_cookie(line): |
|
328 | def find_cookie(line): | |
329 | try: |
|
329 | try: | |
330 | # Decode as UTF-8. Either the line is an encoding declaration, |
|
330 | # Decode as UTF-8. Either the line is an encoding declaration, | |
331 | # in which case it should be pure ASCII, or it must be UTF-8 |
|
331 | # in which case it should be pure ASCII, or it must be UTF-8 | |
332 | # per default encoding. |
|
332 | # per default encoding. | |
333 | line_string = line.decode('utf-8') |
|
333 | line_string = line.decode('utf-8') | |
334 | except UnicodeDecodeError: |
|
334 | except UnicodeDecodeError: | |
335 | raise SyntaxError("invalid or missing encoding declaration") |
|
335 | raise SyntaxError("invalid or missing encoding declaration") | |
336 |
|
336 | |||
337 | matches = cookie_re.findall(line_string) |
|
337 | matches = cookie_re.findall(line_string) | |
338 | if not matches: |
|
338 | if not matches: | |
339 | return None |
|
339 | return None | |
340 | encoding = _get_normal_name(matches[0]) |
|
340 | encoding = _get_normal_name(matches[0]) | |
341 | try: |
|
341 | try: | |
342 | codec = lookup(encoding) |
|
342 | codec = lookup(encoding) | |
343 | except LookupError: |
|
343 | except LookupError: | |
344 | # This behaviour mimics the Python interpreter |
|
344 | # This behaviour mimics the Python interpreter | |
345 | raise SyntaxError("unknown encoding: " + encoding) |
|
345 | raise SyntaxError("unknown encoding: " + encoding) | |
346 |
|
346 | |||
347 | if bom_found: |
|
347 | if bom_found: | |
348 | if encoding != 'utf-8': |
|
348 | if encoding != 'utf-8': | |
349 | # This behaviour mimics the Python interpreter |
|
349 | # This behaviour mimics the Python interpreter | |
350 | raise SyntaxError('encoding problem: utf-8') |
|
350 | raise SyntaxError('encoding problem: utf-8') | |
351 | encoding += '-sig' |
|
351 | encoding += '-sig' | |
352 | return encoding |
|
352 | return encoding | |
353 |
|
353 | |||
354 | first = read_or_stop() |
|
354 | first = read_or_stop() | |
355 | if first.startswith(BOM_UTF8): |
|
355 | if first.startswith(BOM_UTF8): | |
356 | bom_found = True |
|
356 | bom_found = True | |
357 | first = first[3:] |
|
357 | first = first[3:] | |
358 | default = 'utf-8-sig' |
|
358 | default = 'utf-8-sig' | |
359 | if not first: |
|
359 | if not first: | |
360 | return default, [] |
|
360 | return default, [] | |
361 |
|
361 | |||
362 | encoding = find_cookie(first) |
|
362 | encoding = find_cookie(first) | |
363 | if encoding: |
|
363 | if encoding: | |
364 | return encoding, [first] |
|
364 | return encoding, [first] | |
365 |
|
365 | |||
366 | second = read_or_stop() |
|
366 | second = read_or_stop() | |
367 | if not second: |
|
367 | if not second: | |
368 | return default, [first] |
|
368 | return default, [first] | |
369 |
|
369 | |||
370 | encoding = find_cookie(second) |
|
370 | encoding = find_cookie(second) | |
371 | if encoding: |
|
371 | if encoding: | |
372 | return encoding, [first, second] |
|
372 | return encoding, [first, second] | |
373 |
|
373 | |||
374 | return default, [first, second] |
|
374 | return default, [first, second] | |
375 |
|
375 | |||
376 |
|
376 | |||
377 | def open(filename): |
|
377 | def open(filename): | |
378 | """Open a file in read only mode using the encoding detected by |
|
378 | """Open a file in read only mode using the encoding detected by | |
379 | detect_encoding(). |
|
379 | detect_encoding(). | |
380 | """ |
|
380 | """ | |
381 | buffer = builtins.open(filename, 'rb') |
|
381 | buffer = builtins.open(filename, 'rb') | |
382 | encoding, lines = detect_encoding(buffer.readline) |
|
382 | encoding, lines = detect_encoding(buffer.readline) | |
383 | buffer.seek(0) |
|
383 | buffer.seek(0) | |
384 | text = TextIOWrapper(buffer, encoding, line_buffering=True) |
|
384 | text = TextIOWrapper(buffer, encoding, line_buffering=True) | |
385 | text.mode = 'r' |
|
385 | text.mode = 'r' | |
386 | return text |
|
386 | return text | |
387 |
|
387 | |||
388 |
|
388 | |||
389 | def tokenize(readline): |
|
389 | def tokenize(readline): | |
390 | """ |
|
390 | """ | |
391 | The tokenize() generator requires one argment, readline, which |
|
391 | The tokenize() generator requires one argment, readline, which | |
392 | must be a callable object which provides the same interface as the |
|
392 | must be a callable object which provides the same interface as the | |
393 | readline() method of built-in file objects. Each call to the function |
|
393 | readline() method of built-in file objects. Each call to the function | |
394 | should return one line of input as bytes. Alternately, readline |
|
394 | should return one line of input as bytes. Alternately, readline | |
395 | can be a callable function terminating with StopIteration: |
|
395 | can be a callable function terminating with :class:`StopIteration`:: | |
|
396 | ||||
396 | readline = open(myfile, 'rb').__next__ # Example of alternate readline |
|
397 | readline = open(myfile, 'rb').__next__ # Example of alternate readline | |
397 |
|
398 | |||
398 | The generator produces 5-tuples with these members: the token type; the |
|
399 | The generator produces 5-tuples with these members: the token type; the | |
399 | token string; a 2-tuple (srow, scol) of ints specifying the row and |
|
400 | token string; a 2-tuple (srow, scol) of ints specifying the row and | |
400 | column where the token begins in the source; a 2-tuple (erow, ecol) of |
|
401 | column where the token begins in the source; a 2-tuple (erow, ecol) of | |
401 | ints specifying the row and column where the token ends in the source; |
|
402 | ints specifying the row and column where the token ends in the source; | |
402 | and the line on which the token was found. The line passed is the |
|
403 | and the line on which the token was found. The line passed is the | |
403 | logical line; continuation lines are included. |
|
404 | logical line; continuation lines are included. | |
404 |
|
405 | |||
405 | The first token sequence will always be an ENCODING token |
|
406 | The first token sequence will always be an ENCODING token | |
406 | which tells you which encoding was used to decode the bytes stream. |
|
407 | which tells you which encoding was used to decode the bytes stream. | |
407 | """ |
|
408 | """ | |
408 | # This import is here to avoid problems when the itertools module is not |
|
409 | # This import is here to avoid problems when the itertools module is not | |
409 | # built yet and tokenize is imported. |
|
410 | # built yet and tokenize is imported. | |
410 | from itertools import chain, repeat |
|
411 | from itertools import chain, repeat | |
411 | encoding, consumed = detect_encoding(readline) |
|
412 | encoding, consumed = detect_encoding(readline) | |
412 | rl_gen = iter(readline, b"") |
|
413 | rl_gen = iter(readline, b"") | |
413 | empty = repeat(b"") |
|
414 | empty = repeat(b"") | |
414 | return _tokenize(chain(consumed, rl_gen, empty).__next__, encoding) |
|
415 | return _tokenize(chain(consumed, rl_gen, empty).__next__, encoding) | |
415 |
|
416 | |||
416 |
|
417 | |||
417 | def _tokenize(readline, encoding): |
|
418 | def _tokenize(readline, encoding): | |
418 | lnum = parenlev = continued = 0 |
|
419 | lnum = parenlev = continued = 0 | |
419 | numchars = '0123456789' |
|
420 | numchars = '0123456789' | |
420 | contstr, needcont = '', 0 |
|
421 | contstr, needcont = '', 0 | |
421 | contline = None |
|
422 | contline = None | |
422 | indents = [0] |
|
423 | indents = [0] | |
423 |
|
424 | |||
424 | if encoding is not None: |
|
425 | if encoding is not None: | |
425 | if encoding == "utf-8-sig": |
|
426 | if encoding == "utf-8-sig": | |
426 | # BOM will already have been stripped. |
|
427 | # BOM will already have been stripped. | |
427 | encoding = "utf-8" |
|
428 | encoding = "utf-8" | |
428 | yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '') |
|
429 | yield TokenInfo(ENCODING, encoding, (0, 0), (0, 0), '') | |
429 | while True: # loop over lines in stream |
|
430 | while True: # loop over lines in stream | |
430 | try: |
|
431 | try: | |
431 | line = readline() |
|
432 | line = readline() | |
432 | except StopIteration: |
|
433 | except StopIteration: | |
433 | line = b'' |
|
434 | line = b'' | |
434 |
|
435 | |||
435 | if encoding is not None: |
|
436 | if encoding is not None: | |
436 | line = line.decode(encoding) |
|
437 | line = line.decode(encoding) | |
437 | lnum += 1 |
|
438 | lnum += 1 | |
438 | pos, max = 0, len(line) |
|
439 | pos, max = 0, len(line) | |
439 |
|
440 | |||
440 | if contstr: # continued string |
|
441 | if contstr: # continued string | |
441 | if not line: |
|
442 | if not line: | |
442 | raise TokenError("EOF in multi-line string", strstart) |
|
443 | raise TokenError("EOF in multi-line string", strstart) | |
443 | endmatch = endprog.match(line) |
|
444 | endmatch = endprog.match(line) | |
444 | if endmatch: |
|
445 | if endmatch: | |
445 | pos = end = endmatch.end(0) |
|
446 | pos = end = endmatch.end(0) | |
446 | yield TokenInfo(STRING, contstr + line[:end], |
|
447 | yield TokenInfo(STRING, contstr + line[:end], | |
447 | strstart, (lnum, end), contline + line) |
|
448 | strstart, (lnum, end), contline + line) | |
448 | contstr, needcont = '', 0 |
|
449 | contstr, needcont = '', 0 | |
449 | contline = None |
|
450 | contline = None | |
450 | elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': |
|
451 | elif needcont and line[-2:] != '\\\n' and line[-3:] != '\\\r\n': | |
451 | yield TokenInfo(ERRORTOKEN, contstr + line, |
|
452 | yield TokenInfo(ERRORTOKEN, contstr + line, | |
452 | strstart, (lnum, len(line)), contline) |
|
453 | strstart, (lnum, len(line)), contline) | |
453 | contstr = '' |
|
454 | contstr = '' | |
454 | contline = None |
|
455 | contline = None | |
455 | continue |
|
456 | continue | |
456 | else: |
|
457 | else: | |
457 | contstr = contstr + line |
|
458 | contstr = contstr + line | |
458 | contline = contline + line |
|
459 | contline = contline + line | |
459 | continue |
|
460 | continue | |
460 |
|
461 | |||
461 | elif parenlev == 0 and not continued: # new statement |
|
462 | elif parenlev == 0 and not continued: # new statement | |
462 | if not line: break |
|
463 | if not line: break | |
463 | column = 0 |
|
464 | column = 0 | |
464 | while pos < max: # measure leading whitespace |
|
465 | while pos < max: # measure leading whitespace | |
465 | if line[pos] == ' ': |
|
466 | if line[pos] == ' ': | |
466 | column += 1 |
|
467 | column += 1 | |
467 | elif line[pos] == '\t': |
|
468 | elif line[pos] == '\t': | |
468 | column = (column//tabsize + 1)*tabsize |
|
469 | column = (column//tabsize + 1)*tabsize | |
469 | elif line[pos] == '\f': |
|
470 | elif line[pos] == '\f': | |
470 | column = 0 |
|
471 | column = 0 | |
471 | else: |
|
472 | else: | |
472 | break |
|
473 | break | |
473 | pos += 1 |
|
474 | pos += 1 | |
474 | if pos == max: |
|
475 | if pos == max: | |
475 | break |
|
476 | break | |
476 |
|
477 | |||
477 | if line[pos] in '#\r\n': # skip comments or blank lines |
|
478 | if line[pos] in '#\r\n': # skip comments or blank lines | |
478 | if line[pos] == '#': |
|
479 | if line[pos] == '#': | |
479 | comment_token = line[pos:].rstrip('\r\n') |
|
480 | comment_token = line[pos:].rstrip('\r\n') | |
480 | nl_pos = pos + len(comment_token) |
|
481 | nl_pos = pos + len(comment_token) | |
481 | yield TokenInfo(COMMENT, comment_token, |
|
482 | yield TokenInfo(COMMENT, comment_token, | |
482 | (lnum, pos), (lnum, pos + len(comment_token)), line) |
|
483 | (lnum, pos), (lnum, pos + len(comment_token)), line) | |
483 | yield TokenInfo(NEWLINE, line[nl_pos:], |
|
484 | yield TokenInfo(NEWLINE, line[nl_pos:], | |
484 | (lnum, nl_pos), (lnum, len(line)), line) |
|
485 | (lnum, nl_pos), (lnum, len(line)), line) | |
485 | else: |
|
486 | else: | |
486 | yield TokenInfo(NEWLINE, line[pos:], |
|
487 | yield TokenInfo(NEWLINE, line[pos:], | |
487 | (lnum, pos), (lnum, len(line)), line) |
|
488 | (lnum, pos), (lnum, len(line)), line) | |
488 | continue |
|
489 | continue | |
489 |
|
490 | |||
490 | if column > indents[-1]: # count indents or dedents |
|
491 | if column > indents[-1]: # count indents or dedents | |
491 | indents.append(column) |
|
492 | indents.append(column) | |
492 | yield TokenInfo(INDENT, line[:pos], (lnum, 0), (lnum, pos), line) |
|
493 | yield TokenInfo(INDENT, line[:pos], (lnum, 0), (lnum, pos), line) | |
493 | while column < indents[-1]: |
|
494 | while column < indents[-1]: | |
494 | if column not in indents: |
|
495 | if column not in indents: | |
495 | raise IndentationError( |
|
496 | raise IndentationError( | |
496 | "unindent does not match any outer indentation level", |
|
497 | "unindent does not match any outer indentation level", | |
497 | ("<tokenize>", lnum, pos, line)) |
|
498 | ("<tokenize>", lnum, pos, line)) | |
498 | indents = indents[:-1] |
|
499 | indents = indents[:-1] | |
499 | yield TokenInfo(DEDENT, '', (lnum, pos), (lnum, pos), line) |
|
500 | yield TokenInfo(DEDENT, '', (lnum, pos), (lnum, pos), line) | |
500 |
|
501 | |||
501 | else: # continued statement |
|
502 | else: # continued statement | |
502 | if not line: |
|
503 | if not line: | |
503 | raise TokenError("EOF in multi-line statement", (lnum, 0)) |
|
504 | raise TokenError("EOF in multi-line statement", (lnum, 0)) | |
504 | continued = 0 |
|
505 | continued = 0 | |
505 |
|
506 | |||
506 | while pos < max: |
|
507 | while pos < max: | |
507 | pseudomatch = pseudoprog.match(line, pos) |
|
508 | pseudomatch = pseudoprog.match(line, pos) | |
508 | if pseudomatch: # scan for tokens |
|
509 | if pseudomatch: # scan for tokens | |
509 | start, end = pseudomatch.span(1) |
|
510 | start, end = pseudomatch.span(1) | |
510 | spos, epos, pos = (lnum, start), (lnum, end), end |
|
511 | spos, epos, pos = (lnum, start), (lnum, end), end | |
511 | token, initial = line[start:end], line[start] |
|
512 | token, initial = line[start:end], line[start] | |
512 |
|
513 | |||
513 | if (initial in numchars or # ordinary number |
|
514 | if (initial in numchars or # ordinary number | |
514 | (initial == '.' and token != '.' and token != '...')): |
|
515 | (initial == '.' and token != '.' and token != '...')): | |
515 | yield TokenInfo(NUMBER, token, spos, epos, line) |
|
516 | yield TokenInfo(NUMBER, token, spos, epos, line) | |
516 | elif initial in '\r\n': |
|
517 | elif initial in '\r\n': | |
517 | yield TokenInfo(NL if parenlev > 0 else NEWLINE, |
|
518 | yield TokenInfo(NL if parenlev > 0 else NEWLINE, | |
518 | token, spos, epos, line) |
|
519 | token, spos, epos, line) | |
519 | elif initial == '#': |
|
520 | elif initial == '#': | |
520 | assert not token.endswith("\n") |
|
521 | assert not token.endswith("\n") | |
521 | yield TokenInfo(COMMENT, token, spos, epos, line) |
|
522 | yield TokenInfo(COMMENT, token, spos, epos, line) | |
522 | elif token in triple_quoted: |
|
523 | elif token in triple_quoted: | |
523 | endprog = endprogs[token] |
|
524 | endprog = endprogs[token] | |
524 | endmatch = endprog.match(line, pos) |
|
525 | endmatch = endprog.match(line, pos) | |
525 | if endmatch: # all on one line |
|
526 | if endmatch: # all on one line | |
526 | pos = endmatch.end(0) |
|
527 | pos = endmatch.end(0) | |
527 | token = line[start:pos] |
|
528 | token = line[start:pos] | |
528 | yield TokenInfo(STRING, token, spos, (lnum, pos), line) |
|
529 | yield TokenInfo(STRING, token, spos, (lnum, pos), line) | |
529 | else: |
|
530 | else: | |
530 | strstart = (lnum, start) # multiple lines |
|
531 | strstart = (lnum, start) # multiple lines | |
531 | contstr = line[start:] |
|
532 | contstr = line[start:] | |
532 | contline = line |
|
533 | contline = line | |
533 | break |
|
534 | break | |
534 | elif initial in single_quoted or \ |
|
535 | elif initial in single_quoted or \ | |
535 | token[:2] in single_quoted or \ |
|
536 | token[:2] in single_quoted or \ | |
536 | token[:3] in single_quoted: |
|
537 | token[:3] in single_quoted: | |
537 | if token[-1] == '\n': # continued string |
|
538 | if token[-1] == '\n': # continued string | |
538 | strstart = (lnum, start) |
|
539 | strstart = (lnum, start) | |
539 | endprog = (endprogs[initial] or endprogs[token[1]] or |
|
540 | endprog = (endprogs[initial] or endprogs[token[1]] or | |
540 | endprogs[token[2]]) |
|
541 | endprogs[token[2]]) | |
541 | contstr, needcont = line[start:], 1 |
|
542 | contstr, needcont = line[start:], 1 | |
542 | contline = line |
|
543 | contline = line | |
543 | break |
|
544 | break | |
544 | else: # ordinary string |
|
545 | else: # ordinary string | |
545 | yield TokenInfo(STRING, token, spos, epos, line) |
|
546 | yield TokenInfo(STRING, token, spos, epos, line) | |
546 | elif initial.isidentifier(): # ordinary name |
|
547 | elif initial.isidentifier(): # ordinary name | |
547 | yield TokenInfo(NAME, token, spos, epos, line) |
|
548 | yield TokenInfo(NAME, token, spos, epos, line) | |
548 | elif initial == '\\': # continued stmt |
|
549 | elif initial == '\\': # continued stmt | |
549 | continued = 1 |
|
550 | continued = 1 | |
550 | else: |
|
551 | else: | |
551 | if initial in '([{': |
|
552 | if initial in '([{': | |
552 | parenlev += 1 |
|
553 | parenlev += 1 | |
553 | elif initial in ')]}': |
|
554 | elif initial in ')]}': | |
554 | parenlev -= 1 |
|
555 | parenlev -= 1 | |
555 | yield TokenInfo(OP, token, spos, epos, line) |
|
556 | yield TokenInfo(OP, token, spos, epos, line) | |
556 | else: |
|
557 | else: | |
557 | yield TokenInfo(ERRORTOKEN, line[pos], |
|
558 | yield TokenInfo(ERRORTOKEN, line[pos], | |
558 | (lnum, pos), (lnum, pos+1), line) |
|
559 | (lnum, pos), (lnum, pos+1), line) | |
559 | pos += 1 |
|
560 | pos += 1 | |
560 |
|
561 | |||
561 | for indent in indents[1:]: # pop remaining indent levels |
|
562 | for indent in indents[1:]: # pop remaining indent levels | |
562 | yield TokenInfo(DEDENT, '', (lnum, 0), (lnum, 0), '') |
|
563 | yield TokenInfo(DEDENT, '', (lnum, 0), (lnum, 0), '') | |
563 | yield TokenInfo(ENDMARKER, '', (lnum, 0), (lnum, 0), '') |
|
564 | yield TokenInfo(ENDMARKER, '', (lnum, 0), (lnum, 0), '') | |
564 |
|
565 | |||
565 |
|
566 | |||
566 | # An undocumented, backwards compatible, API for all the places in the standard |
|
567 | # An undocumented, backwards compatible, API for all the places in the standard | |
567 | # library that expect to be able to use tokenize with strings |
|
568 | # library that expect to be able to use tokenize with strings | |
568 | def generate_tokens(readline): |
|
569 | def generate_tokens(readline): | |
569 | return _tokenize(readline, None) |
|
570 | return _tokenize(readline, None) | |
570 |
|
571 | |||
571 | if __name__ == "__main__": |
|
572 | if __name__ == "__main__": | |
572 | # Quick sanity check |
|
573 | # Quick sanity check | |
573 | s = b'''def parseline(self, line): |
|
574 | s = b'''def parseline(self, line): | |
574 | """Parse the line into a command name and a string containing |
|
575 | """Parse the line into a command name and a string containing | |
575 | the arguments. Returns a tuple containing (command, args, line). |
|
576 | the arguments. Returns a tuple containing (command, args, line). | |
576 | 'command' and 'args' may be None if the line couldn't be parsed. |
|
577 | 'command' and 'args' may be None if the line couldn't be parsed. | |
577 | """ |
|
578 | """ | |
578 | line = line.strip() |
|
579 | line = line.strip() | |
579 | if not line: |
|
580 | if not line: | |
580 | return None, None, line |
|
581 | return None, None, line | |
581 | elif line[0] == '?': |
|
582 | elif line[0] == '?': | |
582 | line = 'help ' + line[1:] |
|
583 | line = 'help ' + line[1:] | |
583 | elif line[0] == '!': |
|
584 | elif line[0] == '!': | |
584 | if hasattr(self, 'do_shell'): |
|
585 | if hasattr(self, 'do_shell'): | |
585 | line = 'shell ' + line[1:] |
|
586 | line = 'shell ' + line[1:] | |
586 | else: |
|
587 | else: | |
587 | return None, None, line |
|
588 | return None, None, line | |
588 | i, n = 0, len(line) |
|
589 | i, n = 0, len(line) | |
589 | while i < n and line[i] in self.identchars: i = i+1 |
|
590 | while i < n and line[i] in self.identchars: i = i+1 | |
590 | cmd, arg = line[:i], line[i:].strip() |
|
591 | cmd, arg = line[:i], line[i:].strip() | |
591 | return cmd, arg, line |
|
592 | return cmd, arg, line | |
592 | ''' |
|
593 | ''' | |
593 | for tok in tokenize(iter(s.splitlines()).__next__): |
|
594 | for tok in tokenize(iter(s.splitlines()).__next__): | |
594 | print(tok) |
|
595 | print(tok) |
@@ -1,127 +1,127 b'' | |||||
1 | """Token-related utilities""" |
|
1 | """Token-related utilities""" | |
2 |
|
2 | |||
3 | # Copyright (c) IPython Development Team. |
|
3 | # Copyright (c) IPython Development Team. | |
4 | # Distributed under the terms of the Modified BSD License. |
|
4 | # Distributed under the terms of the Modified BSD License. | |
5 |
|
5 | |||
6 |
|
6 | |||
7 | from collections import namedtuple |
|
7 | from collections import namedtuple | |
8 | from io import StringIO |
|
8 | from io import StringIO | |
9 | from keyword import iskeyword |
|
9 | from keyword import iskeyword | |
10 |
|
10 | |||
11 | from . import tokenize2 |
|
11 | from . import tokenize2 | |
12 | from .py3compat import cast_unicode_py2 |
|
12 | from .py3compat import cast_unicode_py2 | |
13 |
|
13 | |||
14 | Token = namedtuple('Token', ['token', 'text', 'start', 'end', 'line']) |
|
14 | Token = namedtuple('Token', ['token', 'text', 'start', 'end', 'line']) | |
15 |
|
15 | |||
16 | def generate_tokens(readline): |
|
16 | def generate_tokens(readline): | |
17 | """wrap generate_tokens to catch EOF errors""" |
|
17 | """wrap generate_tokens to catch EOF errors""" | |
18 | try: |
|
18 | try: | |
19 | for token in tokenize2.generate_tokens(readline): |
|
19 | for token in tokenize2.generate_tokens(readline): | |
20 | yield token |
|
20 | yield token | |
21 | except tokenize2.TokenError: |
|
21 | except tokenize2.TokenError: | |
22 | # catch EOF error |
|
22 | # catch EOF error | |
23 | return |
|
23 | return | |
24 |
|
24 | |||
25 | def line_at_cursor(cell, cursor_pos=0): |
|
25 | def line_at_cursor(cell, cursor_pos=0): | |
26 | """Return the line in a cell at a given cursor position |
|
26 | """Return the line in a cell at a given cursor position | |
27 |
|
27 | |||
28 | Used for calling line-based APIs that don't support multi-line input, yet. |
|
28 | Used for calling line-based APIs that don't support multi-line input, yet. | |
29 |
|
29 | |||
30 | Parameters |
|
30 | Parameters | |
31 | ---------- |
|
31 | ---------- | |
32 |
|
32 | |||
33 | cell: str |
|
33 | cell: str | |
34 | multiline block of text |
|
34 | multiline block of text | |
35 | cursor_pos: integer |
|
35 | cursor_pos: integer | |
36 | the cursor position |
|
36 | the cursor position | |
37 |
|
37 | |||
38 | Returns |
|
38 | Returns | |
39 | ------- |
|
39 | ------- | |
40 |
|
40 | |||
41 |
(line, offset): ( |
|
41 | (line, offset): (string, integer) | |
42 | The line with the current cursor, and the character offset of the start of the line. |
|
42 | The line with the current cursor, and the character offset of the start of the line. | |
43 | """ |
|
43 | """ | |
44 | offset = 0 |
|
44 | offset = 0 | |
45 | lines = cell.splitlines(True) |
|
45 | lines = cell.splitlines(True) | |
46 | for line in lines: |
|
46 | for line in lines: | |
47 | next_offset = offset + len(line) |
|
47 | next_offset = offset + len(line) | |
48 | if next_offset >= cursor_pos: |
|
48 | if next_offset >= cursor_pos: | |
49 | break |
|
49 | break | |
50 | offset = next_offset |
|
50 | offset = next_offset | |
51 | else: |
|
51 | else: | |
52 | line = "" |
|
52 | line = "" | |
53 | return (line, offset) |
|
53 | return (line, offset) | |
54 |
|
54 | |||
55 | def token_at_cursor(cell, cursor_pos=0): |
|
55 | def token_at_cursor(cell, cursor_pos=0): | |
56 | """Get the token at a given cursor |
|
56 | """Get the token at a given cursor | |
57 |
|
57 | |||
58 | Used for introspection. |
|
58 | Used for introspection. | |
59 |
|
59 | |||
60 | Function calls are prioritized, so the token for the callable will be returned |
|
60 | Function calls are prioritized, so the token for the callable will be returned | |
61 | if the cursor is anywhere inside the call. |
|
61 | if the cursor is anywhere inside the call. | |
62 |
|
62 | |||
63 | Parameters |
|
63 | Parameters | |
64 | ---------- |
|
64 | ---------- | |
65 |
|
65 | |||
66 | cell : unicode |
|
66 | cell : unicode | |
67 | A block of Python code |
|
67 | A block of Python code | |
68 | cursor_pos : int |
|
68 | cursor_pos : int | |
69 | The location of the cursor in the block where the token should be found |
|
69 | The location of the cursor in the block where the token should be found | |
70 | """ |
|
70 | """ | |
71 | cell = cast_unicode_py2(cell) |
|
71 | cell = cast_unicode_py2(cell) | |
72 | names = [] |
|
72 | names = [] | |
73 | tokens = [] |
|
73 | tokens = [] | |
74 | call_names = [] |
|
74 | call_names = [] | |
75 |
|
75 | |||
76 | offsets = {1: 0} # lines start at 1 |
|
76 | offsets = {1: 0} # lines start at 1 | |
77 | for tup in generate_tokens(StringIO(cell).readline): |
|
77 | for tup in generate_tokens(StringIO(cell).readline): | |
78 |
|
78 | |||
79 | tok = Token(*tup) |
|
79 | tok = Token(*tup) | |
80 |
|
80 | |||
81 | # token, text, start, end, line = tup |
|
81 | # token, text, start, end, line = tup | |
82 | start_line, start_col = tok.start |
|
82 | start_line, start_col = tok.start | |
83 | end_line, end_col = tok.end |
|
83 | end_line, end_col = tok.end | |
84 | if end_line + 1 not in offsets: |
|
84 | if end_line + 1 not in offsets: | |
85 | # keep track of offsets for each line |
|
85 | # keep track of offsets for each line | |
86 | lines = tok.line.splitlines(True) |
|
86 | lines = tok.line.splitlines(True) | |
87 | for lineno, line in enumerate(lines, start_line + 1): |
|
87 | for lineno, line in enumerate(lines, start_line + 1): | |
88 | if lineno not in offsets: |
|
88 | if lineno not in offsets: | |
89 | offsets[lineno] = offsets[lineno-1] + len(line) |
|
89 | offsets[lineno] = offsets[lineno-1] + len(line) | |
90 |
|
90 | |||
91 | offset = offsets[start_line] |
|
91 | offset = offsets[start_line] | |
92 | # allow '|foo' to find 'foo' at the beginning of a line |
|
92 | # allow '|foo' to find 'foo' at the beginning of a line | |
93 | boundary = cursor_pos + 1 if start_col == 0 else cursor_pos |
|
93 | boundary = cursor_pos + 1 if start_col == 0 else cursor_pos | |
94 | if offset + start_col >= boundary: |
|
94 | if offset + start_col >= boundary: | |
95 | # current token starts after the cursor, |
|
95 | # current token starts after the cursor, | |
96 | # don't consume it |
|
96 | # don't consume it | |
97 | break |
|
97 | break | |
98 |
|
98 | |||
99 | if tok.token == tokenize2.NAME and not iskeyword(tok.text): |
|
99 | if tok.token == tokenize2.NAME and not iskeyword(tok.text): | |
100 | if names and tokens and tokens[-1].token == tokenize2.OP and tokens[-1].text == '.': |
|
100 | if names and tokens and tokens[-1].token == tokenize2.OP and tokens[-1].text == '.': | |
101 | names[-1] = "%s.%s" % (names[-1], tok.text) |
|
101 | names[-1] = "%s.%s" % (names[-1], tok.text) | |
102 | else: |
|
102 | else: | |
103 | names.append(tok.text) |
|
103 | names.append(tok.text) | |
104 | elif tok.token == tokenize2.OP: |
|
104 | elif tok.token == tokenize2.OP: | |
105 | if tok.text == '=' and names: |
|
105 | if tok.text == '=' and names: | |
106 | # don't inspect the lhs of an assignment |
|
106 | # don't inspect the lhs of an assignment | |
107 | names.pop(-1) |
|
107 | names.pop(-1) | |
108 | if tok.text == '(' and names: |
|
108 | if tok.text == '(' and names: | |
109 | # if we are inside a function call, inspect the function |
|
109 | # if we are inside a function call, inspect the function | |
110 | call_names.append(names[-1]) |
|
110 | call_names.append(names[-1]) | |
111 | elif tok.text == ')' and call_names: |
|
111 | elif tok.text == ')' and call_names: | |
112 | call_names.pop(-1) |
|
112 | call_names.pop(-1) | |
113 |
|
113 | |||
114 | tokens.append(tok) |
|
114 | tokens.append(tok) | |
115 |
|
115 | |||
116 | if offsets[end_line] + end_col > cursor_pos: |
|
116 | if offsets[end_line] + end_col > cursor_pos: | |
117 | # we found the cursor, stop reading |
|
117 | # we found the cursor, stop reading | |
118 | break |
|
118 | break | |
119 |
|
119 | |||
120 | if call_names: |
|
120 | if call_names: | |
121 | return call_names[-1] |
|
121 | return call_names[-1] | |
122 | elif names: |
|
122 | elif names: | |
123 | return names[-1] |
|
123 | return names[-1] | |
124 | else: |
|
124 | else: | |
125 | return '' |
|
125 | return '' | |
126 |
|
126 | |||
127 |
|
127 |
@@ -1,230 +1,230 b'' | |||||
1 | ======================= |
|
1 | ======================= | |
2 | Specific config details |
|
2 | Specific config details | |
3 | ======================= |
|
3 | ======================= | |
4 |
|
4 | |||
5 | .. _custom_prompts: |
|
5 | .. _custom_prompts: | |
6 |
|
6 | |||
7 | Custom Prompts |
|
7 | Custom Prompts | |
8 | ============== |
|
8 | ============== | |
9 |
|
9 | |||
10 | .. versionchanged:: 5.0 |
|
10 | .. versionchanged:: 5.0 | |
11 |
|
11 | |||
12 | From IPython 5, prompts are produced as a list of Pygments tokens, which are |
|
12 | From IPython 5, prompts are produced as a list of Pygments tokens, which are | |
13 | tuples of (token_type, text). You can customise prompts by writing a method |
|
13 | tuples of (token_type, text). You can customise prompts by writing a method | |
14 | which generates a list of tokens. |
|
14 | which generates a list of tokens. | |
15 |
|
15 | |||
16 | There are four kinds of prompt: |
|
16 | There are four kinds of prompt: | |
17 |
|
17 | |||
18 | * The **in** prompt is shown before the first line of input |
|
18 | * The **in** prompt is shown before the first line of input | |
19 | (default like ``In [1]:``). |
|
19 | (default like ``In [1]:``). | |
20 | * The **continuation** prompt is shown before further lines of input |
|
20 | * The **continuation** prompt is shown before further lines of input | |
21 | (default like ``...:``). |
|
21 | (default like ``...:``). | |
22 | * The **rewrite** prompt is shown to highlight how special syntax has been |
|
22 | * The **rewrite** prompt is shown to highlight how special syntax has been | |
23 | interpreted (default like ``----->``). |
|
23 | interpreted (default like ``----->``). | |
24 | * The **out** prompt is shown before the result from evaluating the input |
|
24 | * The **out** prompt is shown before the result from evaluating the input | |
25 | (default like ``Out[1]:``). |
|
25 | (default like ``Out[1]:``). | |
26 |
|
26 | |||
27 | Custom prompts are supplied together as a class. If you want to customise only |
|
27 | Custom prompts are supplied together as a class. If you want to customise only | |
28 | some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`, |
|
28 | some of the prompts, inherit from :class:`IPython.terminal.prompts.Prompts`, | |
29 | which defines the defaults. The required interface is like this: |
|
29 | which defines the defaults. The required interface is like this: | |
30 |
|
30 | |||
31 | .. class:: MyPrompts(shell) |
|
31 | .. class:: MyPrompts(shell) | |
32 |
|
32 | |||
33 | Prompt style definition. *shell* is a reference to the |
|
33 | Prompt style definition. *shell* is a reference to the | |
34 | :class:`~.TerminalInteractiveShell` instance. |
|
34 | :class:`~.TerminalInteractiveShell` instance. | |
35 |
|
35 | |||
36 | .. method:: in_prompt_tokens(cli=None) |
|
36 | .. method:: in_prompt_tokens(cli=None) | |
37 | continuation_prompt_tokens(self, cli=None, width=None) |
|
37 | continuation_prompt_tokens(self, cli=None, width=None) | |
38 | rewrite_prompt_tokens() |
|
38 | rewrite_prompt_tokens() | |
39 | out_prompt_tokens() |
|
39 | out_prompt_tokens() | |
40 |
|
40 | |||
41 | Return the respective prompts as lists of ``(token_type, text)`` tuples. |
|
41 | Return the respective prompts as lists of ``(token_type, text)`` tuples. | |
42 |
|
42 | |||
43 | For continuation prompts, *width* is an integer representing the width of |
|
43 | For continuation prompts, *width* is an integer representing the width of | |
44 | the prompt area in terminal columns. |
|
44 | the prompt area in terminal columns. | |
45 |
|
45 | |||
46 | *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance. |
|
46 | *cli*, where used, is the prompt_toolkit ``CommandLineInterface`` instance. | |
47 | This is mainly for compatibility with the API prompt_toolkit expects. |
|
47 | This is mainly for compatibility with the API prompt_toolkit expects. | |
48 |
|
48 | |||
49 | Here is an example Prompt class that will show the current working directory |
|
49 | Here is an example Prompt class that will show the current working directory | |
50 | in the input prompt: |
|
50 | in the input prompt: | |
51 |
|
51 | |||
52 | .. code-block:: python |
|
52 | .. code-block:: python | |
53 |
|
53 | |||
54 | from IPython.terminal.prompts import Prompts, Token |
|
54 | from IPython.terminal.prompts import Prompts, Token | |
55 | import os |
|
55 | import os | |
56 |
|
56 | |||
57 | class MyPrompt(Prompts): |
|
57 | class MyPrompt(Prompts): | |
58 | def in_prompt_tokens(self, cli=None): |
|
58 | def in_prompt_tokens(self, cli=None): | |
59 | return [(Token, os.getcwd()), |
|
59 | return [(Token, os.getcwd()), | |
60 | (Token.Prompt, ' >>>')] |
|
60 | (Token.Prompt, ' >>>')] | |
61 |
|
61 | |||
62 | To set the new prompt, assign it to the ``prompts`` attribute of the IPython |
|
62 | To set the new prompt, assign it to the ``prompts`` attribute of the IPython | |
63 | shell: |
|
63 | shell: | |
64 |
|
64 | |||
65 | .. code-block:: python |
|
65 | .. code-block:: python | |
66 |
|
66 | |||
67 | In [2]: ip = get_ipython() |
|
67 | In [2]: ip = get_ipython() | |
68 | ...: ip.prompts = MyPrompt(ip) |
|
68 | ...: ip.prompts = MyPrompt(ip) | |
69 |
|
69 | |||
70 | /home/bob >>> # it works |
|
70 | /home/bob >>> # it works | |
71 |
|
71 | |||
72 | See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an |
|
72 | See ``IPython/example/utils/cwd_prompt.py`` for an example of how to write an | |
73 | extensions to customise prompts. |
|
73 | extensions to customise prompts. | |
74 |
|
74 | |||
75 | Inside IPython or in a startup script, you can use a custom prompts class |
|
75 | Inside IPython or in a startup script, you can use a custom prompts class | |
76 | by setting ``get_ipython().prompts`` to an *instance* of the class. |
|
76 | by setting ``get_ipython().prompts`` to an *instance* of the class. | |
77 | In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to |
|
77 | In configuration, ``TerminalInteractiveShell.prompts_class`` may be set to | |
78 | either the class object, or a string of its full importable name. |
|
78 | either the class object, or a string of its full importable name. | |
79 |
|
79 | |||
80 | To include invisible terminal control sequences in a prompt, use |
|
80 | To include invisible terminal control sequences in a prompt, use | |
81 | ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored |
|
81 | ``Token.ZeroWidthEscape`` as the token type. Tokens with this type are ignored | |
82 | when calculating the width. |
|
82 | when calculating the width. | |
83 |
|
83 | |||
84 | Colours in the prompt are determined by the token types and the highlighting |
|
84 | Colours in the prompt are determined by the token types and the highlighting | |
85 | style; see below for more details. The tokens used in the default prompts are |
|
85 | style; see below for more details. The tokens used in the default prompts are | |
86 | ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``. |
|
86 | ``Prompt``, ``PromptNum``, ``OutPrompt`` and ``OutPromptNum``. | |
87 |
|
87 | |||
88 | .. _termcolour: |
|
88 | .. _termcolour: | |
89 |
|
89 | |||
90 | Terminal Colors |
|
90 | Terminal Colors | |
91 | =============== |
|
91 | =============== | |
92 |
|
92 | |||
93 | .. versionchanged:: 5.0 |
|
93 | .. versionchanged:: 5.0 | |
94 |
|
94 | |||
95 | There are two main configuration options controlling colours. |
|
95 | There are two main configuration options controlling colours. | |
96 |
|
96 | |||
97 | ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the |
|
97 | ``InteractiveShell.colors`` sets the colour of tracebacks and object info (the | |
98 | output from e.g. ``zip?``). It may also affect other things if the option below |
|
98 | output from e.g. ``zip?``). It may also affect other things if the option below | |
99 | is set to ``'legacy'``. It has four case-insensitive values: |
|
99 | is set to ``'legacy'``. It has four case-insensitive values: | |
100 | ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which |
|
100 | ``'nocolor', 'neutral', 'linux', 'lightbg'``. The default is *neutral*, which | |
101 | should be legible on either dark or light terminal backgrounds. *linux* is |
|
101 | should be legible on either dark or light terminal backgrounds. *linux* is | |
102 | optimised for dark backgrounds and *lightbg* for light ones. |
|
102 | optimised for dark backgrounds and *lightbg* for light ones. | |
103 |
|
103 | |||
104 | ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and |
|
104 | ``TerminalInteractiveShell.highlighting_style`` determines prompt colours and | |
105 | syntax highlighting. It takes the name (as a string) or class (as a subclass of |
|
105 | syntax highlighting. It takes the name (as a string) or class (as a subclass of | |
106 | ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'`` |
|
106 | ``pygments.style.Style``) of a Pygments style, or the special value ``'legacy'`` | |
107 | to pick a style in accordance with ``InteractiveShell.colors``. |
|
107 | to pick a style in accordance with ``InteractiveShell.colors``. | |
108 |
|
108 | |||
109 | You can see the Pygments styles available on your system by running:: |
|
109 | You can see the Pygments styles available on your system by running:: | |
110 |
|
110 | |||
111 | import pygments |
|
111 | import pygments | |
112 | list(pygments.styles.get_all_styles()) |
|
112 | list(pygments.styles.get_all_styles()) | |
113 |
|
113 | |||
114 | Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override |
|
114 | Additionally, ``TerminalInteractiveShell.highlighting_style_overrides`` can override | |
115 | specific styles in the highlighting. It should be a dictionary mapping Pygments |
|
115 | specific styles in the highlighting. It should be a dictionary mapping Pygments | |
116 | token types to strings defining the style. See `Pygments' documentation |
|
116 | token types to strings defining the style. See `Pygments' documentation | |
117 | <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used |
|
117 | <http://pygments.org/docs/styles/#creating-own-styles>`__ for the language used | |
118 | to define styles. |
|
118 | to define styles. | |
119 |
|
119 | |||
120 | Colors in the pager |
|
120 | Colors in the pager | |
121 | ------------------- |
|
121 | ------------------- | |
122 |
|
122 | |||
123 | On some systems, the default pager has problems with ANSI colour codes. |
|
123 | On some systems, the default pager has problems with ANSI colour codes. | |
124 | To configure your default pager to allow these: |
|
124 | To configure your default pager to allow these: | |
125 |
|
125 | |||
126 | 1. Set the environment PAGER variable to ``less``. |
|
126 | 1. Set the environment PAGER variable to ``less``. | |
127 | 2. Set the environment LESS variable to ``-r`` (plus any other options |
|
127 | 2. Set the environment LESS variable to ``-r`` (plus any other options | |
128 | you always want to pass to less by default). This tells less to |
|
128 | you always want to pass to less by default). This tells less to | |
129 | properly interpret control sequences, which is how color |
|
129 | properly interpret control sequences, which is how color | |
130 | information is given to your terminal. |
|
130 | information is given to your terminal. | |
131 |
|
131 | |||
132 | .. _editors: |
|
132 | .. _editors: | |
133 |
|
133 | |||
134 | Editor configuration |
|
134 | Editor configuration | |
135 | ==================== |
|
135 | ==================== | |
136 |
|
136 | |||
137 | IPython can integrate with text editors in a number of different ways: |
|
137 | IPython can integrate with text editors in a number of different ways: | |
138 |
|
138 | |||
139 | * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can |
|
139 | * Editors (such as `(X)Emacs`_, vim_ and TextMate_) can | |
140 | send code to IPython for execution. |
|
140 | send code to IPython for execution. | |
141 |
|
141 | |||
142 | * IPython's ``%edit`` magic command can open an editor of choice to edit |
|
142 | * IPython's ``%edit`` magic command can open an editor of choice to edit | |
143 | a code block. |
|
143 | a code block. | |
144 |
|
144 | |||
145 | The %edit command (and its alias %ed) will invoke the editor set in your |
|
145 | The %edit command (and its alias %ed) will invoke the editor set in your | |
146 | environment as :envvar:`EDITOR`. If this variable is not set, it will default |
|
146 | environment as :envvar:`EDITOR`. If this variable is not set, it will default | |
147 | to vi under Linux/Unix and to notepad under Windows. You may want to set this |
|
147 | to vi under Linux/Unix and to notepad under Windows. You may want to set this | |
148 | variable properly and to a lightweight editor which doesn't take too long to |
|
148 | variable properly and to a lightweight editor which doesn't take too long to | |
149 | start (that is, something other than a new instance of Emacs). This way you |
|
149 | start (that is, something other than a new instance of Emacs). This way you | |
150 | can edit multi-line code quickly and with the power of a real editor right |
|
150 | can edit multi-line code quickly and with the power of a real editor right | |
151 | inside IPython. |
|
151 | inside IPython. | |
152 |
|
152 | |||
153 | You can also control the editor by setting :attr:`TerminalInteractiveShell.editor` |
|
153 | You can also control the editor by setting :attr:`TerminalInteractiveShell.editor` | |
154 | in :file:`ipython_config.py`. |
|
154 | in :file:`ipython_config.py`. | |
155 |
|
155 | |||
156 | Vim |
|
156 | Vim | |
157 | --- |
|
157 | --- | |
158 |
|
158 | |||
159 | Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides |
|
159 | Paul Ivanov's `vim-ipython <https://github.com/ivanov/vim-ipython>`_ provides | |
160 | powerful IPython integration for vim. |
|
160 | powerful IPython integration for vim. | |
161 |
|
161 | |||
162 | .. _emacs: |
|
162 | .. _emacs: | |
163 |
|
163 | |||
164 | (X)Emacs |
|
164 | (X)Emacs | |
165 | -------- |
|
165 | -------- | |
166 |
|
166 | |||
167 | If you are a dedicated Emacs user, and want to use Emacs when IPython's |
|
167 | If you are a dedicated Emacs user, and want to use Emacs when IPython's | |
168 | ``%edit`` magic command is called you should set up the Emacs server so that |
|
168 | ``%edit`` magic command is called you should set up the Emacs server so that | |
169 | new requests are handled by the original process. This means that almost no |
|
169 | new requests are handled by the original process. This means that almost no | |
170 | time is spent in handling the request (assuming an Emacs process is already |
|
170 | time is spent in handling the request (assuming an Emacs process is already | |
171 | running). For this to work, you need to set your EDITOR environment variable |
|
171 | running). For this to work, you need to set your EDITOR environment variable | |
172 | to 'emacsclient'. The code below, supplied by Francois Pinard, can then be |
|
172 | to 'emacsclient'. The code below, supplied by Francois Pinard, can then be | |
173 | used in your :file:`.emacs` file to enable the server: |
|
173 | used in your :file:`.emacs` file to enable the server: | |
174 |
|
174 | |||
175 | .. code-block:: common-lisp |
|
175 | .. code-block:: common-lisp | |
176 |
|
176 | |||
177 | (defvar server-buffer-clients) |
|
177 | (defvar server-buffer-clients) | |
178 | (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm)) |
|
178 | (when (and (fboundp 'server-start) (string-equal (getenv "TERM") 'xterm)) | |
179 | (server-start) |
|
179 | (server-start) | |
180 | (defun fp-kill-server-with-buffer-routine () |
|
180 | (defun fp-kill-server-with-buffer-routine () | |
181 | (and server-buffer-clients (server-done))) |
|
181 | (and server-buffer-clients (server-done))) | |
182 | (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine)) |
|
182 | (add-hook 'kill-buffer-hook 'fp-kill-server-with-buffer-routine)) | |
183 |
|
183 | |||
184 | Thanks to the work of Alexander Schmolck and Prabhu Ramachandran, |
|
184 | Thanks to the work of Alexander Schmolck and Prabhu Ramachandran, | |
185 | currently (X)Emacs and IPython get along very well in other ways. |
|
185 | currently (X)Emacs and IPython get along very well in other ways. | |
186 |
|
186 | |||
187 | With (X)EMacs >= 24, You can enable IPython in python-mode with: |
|
187 | With (X)EMacs >= 24, You can enable IPython in python-mode with: | |
188 |
|
188 | |||
189 | .. code-block:: common-lisp |
|
189 | .. code-block:: common-lisp | |
190 |
|
190 | |||
191 | (require 'python) |
|
191 | (require 'python) | |
192 | (setq python-shell-interpreter "ipython") |
|
192 | (setq python-shell-interpreter "ipython") | |
193 |
|
193 | |||
194 | .. _`(X)Emacs`: http://www.gnu.org/software/emacs/ |
|
194 | .. _`(X)Emacs`: http://www.gnu.org/software/emacs/ | |
195 | .. _TextMate: http://macromates.com/ |
|
195 | .. _TextMate: http://macromates.com/ | |
196 | .. _vim: http://www.vim.org/ |
|
196 | .. _vim: http://www.vim.org/ | |
197 |
|
197 | |||
198 | .. _custom_keyboard_shortcuts |
|
198 | .. _custom_keyboard_shortcuts: | |
199 |
|
199 | |||
200 | Keyboard Shortcuts |
|
200 | Keyboard Shortcuts | |
201 | ================== |
|
201 | ================== | |
202 |
|
202 | |||
203 |
|
|
203 | .. versionchanged:: 5.0 | |
204 |
|
204 | |||
205 | You can customise keyboard shortcuts for terminal IPython. Put code like this in |
|
205 | You can customise keyboard shortcuts for terminal IPython. Put code like this in | |
206 | a :ref:`startup file <startup_files>`:: |
|
206 | a :ref:`startup file <startup_files>`:: | |
207 |
|
207 | |||
208 | from IPython import get_ipython |
|
208 | from IPython import get_ipython | |
209 | from prompt_toolkit.enums import DEFAULT_BUFFER |
|
209 | from prompt_toolkit.enums import DEFAULT_BUFFER | |
210 | from prompt_toolkit.keys import Keys |
|
210 | from prompt_toolkit.keys import Keys | |
211 | from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode |
|
211 | from prompt_toolkit.filters import HasFocus, HasSelection, ViInsertMode, EmacsInsertMode | |
212 |
|
212 | |||
213 | ip = get_ipython() |
|
213 | ip = get_ipython() | |
214 | insert_mode = ViInsertMode() | EmacsInsertMode() |
|
214 | insert_mode = ViInsertMode() | EmacsInsertMode() | |
215 |
|
215 | |||
216 | def insert_unexpected(event): |
|
216 | def insert_unexpected(event): | |
217 | buf = event.current_buffer |
|
217 | buf = event.current_buffer | |
218 | buf.insert_text('The Spanish Inquisition') |
|
218 | buf.insert_text('The Spanish Inquisition') | |
219 |
|
219 | |||
220 | # Register the shortcut if IPython is using prompt_toolkit |
|
220 | # Register the shortcut if IPython is using prompt_toolkit | |
221 | if getattr(ip, 'pt_cli'): |
|
221 | if getattr(ip, 'pt_cli'): | |
222 | registry = ip.pt_cli.application.key_bindings_registry |
|
222 | registry = ip.pt_cli.application.key_bindings_registry | |
223 | registry.add_binding(Keys.ControlN, |
|
223 | registry.add_binding(Keys.ControlN, | |
224 | filter=(HasFocus(DEFAULT_BUFFER) |
|
224 | filter=(HasFocus(DEFAULT_BUFFER) | |
225 | & ~HasSelection() |
|
225 | & ~HasSelection() | |
226 | & insert_mode))(insert_unexpected) |
|
226 | & insert_mode))(insert_unexpected) | |
227 |
|
227 | |||
228 | For more information on filters and what you can do with the ``event`` object, |
|
228 | For more information on filters and what you can do with the ``event`` object, | |
229 | `see the prompt_toolkit docs |
|
229 | `see the prompt_toolkit docs | |
230 | <http://python-prompt-toolkit.readthedocs.io/en/latest/pages/building_prompts.html#adding-custom-key-bindings>`__. |
|
230 | <http://python-prompt-toolkit.readthedocs.io/en/latest/pages/building_prompts.html#adding-custom-key-bindings>`__. |
@@ -1,175 +1,176 b'' | |||||
1 | ===================== |
|
1 | ===================== | |
2 | Development version |
|
2 | Development version | |
3 | ===================== |
|
3 | ===================== | |
4 |
|
4 | |||
5 | This document describes in-flight development work. |
|
5 | This document describes in-flight development work. | |
6 |
|
6 | |||
7 | .. warning:: |
|
7 | .. warning:: | |
8 |
|
8 | |||
9 | Please do not edit this file by hand (doing so will likely cause merge |
|
9 | Please do not edit this file by hand (doing so will likely cause merge | |
10 | conflicts for other Pull Requests). Instead, create a new file in the |
|
10 | conflicts for other Pull Requests). Instead, create a new file in the | |
11 | `docs/source/whatsnew/pr` folder |
|
11 | `docs/source/whatsnew/pr` folder | |
12 |
|
12 | |||
13 | IPython 6.0 |
|
13 | IPython 6.0 | |
14 | =========== |
|
14 | =========== | |
15 |
|
15 | |||
16 | Released .... ...., 2017 |
|
16 | Released .... ...., 2017 | |
17 |
|
17 | |||
18 | IPython 6 feature a major improvement in the completion machinery which is now |
|
18 | IPython 6 feature a major improvement in the completion machinery which is now | |
19 | capable of completing non-executed code. It is also the first version of IPython |
|
19 | capable of completing non-executed code. It is also the first version of IPython | |
20 | to stop compatibility with Python 2, which is still supported on the bugfix only |
|
20 | to stop compatibility with Python 2, which is still supported on the bugfix only | |
21 | 5.x branch. Read below to have a non-exhaustive list of new features. |
|
21 | 5.x branch. Read below to have a non-exhaustive list of new features. | |
22 |
|
22 | |||
23 | Make sure you have pip > 9.0 before upgrading. |
|
23 | Make sure you have pip > 9.0 before upgrading. | |
24 | You should be able to update by using: |
|
24 | You should be able to update by using: | |
25 |
|
25 | |||
26 | .. code:: |
|
26 | .. code:: | |
27 |
|
27 | |||
28 | pip install ipython --upgrade |
|
28 | pip install ipython --upgrade | |
29 |
|
29 | |||
30 | New completion API and Interface |
|
30 | New completion API and Interface | |
31 | -------------------------------- |
|
31 | -------------------------------- | |
32 |
|
32 | |||
33 | The completer Completion API has seen an overhaul, and the new completer have |
|
33 | The completer Completion API has seen an overhaul, and the new completer have | |
34 | plenty of improvement both from the end users of terminal IPython or for |
|
34 | plenty of improvement both from the end users of terminal IPython or for | |
35 | consumers of the API. |
|
35 | consumers of the API. | |
36 |
|
36 | |||
37 | This new API is capable of pulling completions from :any:`jedi`, thus allowing |
|
37 | This new API is capable of pulling completions from :any:`jedi`, thus allowing | |
38 | type inference on non-executed code. If :any:`jedi` is installed completion like |
|
38 | type inference on non-executed code. If :any:`jedi` is installed completion like | |
39 | the following are now becoming possible without code evaluation: |
|
39 | the following are now becoming possible without code evaluation: | |
40 |
|
40 | |||
41 | >>> data = ['Number of users', 123_456] |
|
41 | >>> data = ['Number of users', 123_456] | |
42 | ... data[0].<tab> |
|
42 | ... data[0].<tab> | |
43 |
|
43 | |||
44 | That is to say, IPython is now capable of inferring that `data[0]` is a string, |
|
44 | That is to say, IPython is now capable of inferring that `data[0]` is a string, | |
45 | and will suggest completions like `.capitalize`. The completion power of IPython |
|
45 | and will suggest completions like `.capitalize`. The completion power of IPython | |
46 | will increase with new Jedi releases, and a number of bugs and more completions |
|
46 | will increase with new Jedi releases, and a number of bugs and more completions | |
47 | are already available on development version of :any:`jedi` if you are curious. |
|
47 | are already available on development version of :any:`jedi` if you are curious. | |
48 |
|
48 | |||
49 | With the help of prompt toolkit, types of completions can be shown in the |
|
49 | With the help of prompt toolkit, types of completions can be shown in the | |
50 | completer interface: |
|
50 | completer interface: | |
51 |
|
51 | |||
52 | .. image:: ../_images/jedi_type_inference_60.png |
|
52 | .. image:: ../_images/jedi_type_inference_60.png | |
53 | :alt: Jedi showing ability to do type inference |
|
53 | :alt: Jedi showing ability to do type inference | |
54 | :align: center |
|
54 | :align: center | |
|
55 | :width: 400px | |||
55 | :target: ../_images/jedi_type_inference_60.png |
|
56 | :target: ../_images/jedi_type_inference_60.png | |
56 |
|
57 | |||
57 | The appearance of the completer is controlled by the |
|
58 | The appearance of the completer is controlled by the | |
58 | ``c.TerminalInteractiveShell.display_completions`` option that will show the |
|
59 | ``c.TerminalInteractiveShell.display_completions`` option that will show the | |
59 | type differently depending on the value among ``'column'``, ``'multicolumn'`` |
|
60 | type differently depending on the value among ``'column'``, ``'multicolumn'`` | |
60 | and ``'readlinelike'`` |
|
61 | and ``'readlinelike'`` | |
61 |
|
62 | |||
62 | The use of Jedi also full fill a number of request and fix a number of bugs |
|
63 | The use of Jedi also full fill a number of request and fix a number of bugs | |
63 | like case insensitive completion, completion after division operator: See |
|
64 | like case insensitive completion, completion after division operator: See | |
64 | :ghpull:`10182`. |
|
65 | :ghpull:`10182`. | |
65 |
|
66 | |||
66 |
Extra patches and updates will be needed to the : |
|
67 | Extra patches and updates will be needed to the :mod:`ipykernel` package for | |
67 | this feature to be available to other clients like jupyter Notebook, Lab, |
|
68 | this feature to be available to other clients like jupyter Notebook, Lab, | |
68 | Nteract, Hydrogen... |
|
69 | Nteract, Hydrogen... | |
69 |
|
70 | |||
70 | The use of Jedi can is barely noticeable on recent enough machines, but can be |
|
71 | The use of Jedi can is barely noticeable on recent enough machines, but can be | |
71 | feel on older ones, in cases were Jedi behavior need to be adjusted, the amount |
|
72 | feel on older ones, in cases were Jedi behavior need to be adjusted, the amount | |
72 | of time given to Jedi to compute type inference can be adjusted with |
|
73 | of time given to Jedi to compute type inference can be adjusted with | |
73 | ``c.IPCompleter.jedi_compute_type_timeout``, with object whose type were not |
|
74 | ``c.IPCompleter.jedi_compute_type_timeout``, with object whose type were not | |
74 | inferred will be shown as ``<unknown>``. Jedi can also be completely deactivated |
|
75 | inferred will be shown as ``<unknown>``. Jedi can also be completely deactivated | |
75 | by using the ``c.Completer.use_jedi=False`` option. |
|
76 | by using the ``c.Completer.use_jedi=False`` option. | |
76 |
|
77 | |||
77 |
|
78 | |||
78 | The old ``Completer.complete()`` API is waiting deprecation and should be |
|
79 | The old ``Completer.complete()`` API is waiting deprecation and should be | |
79 | replaced replaced by ``Completer.completions()`` in a near future. Feedback on |
|
80 | replaced replaced by ``Completer.completions()`` in a near future. Feedback on | |
80 | the current state of the API and suggestions welcome. |
|
81 | the current state of the API and suggestions welcome. | |
81 |
|
82 | |||
82 | Python 3 only codebase |
|
83 | Python 3 only codebase | |
83 | ---------------------- |
|
84 | ---------------------- | |
84 |
|
85 | |||
85 | One of the large challenges in IPython 6.0 has been the adoption of a pure |
|
86 | One of the large challenges in IPython 6.0 has been the adoption of a pure | |
86 | Python 3 code base, which lead us to great length to upstream patches in pip, |
|
87 | Python 3 code base, which lead us to great length to upstream patches in pip, | |
87 | pypi and warehouse to make sure Python 2 system still upgrade to the latest |
|
88 | pypi and warehouse to make sure Python 2 system still upgrade to the latest | |
88 | compatible Python version compatible. |
|
89 | compatible Python version compatible. | |
89 |
|
90 | |||
90 | We remind our Python 2 users that IPython 5 is still compatible with Python 2.7, |
|
91 | We remind our Python 2 users that IPython 5 is still compatible with Python 2.7, | |
91 | still maintained and get regular releases. Using pip 9+, upgrading IPython will |
|
92 | still maintained and get regular releases. Using pip 9+, upgrading IPython will | |
92 | automatically upgrade to the latest version compatible with your system. |
|
93 | automatically upgrade to the latest version compatible with your system. | |
93 |
|
94 | |||
94 | .. warning:: |
|
95 | .. warning:: | |
95 |
|
96 | |||
96 | If you are on a system using an older verison of pip on Python 2, pip may |
|
97 | If you are on a system using an older verison of pip on Python 2, pip may | |
97 | still install IPython 6.0 on your system, and IPython will refuse to start. |
|
98 | still install IPython 6.0 on your system, and IPython will refuse to start. | |
98 | You can fix this by ugrading pip, and reinstalling ipython, or forcing pip to |
|
99 | You can fix this by ugrading pip, and reinstalling ipython, or forcing pip to | |
99 | install an earlier version: ``pip install 'ipython<6'`` |
|
100 | install an earlier version: ``pip install 'ipython<6'`` | |
100 |
|
101 | |||
101 | The ability to use only Python 3 on the code base of IPython has bring a number |
|
102 | The ability to use only Python 3 on the code base of IPython has bring a number | |
102 | of advantage. Most of the newly written code make use of `optional function type |
|
103 | of advantage. Most of the newly written code make use of `optional function type | |
103 | anotation <https://www.python.org/dev/peps/pep-0484/>`_ leading to clearer code |
|
104 | anotation <https://www.python.org/dev/peps/pep-0484/>`_ leading to clearer code | |
104 | and better documentation. |
|
105 | and better documentation. | |
105 |
|
106 | |||
106 | The total size of the repository has also for a first time between releases |
|
107 | The total size of the repository has also for a first time between releases | |
107 | (excluding the big split for 4.0) decreased by about 1500 lines, potentially |
|
108 | (excluding the big split for 4.0) decreased by about 1500 lines, potentially | |
108 | quite a bit more codewide as some documents like this one are append only and |
|
109 | quite a bit more codewide as some documents like this one are append only and | |
109 | are about 300 lines long. |
|
110 | are about 300 lines long. | |
110 |
|
111 | |||
111 | The removal as of Python2/Python3 shim layer has made the code quite clearer and |
|
112 | The removal as of Python2/Python3 shim layer has made the code quite clearer and | |
112 | more idiomatic in a number of location, and much friendlier to work with and |
|
113 | more idiomatic in a number of location, and much friendlier to work with and | |
113 | understand. We hope to further embrace Python 3 capability in the next release |
|
114 | understand. We hope to further embrace Python 3 capability in the next release | |
114 | cycle and introduce more of the Python 3 only idioms (yield from, kwarg only, |
|
115 | cycle and introduce more of the Python 3 only idioms (yield from, kwarg only, | |
115 | general unpacking) in the code base of IPython, and see if we can take advantage |
|
116 | general unpacking) in the code base of IPython, and see if we can take advantage | |
116 | of these as well to improve user experience with better error messages and |
|
117 | of these as well to improve user experience with better error messages and | |
117 | hints. |
|
118 | hints. | |
118 |
|
119 | |||
119 |
|
120 | |||
120 | Miscs improvements |
|
121 | Miscs improvements | |
121 | ------------------ |
|
122 | ------------------ | |
122 |
|
123 | |||
123 |
|
124 | |||
124 | - The :cellmagic:`capture` magic can now capture the result of a cell (from an |
|
125 | - The :cellmagic:`capture` magic can now capture the result of a cell (from an | |
125 | expression on the last line), as well as printed and displayed output. |
|
126 | expression on the last line), as well as printed and displayed output. | |
126 | :ghpull:`9851`. |
|
127 | :ghpull:`9851`. | |
127 |
|
128 | |||
128 | - Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already |
|
129 | - Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already | |
129 | does in the main terminal prompt. |
|
130 | does in the main terminal prompt. | |
130 |
|
131 | |||
131 | - autoreload can now reload ``Enum``. See :ghissue:`10232` and :ghpull:`10316` |
|
132 | - autoreload can now reload ``Enum``. See :ghissue:`10232` and :ghpull:`10316` | |
132 |
|
133 | |||
133 | - IPython.display has gained a :any:`GeoJSON <IPython.display.GeoJSON>` object. |
|
134 | - IPython.display has gained a :any:`GeoJSON <IPython.display.GeoJSON>` object. | |
134 | :ghpull:`10288` and :ghpull:`10253` |
|
135 | :ghpull:`10288` and :ghpull:`10253` | |
135 |
|
136 | |||
136 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. |
|
137 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT. | |
137 |
|
138 | |||
138 |
|
139 | |||
139 | Functions Deprecated in 6.x Development cycle |
|
140 | Functions Deprecated in 6.x Development cycle | |
140 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
141 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
141 |
|
142 | |||
142 | - Loading extensions from ``ipython_extension_dir`` print a warning that this |
|
143 | - Loading extensions from ``ipython_extension_dir`` print a warning that this | |
143 | location is pending deprecation. This should only affect users still having |
|
144 | location is pending deprecation. This should only affect users still having | |
144 | extensions installed with ``%install_ext`` which has been deprecated since |
|
145 | extensions installed with ``%install_ext`` which has been deprecated since | |
145 | IPython 4.0, and removed in 5.0. Extensions still present in |
|
146 | IPython 4.0, and removed in 5.0. Extensions still present in | |
146 | ``ipython_extension_dir`` may shadow more recently installed versions using |
|
147 | ``ipython_extension_dir`` may shadow more recently installed versions using | |
147 | pip. It is thus recommended to clean ``ipython_extension_dir`` of any |
|
148 | pip. It is thus recommended to clean ``ipython_extension_dir`` of any | |
148 | extension now available as a package. |
|
149 | extension now available as a package. | |
149 |
|
150 | |||
150 |
|
151 | |||
151 | - ``IPython.utils.warn`` was deprecated in IPython 4.0, and has now been removed. |
|
152 | - ``IPython.utils.warn`` was deprecated in IPython 4.0, and has now been removed. | |
152 | instead of ``IPython.utils.warn`` inbuilt :any:`warnings` module is used. |
|
153 | instead of ``IPython.utils.warn`` inbuilt :any:`warnings` module is used. | |
153 |
|
154 | |||
154 |
|
155 | |||
155 | - The function `IPython.core.oinspect.py:call_tip` is unused, was marked as |
|
156 | - The function `IPython.core.oinspect.py:call_tip` is unused, was marked as | |
156 | Deprecated (raising a Deprecation Warning) and marked for later removal |
|
157 | Deprecated (raising a Deprecation Warning) and marked for later removal | |
157 | :ghpull:`10104` |
|
158 | :ghpull:`10104` | |
158 |
|
159 | |||
159 | Backwards incompatible changes |
|
160 | Backwards incompatible changes | |
160 | ------------------------------ |
|
161 | ------------------------------ | |
161 |
|
162 | |||
162 | Functions Removed in 6.x Development cycle |
|
163 | Functions Removed in 6.x Development cycle | |
163 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
164 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
164 |
|
165 | |||
165 | The following functions have been removed in the |
|
166 | The following functions have been removed in the | |
166 | development cycle marked for Milestone 6.0. |
|
167 | development cycle marked for Milestone 6.0. | |
167 |
|
168 | |||
168 | - ``IPython/utils/process.py`` - ``is_cmd_found`` |
|
169 | - ``IPython/utils/process.py`` - ``is_cmd_found`` | |
169 | - ``IPython/utils/process.py`` - ``pycmd2argv`` |
|
170 | - ``IPython/utils/process.py`` - ``pycmd2argv`` | |
170 |
|
171 | |||
171 | - The `--deep-reload` flag and the corresponding options to inject `dreload` or |
|
172 | - The `--deep-reload` flag and the corresponding options to inject `dreload` or | |
172 | `reload` into the interactive namespace have been removed. You have to |
|
173 | `reload` into the interactive namespace have been removed. You have to | |
173 | explicitly import `reload` from `IPython.lib.deepreload` to use it. |
|
174 | explicitly import `reload` from `IPython.lib.deepreload` to use it. | |
174 |
|
175 | |||
175 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. |
|
176 | .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT. |
General Comments 0
You need to be logged in to leave comments.
Login now