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