##// END OF EJS Templates
Exit code 1 if non-interactive execution fails...
Thomas Kluyver -
Show More
@@ -1,378 +1,380 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
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 (
29 29 ScriptMagics, LoggingMagics
30 30 )
31 31 from IPython.core.shellapp import (
32 32 InteractiveShellApp, shell_flags, shell_aliases
33 33 )
34 34 from IPython.extensions.storemagic import StoreMagics
35 35 from .interactiveshell import TerminalInteractiveShell
36 36 from IPython.paths import get_ipython_dir
37 37 from traitlets import (
38 38 Bool, List, default, observe, Type
39 39 )
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Globals, utilities and helpers
43 43 #-----------------------------------------------------------------------------
44 44
45 45 _examples = """
46 46 ipython --matplotlib # enable matplotlib integration
47 47 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
48 48
49 49 ipython --log-level=DEBUG # set logging to DEBUG
50 50 ipython --profile=foo # start with profile foo
51 51
52 52 ipython profile create foo # create profile foo w/ default config files
53 53 ipython help profile # show the help for the profile subcmd
54 54
55 55 ipython locate # print the path to the IPython directory
56 56 ipython locate profile foo # print the path to the directory for profile `foo`
57 57 """
58 58
59 59 #-----------------------------------------------------------------------------
60 60 # Crash handler for this application
61 61 #-----------------------------------------------------------------------------
62 62
63 63 class IPAppCrashHandler(CrashHandler):
64 64 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
65 65
66 66 def __init__(self, app):
67 67 contact_name = release.author
68 68 contact_email = release.author_email
69 69 bug_tracker = 'https://github.com/ipython/ipython/issues'
70 70 super(IPAppCrashHandler,self).__init__(
71 71 app, contact_name, contact_email, bug_tracker
72 72 )
73 73
74 74 def make_report(self,traceback):
75 75 """Return a string containing a crash report."""
76 76
77 77 sec_sep = self.section_sep
78 78 # Start with parent report
79 79 report = [super(IPAppCrashHandler, self).make_report(traceback)]
80 80 # Add interactive-specific info we may have
81 81 rpt_add = report.append
82 82 try:
83 83 rpt_add(sec_sep+"History of session input:")
84 84 for line in self.app.shell.user_ns['_ih']:
85 85 rpt_add(line)
86 86 rpt_add('\n*** Last line of input (may not be in above history):\n')
87 87 rpt_add(self.app.shell._last_input_line+'\n')
88 88 except:
89 89 pass
90 90
91 91 return ''.join(report)
92 92
93 93 #-----------------------------------------------------------------------------
94 94 # Aliases and Flags
95 95 #-----------------------------------------------------------------------------
96 96 flags = dict(base_flags)
97 97 flags.update(shell_flags)
98 98 frontend_flags = {}
99 99 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
100 100 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
101 101 'Turn on auto editing of files with syntax errors.',
102 102 'Turn off auto editing of files with syntax errors.'
103 103 )
104 104 addflag('simple-prompt', 'TerminalInteractiveShell.simple_prompt',
105 105 "Force simple minimal prompt using `raw_input`",
106 106 "Use a rich interactive prompt with prompt_toolkit",
107 107 )
108 108
109 109 addflag('banner', 'TerminalIPythonApp.display_banner',
110 110 "Display a banner upon starting IPython.",
111 111 "Don't display a banner upon starting IPython."
112 112 )
113 113 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
114 114 """Set to confirm when you try to exit IPython with an EOF (Control-D
115 115 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
116 116 you can force a direct exit without any confirmation.""",
117 117 "Don't prompt the user when exiting."
118 118 )
119 119 addflag('term-title', 'TerminalInteractiveShell.term_title',
120 120 "Enable auto setting the terminal title.",
121 121 "Disable auto setting the terminal title."
122 122 )
123 123 classic_config = Config()
124 124 classic_config.InteractiveShell.cache_size = 0
125 125 classic_config.PlainTextFormatter.pprint = False
126 126 classic_config.TerminalInteractiveShell.prompts_class='IPython.terminal.prompts.ClassicPrompts'
127 127 classic_config.InteractiveShell.separate_in = ''
128 128 classic_config.InteractiveShell.separate_out = ''
129 129 classic_config.InteractiveShell.separate_out2 = ''
130 130 classic_config.InteractiveShell.colors = 'NoColor'
131 131 classic_config.InteractiveShell.xmode = 'Plain'
132 132
133 133 frontend_flags['classic']=(
134 134 classic_config,
135 135 "Gives IPython a similar feel to the classic Python prompt."
136 136 )
137 137 # # log doesn't make so much sense this way anymore
138 138 # paa('--log','-l',
139 139 # action='store_true', dest='InteractiveShell.logstart',
140 140 # help="Start logging to the default log file (./ipython_log.py).")
141 141 #
142 142 # # quick is harder to implement
143 143 frontend_flags['quick']=(
144 144 {'TerminalIPythonApp' : {'quick' : True}},
145 145 "Enable quick startup with no config files."
146 146 )
147 147
148 148 frontend_flags['i'] = (
149 149 {'TerminalIPythonApp' : {'force_interact' : True}},
150 150 """If running code from the command line, become interactive afterwards.
151 151 It is often useful to follow this with `--` to treat remaining flags as
152 152 script arguments.
153 153 """
154 154 )
155 155 flags.update(frontend_flags)
156 156
157 157 aliases = dict(base_aliases)
158 158 aliases.update(shell_aliases)
159 159
160 160 #-----------------------------------------------------------------------------
161 161 # Main classes and functions
162 162 #-----------------------------------------------------------------------------
163 163
164 164
165 165 class LocateIPythonApp(BaseIPythonApplication):
166 166 description = """print the path to the IPython dir"""
167 167 subcommands = dict(
168 168 profile=('IPython.core.profileapp.ProfileLocate',
169 169 "print the path to an IPython profile directory",
170 170 ),
171 171 )
172 172 def start(self):
173 173 if self.subapp is not None:
174 174 return self.subapp.start()
175 175 else:
176 176 print(self.ipython_dir)
177 177
178 178
179 179 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
180 180 name = u'ipython'
181 181 description = usage.cl_usage
182 182 crash_handler_class = IPAppCrashHandler
183 183 examples = _examples
184 184
185 185 flags = flags
186 186 aliases = aliases
187 187 classes = List()
188 188
189 189 interactive_shell_class = Type(
190 190 klass=object, # use default_value otherwise which only allow subclasses.
191 191 default_value=TerminalInteractiveShell,
192 192 help="Class to use to instantiate the TerminalInteractiveShell object. Useful for custom Frontends"
193 193 ).tag(config=True)
194 194
195 195 @default('classes')
196 196 def _classes_default(self):
197 197 """This has to be in a method, for TerminalIPythonApp to be available."""
198 198 return [
199 199 InteractiveShellApp, # ShellApp comes before TerminalApp, because
200 200 self.__class__, # it will also affect subclasses (e.g. QtConsole)
201 201 TerminalInteractiveShell,
202 202 HistoryManager,
203 203 ProfileDir,
204 204 PlainTextFormatter,
205 205 IPCompleter,
206 206 ScriptMagics,
207 207 LoggingMagics,
208 208 StoreMagics,
209 209 ]
210 210
211 211 deprecated_subcommands = dict(
212 212 qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
213 213 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
214 214 ),
215 215 notebook=('notebook.notebookapp.NotebookApp',
216 216 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
217 217 ),
218 218 console=('jupyter_console.app.ZMQTerminalIPythonApp',
219 219 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
220 220 ),
221 221 nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
222 222 "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
223 223 ),
224 224 trust=('nbformat.sign.TrustNotebookApp',
225 225 "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
226 226 ),
227 227 kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
228 228 "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
229 229 ),
230 230 )
231 231 subcommands = dict(
232 232 profile = ("IPython.core.profileapp.ProfileApp",
233 233 "Create and manage IPython profiles."
234 234 ),
235 235 kernel = ("ipykernel.kernelapp.IPKernelApp",
236 236 "Start a kernel without an attached frontend."
237 237 ),
238 238 locate=('IPython.terminal.ipapp.LocateIPythonApp',
239 239 LocateIPythonApp.description
240 240 ),
241 241 history=('IPython.core.historyapp.HistoryApp',
242 242 "Manage the IPython history database."
243 243 ),
244 244 )
245 245 deprecated_subcommands['install-nbextension'] = (
246 246 "notebook.nbextensions.InstallNBExtensionApp",
247 247 "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
248 248 )
249 249 subcommands.update(deprecated_subcommands)
250 250
251 251 # *do* autocreate requested profile, but don't create the config file.
252 252 auto_create=Bool(True)
253 253 # configurables
254 254 quick = Bool(False,
255 255 help="""Start IPython quickly by skipping the loading of config files."""
256 256 ).tag(config=True)
257 257 @observe('quick')
258 258 def _quick_changed(self, change):
259 259 if change['new']:
260 260 self.load_config_file = lambda *a, **kw: None
261 261
262 262 display_banner = Bool(True,
263 263 help="Whether to display a banner upon starting IPython."
264 264 ).tag(config=True)
265 265
266 266 # if there is code of files to run from the cmd line, don't interact
267 267 # unless the --i flag (App.force_interact) is true.
268 268 force_interact = Bool(False,
269 269 help="""If a command or file is given via the command-line,
270 270 e.g. 'ipython foo.py', start an interactive shell after executing the
271 271 file or command."""
272 272 ).tag(config=True)
273 273 @observe('force_interact')
274 274 def _force_interact_changed(self, change):
275 275 if change['new']:
276 276 self.interact = True
277 277
278 278 @observe('file_to_run', 'code_to_run', 'module_to_run')
279 279 def _file_to_run_changed(self, change):
280 280 new = change['new']
281 281 if new:
282 282 self.something_to_run = True
283 283 if new and not self.force_interact:
284 284 self.interact = False
285 285
286 286 # internal, not-configurable
287 287 something_to_run=Bool(False)
288 288
289 289 def parse_command_line(self, argv=None):
290 290 """override to allow old '-pylab' flag with deprecation warning"""
291 291
292 292 argv = sys.argv[1:] if argv is None else argv
293 293
294 294 if '-pylab' in argv:
295 295 # deprecated `-pylab` given,
296 296 # warn and transform into current syntax
297 297 argv = argv[:] # copy, don't clobber
298 298 idx = argv.index('-pylab')
299 299 warnings.warn("`-pylab` flag has been deprecated.\n"
300 300 " Use `--matplotlib <backend>` and import pylab manually.")
301 301 argv[idx] = '--pylab'
302 302
303 303 return super(TerminalIPythonApp, self).parse_command_line(argv)
304 304
305 305 @catch_config_error
306 306 def initialize(self, argv=None):
307 307 """Do actions after construct, but before starting the app."""
308 308 super(TerminalIPythonApp, self).initialize(argv)
309 309 if self.subapp is not None:
310 310 # don't bother initializing further, starting subapp
311 311 return
312 312 # print self.extra_args
313 313 if self.extra_args and not self.something_to_run:
314 314 self.file_to_run = self.extra_args[0]
315 315 self.init_path()
316 316 # create the shell
317 317 self.init_shell()
318 318 # and draw the banner
319 319 self.init_banner()
320 320 # Now a variety of things that happen after the banner is printed.
321 321 self.init_gui_pylab()
322 322 self.init_extensions()
323 323 self.init_code()
324 324
325 325 def init_shell(self):
326 326 """initialize the InteractiveShell instance"""
327 327 # Create an InteractiveShell instance.
328 328 # shell.display_banner should always be False for the terminal
329 329 # based app, because we call shell.show_banner() by hand below
330 330 # so the banner shows *before* all extension loading stuff.
331 331 self.shell = self.interactive_shell_class.instance(parent=self,
332 332 profile_dir=self.profile_dir,
333 333 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
334 334 self.shell.configurables.append(self)
335 335
336 336 def init_banner(self):
337 337 """optionally display the banner"""
338 338 if self.display_banner and self.interact:
339 339 self.shell.show_banner()
340 340 # Make sure there is a space below the banner.
341 341 if self.log_level <= logging.INFO: print()
342 342
343 343 def _pylab_changed(self, name, old, new):
344 344 """Replace --pylab='inline' with --pylab='auto'"""
345 345 if new == 'inline':
346 346 warnings.warn("'inline' not available as pylab backend, "
347 347 "using 'auto' instead.")
348 348 self.pylab = 'auto'
349 349
350 350 def start(self):
351 351 if self.subapp is not None:
352 352 return self.subapp.start()
353 353 # perform any prexec steps:
354 354 if self.interact:
355 355 self.log.debug("Starting IPython's mainloop...")
356 356 self.shell.mainloop()
357 357 else:
358 358 self.log.debug("IPython not interactive...")
359 if not self.shell.last_execution_succeeded:
360 sys.exit(1)
359 361
360 362 def load_default_config(ipython_dir=None):
361 363 """Load the default config file from the default ipython_dir.
362 364
363 365 This is useful for embedded shells.
364 366 """
365 367 if ipython_dir is None:
366 368 ipython_dir = get_ipython_dir()
367 369
368 370 profile_dir = os.path.join(ipython_dir, 'profile_default')
369 371 app = TerminalIPythonApp()
370 372 app.config_file_paths.append(profile_dir)
371 373 app.load_config_file()
372 374 return app.config
373 375
374 376 launch_new_instance = TerminalIPythonApp.launch_instance
375 377
376 378
377 379 if __name__ == '__main__':
378 380 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now