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