##// END OF EJS Templates
Make the TerminalInteractiveShell class configurable....
Matthias Bussonnier -
Show More
@@ -1,370 +1,377 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The :class:`~IPython.core.application.Application` object for the command
5 5 line :command:`ipython` program.
6 6 """
7 7
8 8 # Copyright (c) IPython Development Team.
9 9 # Distributed under the terms of the Modified BSD License.
10 10
11 11
12 12 import logging
13 13 import os
14 14 import sys
15 15 import warnings
16 16
17 17 from traitlets.config.loader import Config
18 18 from traitlets.config.application import boolean_flag, catch_config_error, Application
19 19 from IPython.core import release
20 20 from IPython.core import usage
21 21 from IPython.core.completer import IPCompleter
22 22 from IPython.core.crashhandler import CrashHandler
23 23 from IPython.core.formatters import PlainTextFormatter
24 24 from IPython.core.history import HistoryManager
25 25 from IPython.core.application import (
26 26 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
27 27 )
28 28 from IPython.core.magics import ScriptMagics
29 29 from IPython.core.shellapp import (
30 30 InteractiveShellApp, shell_flags, shell_aliases
31 31 )
32 32 from IPython.extensions.storemagic import StoreMagics
33 33 from .interactiveshell import TerminalInteractiveShell
34 34 from IPython.paths import get_ipython_dir
35 35 from traitlets import (
36 Bool, List, Dict, default, observe,
36 Bool, List, Dict, default, observe, Type
37 37 )
38 38
39 39 #-----------------------------------------------------------------------------
40 40 # Globals, utilities and helpers
41 41 #-----------------------------------------------------------------------------
42 42
43 43 _examples = """
44 44 ipython --matplotlib # enable matplotlib integration
45 45 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
46 46
47 47 ipython --log-level=DEBUG # set logging to DEBUG
48 48 ipython --profile=foo # start with profile foo
49 49
50 50 ipython profile create foo # create profile foo w/ default config files
51 51 ipython help profile # show the help for the profile subcmd
52 52
53 53 ipython locate # print the path to the IPython directory
54 54 ipython locate profile foo # print the path to the directory for profile `foo`
55 55 """
56 56
57 57 #-----------------------------------------------------------------------------
58 58 # Crash handler for this application
59 59 #-----------------------------------------------------------------------------
60 60
61 61 class IPAppCrashHandler(CrashHandler):
62 62 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
63 63
64 64 def __init__(self, app):
65 65 contact_name = release.author
66 66 contact_email = release.author_email
67 67 bug_tracker = 'https://github.com/ipython/ipython/issues'
68 68 super(IPAppCrashHandler,self).__init__(
69 69 app, contact_name, contact_email, bug_tracker
70 70 )
71 71
72 72 def make_report(self,traceback):
73 73 """Return a string containing a crash report."""
74 74
75 75 sec_sep = self.section_sep
76 76 # Start with parent report
77 77 report = [super(IPAppCrashHandler, self).make_report(traceback)]
78 78 # Add interactive-specific info we may have
79 79 rpt_add = report.append
80 80 try:
81 81 rpt_add(sec_sep+"History of session input:")
82 82 for line in self.app.shell.user_ns['_ih']:
83 83 rpt_add(line)
84 84 rpt_add('\n*** Last line of input (may not be in above history):\n')
85 85 rpt_add(self.app.shell._last_input_line+'\n')
86 86 except:
87 87 pass
88 88
89 89 return ''.join(report)
90 90
91 91 #-----------------------------------------------------------------------------
92 92 # Aliases and Flags
93 93 #-----------------------------------------------------------------------------
94 94 flags = dict(base_flags)
95 95 flags.update(shell_flags)
96 96 frontend_flags = {}
97 97 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
98 98 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
99 99 'Turn on auto editing of files with syntax errors.',
100 100 'Turn off auto editing of files with syntax errors.'
101 101 )
102 102 addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
103 103 "Force simple minimal prompt using `raw_input`",
104 104 "Use a rich interactive prompt with prompt_toolkit",
105 105 )
106 106
107 107 addflag('banner', 'TerminalIPythonApp.display_banner',
108 108 "Display a banner upon starting IPython.",
109 109 "Don't display a banner upon starting IPython."
110 110 )
111 111 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
112 112 """Set to confirm when you try to exit IPython with an EOF (Control-D
113 113 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
114 114 you can force a direct exit without any confirmation.""",
115 115 "Don't prompt the user when exiting."
116 116 )
117 117 addflag('term-title', 'TerminalInteractiveShell.term_title',
118 118 "Enable auto setting the terminal title.",
119 119 "Disable auto setting the terminal title."
120 120 )
121 121 classic_config = Config()
122 122 classic_config.InteractiveShell.cache_size = 0
123 123 classic_config.PlainTextFormatter.pprint = False
124 124 classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
125 125 classic_config.InteractiveShell.separate_in = ''
126 126 classic_config.InteractiveShell.separate_out = ''
127 127 classic_config.InteractiveShell.separate_out2 = ''
128 128 classic_config.InteractiveShell.colors = 'NoColor'
129 129 classic_config.InteractiveShell.xmode = 'Plain'
130 130
131 131 frontend_flags['classic']=(
132 132 classic_config,
133 133 "Gives IPython a similar feel to the classic Python prompt."
134 134 )
135 135 # # log doesn't make so much sense this way anymore
136 136 # paa('--log','-l',
137 137 # action='store_true', dest='InteractiveShell.logstart',
138 138 # help="Start logging to the default log file (./ipython_log.py).")
139 139 #
140 140 # # quick is harder to implement
141 141 frontend_flags['quick']=(
142 142 {'TerminalIPythonApp' : {'quick' : True}},
143 143 "Enable quick startup with no config files."
144 144 )
145 145
146 146 frontend_flags['i'] = (
147 147 {'TerminalIPythonApp' : {'force_interact' : True}},
148 148 """If running code from the command line, become interactive afterwards.
149 149 It is often useful to follow this with `--` to treat remaining flags as
150 150 script arguments.
151 151 """
152 152 )
153 153 flags.update(frontend_flags)
154 154
155 155 aliases = dict(base_aliases)
156 156 aliases.update(shell_aliases)
157 157
158 158 #-----------------------------------------------------------------------------
159 159 # Main classes and functions
160 160 #-----------------------------------------------------------------------------
161 161
162 162
163 163 class LocateIPythonApp(BaseIPythonApplication):
164 164 description = """print the path to the IPython dir"""
165 165 subcommands = Dict(dict(
166 166 profile=('IPython.core.profileapp.ProfileLocate',
167 167 "print the path to an IPython profile directory",
168 168 ),
169 169 ))
170 170 def start(self):
171 171 if self.subapp is not None:
172 172 return self.subapp.start()
173 173 else:
174 174 print(self.ipython_dir)
175 175
176 176
177 177 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
178 178 name = u'ipython'
179 179 description = usage.cl_usage
180 180 crash_handler_class = IPAppCrashHandler
181 181 examples = _examples
182 182
183 183 flags = Dict(flags)
184 184 aliases = Dict(aliases)
185 185 classes = List()
186
187 interactive_shell_class = Type(
188 klass=object, # use default_value otherwise which only allow subclasses.
189 default_value=TerminalInteractiveShell,
190 help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
191 ).tag(config=True)
192
186 193 @default('classes')
187 194 def _classes_default(self):
188 195 """This has to be in a method, for TerminalIPythonApp to be available."""
189 196 return [
190 197 InteractiveShellApp, # ShellApp comes before TerminalApp, because
191 198 self.__class__, # it will also affect subclasses (e.g. QtConsole)
192 199 TerminalInteractiveShell,
193 200 HistoryManager,
194 201 ProfileDir,
195 202 PlainTextFormatter,
196 203 IPCompleter,
197 204 ScriptMagics,
198 205 StoreMagics,
199 206 ]
200 207
201 208 deprecated_subcommands = dict(
202 209 qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
203 210 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
204 211 ),
205 212 notebook=('notebook.notebookapp.NotebookApp',
206 213 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
207 214 ),
208 215 console=('jupyter_console.app.ZMQTerminalIPythonApp',
209 216 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
210 217 ),
211 218 nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
212 219 "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
213 220 ),
214 221 trust=('nbformat.sign.TrustNotebookApp',
215 222 "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
216 223 ),
217 224 kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
218 225 "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
219 226 ),
220 227 )
221 228 subcommands = dict(
222 229 profile = ("IPython.core.profileapp.ProfileApp",
223 230 "Create and manage IPython profiles."
224 231 ),
225 232 kernel = ("ipykernel.kernelapp.IPKernelApp",
226 233 "Start a kernel without an attached frontend."
227 234 ),
228 235 locate=('IPython.terminal.ipapp.LocateIPythonApp',
229 236 LocateIPythonApp.description
230 237 ),
231 238 history=('IPython.core.historyapp.HistoryApp',
232 239 "Manage the IPython history database."
233 240 ),
234 241 )
235 242 deprecated_subcommands['install-nbextension'] = (
236 243 "notebook.nbextensions.InstallNBExtensionApp",
237 244 "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
238 245 )
239 246 subcommands.update(deprecated_subcommands)
240 247
241 248 # *do* autocreate requested profile, but don't create the config file.
242 249 auto_create=Bool(True)
243 250 # configurables
244 251 quick = Bool(False,
245 252 help="""Start IPython quickly by skipping the loading of config files."""
246 253 ).tag(config=True)
247 254 @observe('quick')
248 255 def _quick_changed(self, change):
249 256 if change['new']:
250 257 self.load_config_file = lambda *a, **kw: None
251 258
252 259 display_banner = Bool(True,
253 260 help="Whether to display a banner upon starting IPython."
254 261 ).tag(config=True)
255 262
256 263 # if there is code of files to run from the cmd line, don't interact
257 264 # unless the --i flag (App.force_interact) is true.
258 265 force_interact = Bool(False,
259 266 help="""If a command or file is given via the command-line,
260 267 e.g. 'ipython foo.py', start an interactive shell after executing the
261 268 file or command."""
262 269 ).tag(config=True)
263 270 @observe('force_interact')
264 271 def _force_interact_changed(self, change):
265 272 if change['new']:
266 273 self.interact = True
267 274
268 275 @observe('file_to_run', 'code_to_run', 'module_to_run')
269 276 def _file_to_run_changed(self, change):
270 277 new = change['new']
271 278 if new:
272 279 self.something_to_run = True
273 280 if new and not self.force_interact:
274 281 self.interact = False
275 282
276 283 # internal, not-configurable
277 284 something_to_run=Bool(False)
278 285
279 286 def parse_command_line(self, argv=None):
280 287 """override to allow old '-pylab' flag with deprecation warning"""
281 288
282 289 argv = sys.argv[1:] if argv is None else argv
283 290
284 291 if '-pylab' in argv:
285 292 # deprecated `-pylab` given,
286 293 # warn and transform into current syntax
287 294 argv = argv[:] # copy, don't clobber
288 295 idx = argv.index('-pylab')
289 296 warnings.warn("`-pylab` flag has been deprecated.\n"
290 297 " Use `--matplotlib <backend>` and import pylab manually.")
291 298 argv[idx] = '--pylab'
292 299
293 300 return super(TerminalIPythonApp, self).parse_command_line(argv)
294 301
295 302 @catch_config_error
296 303 def initialize(self, argv=None):
297 304 """Do actions after construct, but before starting the app."""
298 305 super(TerminalIPythonApp, self).initialize(argv)
299 306 if self.subapp is not None:
300 307 # don't bother initializing further, starting subapp
301 308 return
302 309 # print self.extra_args
303 310 if self.extra_args and not self.something_to_run:
304 311 self.file_to_run = self.extra_args[0]
305 312 self.init_path()
306 313 # create the shell
307 314 self.init_shell()
308 315 # and draw the banner
309 316 self.init_banner()
310 317 # Now a variety of things that happen after the banner is printed.
311 318 self.init_gui_pylab()
312 319 self.init_extensions()
313 320 self.init_code()
314 321
315 322 def init_shell(self):
316 323 """initialize the InteractiveShell instance"""
317 324 # Create an InteractiveShell instance.
318 325 # shell.display_banner should always be False for the terminal
319 326 # based app, because we call shell.show_banner() by hand below
320 327 # so the banner shows *before* all extension loading stuff.
321 self.shell = TerminalInteractiveShell.instance(parent=self,
328 self.shell = self.interactive_shell_class.instance(parent=self,
322 329 profile_dir=self.profile_dir,
323 330 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
324 331 self.shell.configurables.append(self)
325 332
326 333 def init_banner(self):
327 334 """optionally display the banner"""
328 335 if self.display_banner and self.interact:
329 336 self.shell.show_banner()
330 337 # Make sure there is a space below the banner.
331 338 if self.log_level <= logging.INFO: print()
332 339
333 340 def _pylab_changed(self, name, old, new):
334 341 """Replace --pylab='inline' with --pylab='auto'"""
335 342 if new == 'inline':
336 343 warnings.warn("'inline' not available as pylab backend, "
337 344 "using 'auto' instead.")
338 345 self.pylab = 'auto'
339 346
340 347 def start(self):
341 348 if self.subapp is not None:
342 349 return self.subapp.start()
343 350 # perform any prexec steps:
344 351 if self.interact:
345 352 self.log.debug("Starting IPython's mainloop...")
346 353 self.shell.mainloop()
347 354 else:
348 355 self.log.debug("IPython not interactive...")
349 356
350 357 def load_default_config(ipython_dir=None):
351 358 """Load the default config file from the default ipython_dir.
352 359
353 360 This is useful for embedded shells.
354 361 """
355 362 if ipython_dir is None:
356 363 ipython_dir = get_ipython_dir()
357 364
358 365 profile_dir = os.path.join(ipython_dir, 'profile_default')
359 366
360 367 config = Config()
361 368 for cf in Application._load_config_files("ipython_config", path=profile_dir):
362 369 config.update(cf)
363 370
364 371 return config
365 372
366 373 launch_new_instance = TerminalIPythonApp.launch_instance
367 374
368 375
369 376 if __name__ == '__main__':
370 377 launch_new_instance()
@@ -1,176 +1,185 b''
1 1 =====================
2 2 Development version
3 3 =====================
4 4
5 5 This document describes in-flight development work.
6 6
7 7 .. warning::
8 8
9 9 Please do not edit this file by hand (doing so will likely cause merge
10 10 conflicts for other Pull Requests). Instead, create a new file in the
11 11 `docs/source/whatsnew/pr` folder
12 12
13 13 IPython 6.0
14 14 ===========
15 15
16 16 Released .... ...., 2017
17 17
18 18 IPython 6 feature a major improvement in the completion machinery which is now
19 19 capable of completing non-executed code. It is also the first version of IPython
20 20 to stop compatibility with Python 2, which is still supported on the bugfix only
21 21 5.x branch. Read below to have a non-exhaustive list of new features.
22 22
23 23 Make sure you have pip > 9.0 before upgrading.
24 24 You should be able to update by using:
25 25
26 26 .. code::
27 27
28 28 pip install ipython --upgrade
29 29
30 30 New completion API and Interface
31 31 --------------------------------
32 32
33 33 The completer Completion API has seen an overhaul, and the new completer have
34 34 plenty of improvement both from the end users of terminal IPython or for
35 35 consumers of the API.
36 36
37 37 This new API is capable of pulling completions from :any:`jedi`, thus allowing
38 38 type inference on non-executed code. If :any:`jedi` is installed completion like
39 39 the following are now becoming possible without code evaluation:
40 40
41 41 >>> data = ['Number of users', 123_456]
42 42 ... data[0].<tab>
43 43
44 44 That is to say, IPython is now capable of inferring that `data[0]` is a string,
45 45 and will suggest completions like `.capitalize`. The completion power of IPython
46 46 will increase with new Jedi releases, and a number of bugs and more completions
47 47 are already available on development version of :any:`jedi` if you are curious.
48 48
49 49 With the help of prompt toolkit, types of completions can be shown in the
50 50 completer interface:
51 51
52 52 .. image:: ../_images/jedi_type_inference_60.png
53 53 :alt: Jedi showing ability to do type inference
54 54 :align: center
55 55 :width: 400px
56 56 :target: ../_images/jedi_type_inference_60.png
57 57
58 58 The appearance of the completer is controlled by the
59 59 ``c.TerminalInteractiveShell.display_completions`` option that will show the
60 60 type differently depending on the value among ``'column'``, ``'multicolumn'``
61 61 and ``'readlinelike'``
62 62
63 63 The use of Jedi also full fill a number of request and fix a number of bugs
64 64 like case insensitive completion, completion after division operator: See
65 65 :ghpull:`10182`.
66 66
67 67 Extra patches and updates will be needed to the :mod:`ipykernel` package for
68 68 this feature to be available to other clients like jupyter Notebook, Lab,
69 69 Nteract, Hydrogen...
70 70
71 71 The use of Jedi can is barely noticeable on recent enough machines, but can be
72 72 feel on older ones, in cases were Jedi behavior need to be adjusted, the amount
73 73 of time given to Jedi to compute type inference can be adjusted with
74 74 ``c.IPCompleter.jedi_compute_type_timeout``, with object whose type were not
75 75 inferred will be shown as ``<unknown>``. Jedi can also be completely deactivated
76 76 by using the ``c.Completer.use_jedi=False`` option.
77 77
78 78
79 79 The old ``Completer.complete()`` API is waiting deprecation and should be
80 80 replaced replaced by ``Completer.completions()`` in a near future. Feedback on
81 81 the current state of the API and suggestions welcome.
82 82
83 83 Python 3 only codebase
84 84 ----------------------
85 85
86 86 One of the large challenges in IPython 6.0 has been the adoption of a pure
87 87 Python 3 code base, which lead us to great length to upstream patches in pip,
88 88 pypi and warehouse to make sure Python 2 system still upgrade to the latest
89 89 compatible Python version compatible.
90 90
91 91 We remind our Python 2 users that IPython 5 is still compatible with Python 2.7,
92 92 still maintained and get regular releases. Using pip 9+, upgrading IPython will
93 93 automatically upgrade to the latest version compatible with your system.
94 94
95 95 .. warning::
96 96
97 97 If you are on a system using an older verison of pip on Python 2, pip may
98 98 still install IPython 6.0 on your system, and IPython will refuse to start.
99 99 You can fix this by ugrading pip, and reinstalling ipython, or forcing pip to
100 100 install an earlier version: ``pip install 'ipython<6'``
101 101
102 102 The ability to use only Python 3 on the code base of IPython has bring a number
103 103 of advantage. Most of the newly written code make use of `optional function type
104 104 anotation <https://www.python.org/dev/peps/pep-0484/>`_ leading to clearer code
105 105 and better documentation.
106 106
107 107 The total size of the repository has also for a first time between releases
108 108 (excluding the big split for 4.0) decreased by about 1500 lines, potentially
109 109 quite a bit more codewide as some documents like this one are append only and
110 110 are about 300 lines long.
111 111
112 112 The removal as of Python2/Python3 shim layer has made the code quite clearer and
113 113 more idiomatic in a number of location, and much friendlier to work with and
114 114 understand. We hope to further embrace Python 3 capability in the next release
115 115 cycle and introduce more of the Python 3 only idioms (yield from, kwarg only,
116 116 general unpacking) in the code base of IPython, and see if we can take advantage
117 117 of these as well to improve user experience with better error messages and
118 118 hints.
119 119
120 120
121 Configurable TerminalInteractiveShell
122 -------------------------------------
123
124 IPython gained a new ``c.TerminalIPythonApp.interactive_shell_class`` option
125 that allow to customize the class used to start the terminal frontend. This
126 should allow user to use custom interfaces, like reviving the former readline
127 interface which is now a separate package not maintained by the core team.
128
129
121 130 Miscs improvements
122 131 ------------------
123 132
124 133
125 134 - The :cellmagic:`capture` magic can now capture the result of a cell (from an
126 135 expression on the last line), as well as printed and displayed output.
127 136 :ghpull:`9851`.
128 137
129 138 - Pressing Ctrl-Z in the terminal debugger now suspends IPython, as it already
130 139 does in the main terminal prompt.
131 140
132 141 - autoreload can now reload ``Enum``. See :ghissue:`10232` and :ghpull:`10316`
133 142
134 143 - IPython.display has gained a :any:`GeoJSON <IPython.display.GeoJSON>` object.
135 144 :ghpull:`10288` and :ghpull:`10253`
136 145
137 146 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
138 147
139 148
140 149 Functions Deprecated in 6.x Development cycle
141 150 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
142 151
143 152 - Loading extensions from ``ipython_extension_dir`` print a warning that this
144 153 location is pending deprecation. This should only affect users still having
145 154 extensions installed with ``%install_ext`` which has been deprecated since
146 155 IPython 4.0, and removed in 5.0. Extensions still present in
147 156 ``ipython_extension_dir`` may shadow more recently installed versions using
148 157 pip. It is thus recommended to clean ``ipython_extension_dir`` of any
149 158 extension now available as a package.
150 159
151 160
152 161 - ``IPython.utils.warn`` was deprecated in IPython 4.0, and has now been removed.
153 162 instead of ``IPython.utils.warn`` inbuilt :any:`warnings` module is used.
154 163
155 164
156 165 - The function `IPython.core.oinspect.py:call_tip` is unused, was marked as
157 166 Deprecated (raising a Deprecation Warning) and marked for later removal
158 167 :ghpull:`10104`
159 168
160 169 Backwards incompatible changes
161 170 ------------------------------
162 171
163 172 Functions Removed in 6.x Development cycle
164 173 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
165 174
166 175 The following functions have been removed in the
167 176 development cycle marked for Milestone 6.0.
168 177
169 178 - ``IPython/utils/process.py`` - ``is_cmd_found``
170 179 - ``IPython/utils/process.py`` - ``pycmd2argv``
171 180
172 181 - The `--deep-reload` flag and the corresponding options to inject `dreload` or
173 182 `reload` into the interactive namespace have been removed. You have to
174 183 explicitly import `reload` from `IPython.lib.deepreload` to use it.
175 184
176 185 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
General Comments 0
You need to be logged in to leave comments. Login now