##// END OF EJS Templates
Backport PR #10676: avoid using private traitlets APIs in load_default_config...
Matthias Bussonnier -
Show More
@@ -1,379 +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 from __future__ import absolute_import
12 12 from __future__ import print_function
13 13
14 14 import logging
15 15 import os
16 16 import sys
17 17 import warnings
18 18
19 19 from traitlets.config.loader import Config
20 20 from traitlets.config.application import boolean_flag, catch_config_error, Application
21 21 from IPython.core import release
22 22 from IPython.core import usage
23 23 from IPython.core.completer import IPCompleter
24 24 from IPython.core.crashhandler import CrashHandler
25 25 from IPython.core.formatters import PlainTextFormatter
26 26 from IPython.core.history import HistoryManager
27 27 from IPython.core.application import (
28 28 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
29 29 )
30 30 from IPython.core.magics import ScriptMagics
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, Dict, 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(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 = Dict(flags)
186 186 aliases = Dict(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 StoreMagics,
208 208 ]
209 209
210 210 deprecated_subcommands = dict(
211 211 qtconsole=('qtconsole.qtconsoleapp.JupyterQtConsoleApp',
212 212 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter Qt Console."""
213 213 ),
214 214 notebook=('notebook.notebookapp.NotebookApp',
215 215 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter HTML Notebook Server."""
216 216 ),
217 217 console=('jupyter_console.app.ZMQTerminalIPythonApp',
218 218 """DEPRECATED, Will be removed in IPython 6.0 : Launch the Jupyter terminal-based Console."""
219 219 ),
220 220 nbconvert=('nbconvert.nbconvertapp.NbConvertApp',
221 221 "DEPRECATED, Will be removed in IPython 6.0 : Convert notebooks to/from other formats."
222 222 ),
223 223 trust=('nbformat.sign.TrustNotebookApp',
224 224 "DEPRECATED, Will be removed in IPython 6.0 : Sign notebooks to trust their potentially unsafe contents at load."
225 225 ),
226 226 kernelspec=('jupyter_client.kernelspecapp.KernelSpecApp',
227 227 "DEPRECATED, Will be removed in IPython 6.0 : Manage Jupyter kernel specifications."
228 228 ),
229 229 )
230 230 subcommands = dict(
231 231 profile = ("IPython.core.profileapp.ProfileApp",
232 232 "Create and manage IPython profiles."
233 233 ),
234 234 kernel = ("ipykernel.kernelapp.IPKernelApp",
235 235 "Start a kernel without an attached frontend."
236 236 ),
237 237 locate=('IPython.terminal.ipapp.LocateIPythonApp',
238 238 LocateIPythonApp.description
239 239 ),
240 240 history=('IPython.core.historyapp.HistoryApp',
241 241 "Manage the IPython history database."
242 242 ),
243 243 )
244 244 deprecated_subcommands['install-nbextension'] = (
245 245 "notebook.nbextensions.InstallNBExtensionApp",
246 246 "DEPRECATED, Will be removed in IPython 6.0 : Install Jupyter notebook extension files"
247 247 )
248 248 subcommands.update(deprecated_subcommands)
249 249
250 250 # *do* autocreate requested profile, but don't create the config file.
251 251 auto_create=Bool(True)
252 252 # configurables
253 253 quick = Bool(False,
254 254 help="""Start IPython quickly by skipping the loading of config files."""
255 255 ).tag(config=True)
256 256 @observe('quick')
257 257 def _quick_changed(self, change):
258 258 if change['new']:
259 259 self.load_config_file = lambda *a, **kw: None
260 260
261 261 display_banner = Bool(True,
262 262 help="Whether to display a banner upon starting IPython."
263 263 ).tag(config=True)
264 264
265 265 # if there is code of files to run from the cmd line, don't interact
266 266 # unless the --i flag (App.force_interact) is true.
267 267 force_interact = Bool(False,
268 268 help="""If a command or file is given via the command-line,
269 269 e.g. 'ipython foo.py', start an interactive shell after executing the
270 270 file or command."""
271 271 ).tag(config=True)
272 272 @observe('force_interact')
273 273 def _force_interact_changed(self, change):
274 274 if change['new']:
275 275 self.interact = True
276 276
277 277 @observe('file_to_run', 'code_to_run', 'module_to_run')
278 278 def _file_to_run_changed(self, change):
279 279 new = change['new']
280 280 if new:
281 281 self.something_to_run = True
282 282 if new and not self.force_interact:
283 283 self.interact = False
284 284
285 285 # internal, not-configurable
286 286 something_to_run=Bool(False)
287 287
288 288 def parse_command_line(self, argv=None):
289 289 """override to allow old '-pylab' flag with deprecation warning"""
290 290
291 291 argv = sys.argv[1:] if argv is None else argv
292 292
293 293 if '-pylab' in argv:
294 294 # deprecated `-pylab` given,
295 295 # warn and transform into current syntax
296 296 argv = argv[:] # copy, don't clobber
297 297 idx = argv.index('-pylab')
298 298 warnings.warn("`-pylab` flag has been deprecated.\n"
299 299 " Use `--matplotlib <backend>` and import pylab manually.")
300 300 argv[idx] = '--pylab'
301 301
302 302 return super(TerminalIPythonApp, self).parse_command_line(argv)
303 303
304 304 @catch_config_error
305 305 def initialize(self, argv=None):
306 306 """Do actions after construct, but before starting the app."""
307 307 super(TerminalIPythonApp, self).initialize(argv)
308 308 if self.subapp is not None:
309 309 # don't bother initializing further, starting subapp
310 310 return
311 311 # print self.extra_args
312 312 if self.extra_args and not self.something_to_run:
313 313 self.file_to_run = self.extra_args[0]
314 314 self.init_path()
315 315 # create the shell
316 316 self.init_shell()
317 317 # and draw the banner
318 318 self.init_banner()
319 319 # Now a variety of things that happen after the banner is printed.
320 320 self.init_gui_pylab()
321 321 self.init_extensions()
322 322 self.init_code()
323 323
324 324 def init_shell(self):
325 325 """initialize the InteractiveShell instance"""
326 326 # Create an InteractiveShell instance.
327 327 # shell.display_banner should always be False for the terminal
328 328 # based app, because we call shell.show_banner() by hand below
329 329 # so the banner shows *before* all extension loading stuff.
330 330 self.shell = self.interactive_shell_class.instance(parent=self,
331 331 profile_dir=self.profile_dir,
332 332 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
333 333 self.shell.configurables.append(self)
334 334
335 335 def init_banner(self):
336 336 """optionally display the banner"""
337 337 if self.display_banner and self.interact:
338 338 self.shell.show_banner()
339 339 # Make sure there is a space below the banner.
340 340 if self.log_level <= logging.INFO: print()
341 341
342 342 def _pylab_changed(self, name, old, new):
343 343 """Replace --pylab='inline' with --pylab='auto'"""
344 344 if new == 'inline':
345 345 warnings.warn("'inline' not available as pylab backend, "
346 346 "using 'auto' instead.")
347 347 self.pylab = 'auto'
348 348
349 349 def start(self):
350 350 if self.subapp is not None:
351 351 return self.subapp.start()
352 352 # perform any prexec steps:
353 353 if self.interact:
354 354 self.log.debug("Starting IPython's mainloop...")
355 355 self.shell.mainloop()
356 356 else:
357 357 self.log.debug("IPython not interactive...")
358 358
359 359 def load_default_config(ipython_dir=None):
360 360 """Load the default config file from the default ipython_dir.
361 361
362 362 This is useful for embedded shells.
363 363 """
364 364 if ipython_dir is None:
365 365 ipython_dir = get_ipython_dir()
366 366
367 367 profile_dir = os.path.join(ipython_dir, 'profile_default')
368
369 config = Config()
370 for cf in Application._load_config_files("ipython_config", path=profile_dir):
371 config.update(cf)
372
373 return config
368 app = TerminalIPythonApp()
369 app.config_file_paths.append(profile_dir)
370 app.load_config_file()
371 return app.config
374 372
375 373 launch_new_instance = TerminalIPythonApp.launch_instance
376 374
377 375
378 376 if __name__ == '__main__':
379 377 launch_new_instance()
General Comments 0
You need to be logged in to leave comments. Login now