##// END OF EJS Templates
Remove checks for pre-0.11 config files
Thomas Kluyver -
Show More
@@ -1,380 +1,374 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6 """
6 """
7
7
8 # Copyright (c) IPython Development Team.
8 # Copyright (c) IPython Development Team.
9 # Distributed under the terms of the Modified BSD License.
9 # Distributed under the terms of the Modified BSD License.
10
10
11 from __future__ import absolute_import
11 from __future__ import absolute_import
12 from __future__ import print_function
12 from __future__ import print_function
13
13
14 import logging
14 import logging
15 import os
15 import os
16 import sys
16 import sys
17
17
18 from IPython.config.loader import Config
18 from IPython.config.loader import Config
19 from IPython.config.application import boolean_flag, catch_config_error, Application
19 from IPython.config.application import boolean_flag, catch_config_error, Application
20 from IPython.core import release
20 from IPython.core import release
21 from IPython.core import usage
21 from IPython.core import usage
22 from IPython.core.completer import IPCompleter
22 from IPython.core.completer import IPCompleter
23 from IPython.core.crashhandler import CrashHandler
23 from IPython.core.crashhandler import CrashHandler
24 from IPython.core.formatters import PlainTextFormatter
24 from IPython.core.formatters import PlainTextFormatter
25 from IPython.core.history import HistoryManager
25 from IPython.core.history import HistoryManager
26 from IPython.core.prompts import PromptManager
26 from IPython.core.prompts import PromptManager
27 from IPython.core.application import (
27 from IPython.core.application import (
28 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
28 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
29 )
29 )
30 from IPython.core.magics import ScriptMagics
30 from IPython.core.magics import ScriptMagics
31 from IPython.core.shellapp import (
31 from IPython.core.shellapp import (
32 InteractiveShellApp, shell_flags, shell_aliases
32 InteractiveShellApp, shell_flags, shell_aliases
33 )
33 )
34 from IPython.extensions.storemagic import StoreMagics
34 from IPython.extensions.storemagic import StoreMagics
35 from IPython.terminal.interactiveshell import TerminalInteractiveShell
35 from IPython.terminal.interactiveshell import TerminalInteractiveShell
36 from IPython.utils import warn
36 from IPython.utils import warn
37 from IPython.utils.path import get_ipython_dir, check_for_old_config
37 from IPython.utils.path import get_ipython_dir
38 from IPython.utils.traitlets import (
38 from IPython.utils.traitlets import (
39 Bool, List, Dict,
39 Bool, List, Dict,
40 )
40 )
41
41
42 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
43 # Globals, utilities and helpers
43 # Globals, utilities and helpers
44 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
45
45
46 _examples = """
46 _examples = """
47 ipython --matplotlib # enable matplotlib integration
47 ipython --matplotlib # enable matplotlib integration
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
48 ipython --matplotlib=qt # enable matplotlib integration with qt4 backend
49
49
50 ipython --log-level=DEBUG # set logging to DEBUG
50 ipython --log-level=DEBUG # set logging to DEBUG
51 ipython --profile=foo # start with profile foo
51 ipython --profile=foo # start with profile foo
52
52
53 ipython qtconsole # start the qtconsole GUI application
53 ipython qtconsole # start the qtconsole GUI application
54 ipython help qtconsole # show the help for the qtconsole subcmd
54 ipython help qtconsole # show the help for the qtconsole subcmd
55
55
56 ipython console # start the terminal-based console application
56 ipython console # start the terminal-based console application
57 ipython help console # show the help for the console subcmd
57 ipython help console # show the help for the console subcmd
58
58
59 ipython notebook # start the IPython notebook
59 ipython notebook # start the IPython notebook
60 ipython help notebook # show the help for the notebook subcmd
60 ipython help notebook # show the help for the notebook subcmd
61
61
62 ipython profile create foo # create profile foo w/ default config files
62 ipython profile create foo # create profile foo w/ default config files
63 ipython help profile # show the help for the profile subcmd
63 ipython help profile # show the help for the profile subcmd
64
64
65 ipython locate # print the path to the IPython directory
65 ipython locate # print the path to the IPython directory
66 ipython locate profile foo # print the path to the directory for profile `foo`
66 ipython locate profile foo # print the path to the directory for profile `foo`
67
67
68 ipython nbconvert # convert notebooks to/from other formats
68 ipython nbconvert # convert notebooks to/from other formats
69 """
69 """
70
70
71 #-----------------------------------------------------------------------------
71 #-----------------------------------------------------------------------------
72 # Crash handler for this application
72 # Crash handler for this application
73 #-----------------------------------------------------------------------------
73 #-----------------------------------------------------------------------------
74
74
75 class IPAppCrashHandler(CrashHandler):
75 class IPAppCrashHandler(CrashHandler):
76 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
76 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
77
77
78 def __init__(self, app):
78 def __init__(self, app):
79 contact_name = release.author
79 contact_name = release.author
80 contact_email = release.author_email
80 contact_email = release.author_email
81 bug_tracker = 'https://github.com/ipython/ipython/issues'
81 bug_tracker = 'https://github.com/ipython/ipython/issues'
82 super(IPAppCrashHandler,self).__init__(
82 super(IPAppCrashHandler,self).__init__(
83 app, contact_name, contact_email, bug_tracker
83 app, contact_name, contact_email, bug_tracker
84 )
84 )
85
85
86 def make_report(self,traceback):
86 def make_report(self,traceback):
87 """Return a string containing a crash report."""
87 """Return a string containing a crash report."""
88
88
89 sec_sep = self.section_sep
89 sec_sep = self.section_sep
90 # Start with parent report
90 # Start with parent report
91 report = [super(IPAppCrashHandler, self).make_report(traceback)]
91 report = [super(IPAppCrashHandler, self).make_report(traceback)]
92 # Add interactive-specific info we may have
92 # Add interactive-specific info we may have
93 rpt_add = report.append
93 rpt_add = report.append
94 try:
94 try:
95 rpt_add(sec_sep+"History of session input:")
95 rpt_add(sec_sep+"History of session input:")
96 for line in self.app.shell.user_ns['_ih']:
96 for line in self.app.shell.user_ns['_ih']:
97 rpt_add(line)
97 rpt_add(line)
98 rpt_add('\n*** Last line of input (may not be in above history):\n')
98 rpt_add('\n*** Last line of input (may not be in above history):\n')
99 rpt_add(self.app.shell._last_input_line+'\n')
99 rpt_add(self.app.shell._last_input_line+'\n')
100 except:
100 except:
101 pass
101 pass
102
102
103 return ''.join(report)
103 return ''.join(report)
104
104
105 #-----------------------------------------------------------------------------
105 #-----------------------------------------------------------------------------
106 # Aliases and Flags
106 # Aliases and Flags
107 #-----------------------------------------------------------------------------
107 #-----------------------------------------------------------------------------
108 flags = dict(base_flags)
108 flags = dict(base_flags)
109 flags.update(shell_flags)
109 flags.update(shell_flags)
110 frontend_flags = {}
110 frontend_flags = {}
111 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
111 addflag = lambda *args: frontend_flags.update(boolean_flag(*args))
112 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
112 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
113 'Turn on auto editing of files with syntax errors.',
113 'Turn on auto editing of files with syntax errors.',
114 'Turn off auto editing of files with syntax errors.'
114 'Turn off auto editing of files with syntax errors.'
115 )
115 )
116 addflag('banner', 'TerminalIPythonApp.display_banner',
116 addflag('banner', 'TerminalIPythonApp.display_banner',
117 "Display a banner upon starting IPython.",
117 "Display a banner upon starting IPython.",
118 "Don't display a banner upon starting IPython."
118 "Don't display a banner upon starting IPython."
119 )
119 )
120 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
120 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
121 """Set to confirm when you try to exit IPython with an EOF (Control-D
121 """Set to confirm when you try to exit IPython with an EOF (Control-D
122 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
122 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
123 you can force a direct exit without any confirmation.""",
123 you can force a direct exit without any confirmation.""",
124 "Don't prompt the user when exiting."
124 "Don't prompt the user when exiting."
125 )
125 )
126 addflag('term-title', 'TerminalInteractiveShell.term_title',
126 addflag('term-title', 'TerminalInteractiveShell.term_title',
127 "Enable auto setting the terminal title.",
127 "Enable auto setting the terminal title.",
128 "Disable auto setting the terminal title."
128 "Disable auto setting the terminal title."
129 )
129 )
130 classic_config = Config()
130 classic_config = Config()
131 classic_config.InteractiveShell.cache_size = 0
131 classic_config.InteractiveShell.cache_size = 0
132 classic_config.PlainTextFormatter.pprint = False
132 classic_config.PlainTextFormatter.pprint = False
133 classic_config.PromptManager.in_template = '>>> '
133 classic_config.PromptManager.in_template = '>>> '
134 classic_config.PromptManager.in2_template = '... '
134 classic_config.PromptManager.in2_template = '... '
135 classic_config.PromptManager.out_template = ''
135 classic_config.PromptManager.out_template = ''
136 classic_config.InteractiveShell.separate_in = ''
136 classic_config.InteractiveShell.separate_in = ''
137 classic_config.InteractiveShell.separate_out = ''
137 classic_config.InteractiveShell.separate_out = ''
138 classic_config.InteractiveShell.separate_out2 = ''
138 classic_config.InteractiveShell.separate_out2 = ''
139 classic_config.InteractiveShell.colors = 'NoColor'
139 classic_config.InteractiveShell.colors = 'NoColor'
140 classic_config.InteractiveShell.xmode = 'Plain'
140 classic_config.InteractiveShell.xmode = 'Plain'
141
141
142 frontend_flags['classic']=(
142 frontend_flags['classic']=(
143 classic_config,
143 classic_config,
144 "Gives IPython a similar feel to the classic Python prompt."
144 "Gives IPython a similar feel to the classic Python prompt."
145 )
145 )
146 # # log doesn't make so much sense this way anymore
146 # # log doesn't make so much sense this way anymore
147 # paa('--log','-l',
147 # paa('--log','-l',
148 # action='store_true', dest='InteractiveShell.logstart',
148 # action='store_true', dest='InteractiveShell.logstart',
149 # help="Start logging to the default log file (./ipython_log.py).")
149 # help="Start logging to the default log file (./ipython_log.py).")
150 #
150 #
151 # # quick is harder to implement
151 # # quick is harder to implement
152 frontend_flags['quick']=(
152 frontend_flags['quick']=(
153 {'TerminalIPythonApp' : {'quick' : True}},
153 {'TerminalIPythonApp' : {'quick' : True}},
154 "Enable quick startup with no config files."
154 "Enable quick startup with no config files."
155 )
155 )
156
156
157 frontend_flags['i'] = (
157 frontend_flags['i'] = (
158 {'TerminalIPythonApp' : {'force_interact' : True}},
158 {'TerminalIPythonApp' : {'force_interact' : True}},
159 """If running code from the command line, become interactive afterwards."""
159 """If running code from the command line, become interactive afterwards."""
160 )
160 )
161 flags.update(frontend_flags)
161 flags.update(frontend_flags)
162
162
163 aliases = dict(base_aliases)
163 aliases = dict(base_aliases)
164 aliases.update(shell_aliases)
164 aliases.update(shell_aliases)
165
165
166 #-----------------------------------------------------------------------------
166 #-----------------------------------------------------------------------------
167 # Main classes and functions
167 # Main classes and functions
168 #-----------------------------------------------------------------------------
168 #-----------------------------------------------------------------------------
169
169
170
170
171 class LocateIPythonApp(BaseIPythonApplication):
171 class LocateIPythonApp(BaseIPythonApplication):
172 description = """print the path to the IPython dir"""
172 description = """print the path to the IPython dir"""
173 subcommands = Dict(dict(
173 subcommands = Dict(dict(
174 profile=('IPython.core.profileapp.ProfileLocate',
174 profile=('IPython.core.profileapp.ProfileLocate',
175 "print the path to an IPython profile directory",
175 "print the path to an IPython profile directory",
176 ),
176 ),
177 ))
177 ))
178 def start(self):
178 def start(self):
179 if self.subapp is not None:
179 if self.subapp is not None:
180 return self.subapp.start()
180 return self.subapp.start()
181 else:
181 else:
182 print(self.ipython_dir)
182 print(self.ipython_dir)
183
183
184
184
185 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
185 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
186 name = u'ipython'
186 name = u'ipython'
187 description = usage.cl_usage
187 description = usage.cl_usage
188 crash_handler_class = IPAppCrashHandler
188 crash_handler_class = IPAppCrashHandler
189 examples = _examples
189 examples = _examples
190
190
191 flags = Dict(flags)
191 flags = Dict(flags)
192 aliases = Dict(aliases)
192 aliases = Dict(aliases)
193 classes = List()
193 classes = List()
194 def _classes_default(self):
194 def _classes_default(self):
195 """This has to be in a method, for TerminalIPythonApp to be available."""
195 """This has to be in a method, for TerminalIPythonApp to be available."""
196 return [
196 return [
197 InteractiveShellApp, # ShellApp comes before TerminalApp, because
197 InteractiveShellApp, # ShellApp comes before TerminalApp, because
198 self.__class__, # it will also affect subclasses (e.g. QtConsole)
198 self.__class__, # it will also affect subclasses (e.g. QtConsole)
199 TerminalInteractiveShell,
199 TerminalInteractiveShell,
200 PromptManager,
200 PromptManager,
201 HistoryManager,
201 HistoryManager,
202 ProfileDir,
202 ProfileDir,
203 PlainTextFormatter,
203 PlainTextFormatter,
204 IPCompleter,
204 IPCompleter,
205 ScriptMagics,
205 ScriptMagics,
206 StoreMagics,
206 StoreMagics,
207 ]
207 ]
208
208
209 subcommands = dict(
209 subcommands = dict(
210 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
210 qtconsole=('IPython.qt.console.qtconsoleapp.IPythonQtConsoleApp',
211 """Launch the IPython Qt Console."""
211 """Launch the IPython Qt Console."""
212 ),
212 ),
213 notebook=('IPython.html.notebookapp.NotebookApp',
213 notebook=('IPython.html.notebookapp.NotebookApp',
214 """Launch the IPython HTML Notebook Server."""
214 """Launch the IPython HTML Notebook Server."""
215 ),
215 ),
216 profile = ("IPython.core.profileapp.ProfileApp",
216 profile = ("IPython.core.profileapp.ProfileApp",
217 "Create and manage IPython profiles."
217 "Create and manage IPython profiles."
218 ),
218 ),
219 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
219 kernel = ("IPython.kernel.zmq.kernelapp.IPKernelApp",
220 "Start a kernel without an attached frontend."
220 "Start a kernel without an attached frontend."
221 ),
221 ),
222 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
222 console=('IPython.terminal.console.app.ZMQTerminalIPythonApp',
223 """Launch the IPython terminal-based Console."""
223 """Launch the IPython terminal-based Console."""
224 ),
224 ),
225 locate=('IPython.terminal.ipapp.LocateIPythonApp',
225 locate=('IPython.terminal.ipapp.LocateIPythonApp',
226 LocateIPythonApp.description
226 LocateIPythonApp.description
227 ),
227 ),
228 history=('IPython.core.historyapp.HistoryApp',
228 history=('IPython.core.historyapp.HistoryApp',
229 "Manage the IPython history database."
229 "Manage the IPython history database."
230 ),
230 ),
231 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
231 nbconvert=('IPython.nbconvert.nbconvertapp.NbConvertApp',
232 "Convert notebooks to/from other formats."
232 "Convert notebooks to/from other formats."
233 ),
233 ),
234 trust=('IPython.nbformat.sign.TrustNotebookApp',
234 trust=('IPython.nbformat.sign.TrustNotebookApp',
235 "Sign notebooks to trust their potentially unsafe contents at load."
235 "Sign notebooks to trust their potentially unsafe contents at load."
236 ),
236 ),
237 kernelspec=('IPython.kernel.kernelspecapp.KernelSpecApp',
237 kernelspec=('IPython.kernel.kernelspecapp.KernelSpecApp',
238 "Manage IPython kernel specifications."
238 "Manage IPython kernel specifications."
239 ),
239 ),
240 )
240 )
241 subcommands['install-nbextension'] = (
241 subcommands['install-nbextension'] = (
242 "IPython.html.nbextensions.NBExtensionApp",
242 "IPython.html.nbextensions.NBExtensionApp",
243 "Install IPython notebook extension files"
243 "Install IPython notebook extension files"
244 )
244 )
245
245
246 # *do* autocreate requested profile, but don't create the config file.
246 # *do* autocreate requested profile, but don't create the config file.
247 auto_create=Bool(True)
247 auto_create=Bool(True)
248 # configurables
248 # configurables
249 ignore_old_config=Bool(False, config=True,
250 help="Suppress warning messages about legacy config files"
251 )
252 quick = Bool(False, config=True,
249 quick = Bool(False, config=True,
253 help="""Start IPython quickly by skipping the loading of config files."""
250 help="""Start IPython quickly by skipping the loading of config files."""
254 )
251 )
255 def _quick_changed(self, name, old, new):
252 def _quick_changed(self, name, old, new):
256 if new:
253 if new:
257 self.load_config_file = lambda *a, **kw: None
254 self.load_config_file = lambda *a, **kw: None
258 self.ignore_old_config=True
259
255
260 display_banner = Bool(True, config=True,
256 display_banner = Bool(True, config=True,
261 help="Whether to display a banner upon starting IPython."
257 help="Whether to display a banner upon starting IPython."
262 )
258 )
263
259
264 # if there is code of files to run from the cmd line, don't interact
260 # if there is code of files to run from the cmd line, don't interact
265 # unless the --i flag (App.force_interact) is true.
261 # unless the --i flag (App.force_interact) is true.
266 force_interact = Bool(False, config=True,
262 force_interact = Bool(False, config=True,
267 help="""If a command or file is given via the command-line,
263 help="""If a command or file is given via the command-line,
268 e.g. 'ipython foo.py', start an interactive shell after executing the
264 e.g. 'ipython foo.py', start an interactive shell after executing the
269 file or command."""
265 file or command."""
270 )
266 )
271 def _force_interact_changed(self, name, old, new):
267 def _force_interact_changed(self, name, old, new):
272 if new:
268 if new:
273 self.interact = True
269 self.interact = True
274
270
275 def _file_to_run_changed(self, name, old, new):
271 def _file_to_run_changed(self, name, old, new):
276 if new:
272 if new:
277 self.something_to_run = True
273 self.something_to_run = True
278 if new and not self.force_interact:
274 if new and not self.force_interact:
279 self.interact = False
275 self.interact = False
280 _code_to_run_changed = _file_to_run_changed
276 _code_to_run_changed = _file_to_run_changed
281 _module_to_run_changed = _file_to_run_changed
277 _module_to_run_changed = _file_to_run_changed
282
278
283 # internal, not-configurable
279 # internal, not-configurable
284 interact=Bool(True)
280 interact=Bool(True)
285 something_to_run=Bool(False)
281 something_to_run=Bool(False)
286
282
287 def parse_command_line(self, argv=None):
283 def parse_command_line(self, argv=None):
288 """override to allow old '-pylab' flag with deprecation warning"""
284 """override to allow old '-pylab' flag with deprecation warning"""
289
285
290 argv = sys.argv[1:] if argv is None else argv
286 argv = sys.argv[1:] if argv is None else argv
291
287
292 if '-pylab' in argv:
288 if '-pylab' in argv:
293 # deprecated `-pylab` given,
289 # deprecated `-pylab` given,
294 # warn and transform into current syntax
290 # warn and transform into current syntax
295 argv = argv[:] # copy, don't clobber
291 argv = argv[:] # copy, don't clobber
296 idx = argv.index('-pylab')
292 idx = argv.index('-pylab')
297 warn.warn("`-pylab` flag has been deprecated.\n"
293 warn.warn("`-pylab` flag has been deprecated.\n"
298 " Use `--matplotlib <backend>` and import pylab manually.")
294 " Use `--matplotlib <backend>` and import pylab manually.")
299 argv[idx] = '--pylab'
295 argv[idx] = '--pylab'
300
296
301 return super(TerminalIPythonApp, self).parse_command_line(argv)
297 return super(TerminalIPythonApp, self).parse_command_line(argv)
302
298
303 @catch_config_error
299 @catch_config_error
304 def initialize(self, argv=None):
300 def initialize(self, argv=None):
305 """Do actions after construct, but before starting the app."""
301 """Do actions after construct, but before starting the app."""
306 super(TerminalIPythonApp, self).initialize(argv)
302 super(TerminalIPythonApp, self).initialize(argv)
307 if self.subapp is not None:
303 if self.subapp is not None:
308 # don't bother initializing further, starting subapp
304 # don't bother initializing further, starting subapp
309 return
305 return
310 if not self.ignore_old_config:
311 check_for_old_config(self.ipython_dir)
312 # print self.extra_args
306 # print self.extra_args
313 if self.extra_args and not self.something_to_run:
307 if self.extra_args and not self.something_to_run:
314 self.file_to_run = self.extra_args[0]
308 self.file_to_run = self.extra_args[0]
315 self.init_path()
309 self.init_path()
316 # create the shell
310 # create the shell
317 self.init_shell()
311 self.init_shell()
318 # and draw the banner
312 # and draw the banner
319 self.init_banner()
313 self.init_banner()
320 # Now a variety of things that happen after the banner is printed.
314 # Now a variety of things that happen after the banner is printed.
321 self.init_gui_pylab()
315 self.init_gui_pylab()
322 self.init_extensions()
316 self.init_extensions()
323 self.init_code()
317 self.init_code()
324
318
325 def init_shell(self):
319 def init_shell(self):
326 """initialize the InteractiveShell instance"""
320 """initialize the InteractiveShell instance"""
327 # Create an InteractiveShell instance.
321 # Create an InteractiveShell instance.
328 # shell.display_banner should always be False for the terminal
322 # shell.display_banner should always be False for the terminal
329 # based app, because we call shell.show_banner() by hand below
323 # based app, because we call shell.show_banner() by hand below
330 # so the banner shows *before* all extension loading stuff.
324 # so the banner shows *before* all extension loading stuff.
331 self.shell = TerminalInteractiveShell.instance(parent=self,
325 self.shell = TerminalInteractiveShell.instance(parent=self,
332 display_banner=False, profile_dir=self.profile_dir,
326 display_banner=False, profile_dir=self.profile_dir,
333 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
327 ipython_dir=self.ipython_dir, user_ns=self.user_ns)
334 self.shell.configurables.append(self)
328 self.shell.configurables.append(self)
335
329
336 def init_banner(self):
330 def init_banner(self):
337 """optionally display the banner"""
331 """optionally display the banner"""
338 if self.display_banner and self.interact:
332 if self.display_banner and self.interact:
339 self.shell.show_banner()
333 self.shell.show_banner()
340 # Make sure there is a space below the banner.
334 # Make sure there is a space below the banner.
341 if self.log_level <= logging.INFO: print()
335 if self.log_level <= logging.INFO: print()
342
336
343 def _pylab_changed(self, name, old, new):
337 def _pylab_changed(self, name, old, new):
344 """Replace --pylab='inline' with --pylab='auto'"""
338 """Replace --pylab='inline' with --pylab='auto'"""
345 if new == 'inline':
339 if new == 'inline':
346 warn.warn("'inline' not available as pylab backend, "
340 warn.warn("'inline' not available as pylab backend, "
347 "using 'auto' instead.")
341 "using 'auto' instead.")
348 self.pylab = 'auto'
342 self.pylab = 'auto'
349
343
350 def start(self):
344 def start(self):
351 if self.subapp is not None:
345 if self.subapp is not None:
352 return self.subapp.start()
346 return self.subapp.start()
353 # perform any prexec steps:
347 # perform any prexec steps:
354 if self.interact:
348 if self.interact:
355 self.log.debug("Starting IPython's mainloop...")
349 self.log.debug("Starting IPython's mainloop...")
356 self.shell.mainloop()
350 self.shell.mainloop()
357 else:
351 else:
358 self.log.debug("IPython not interactive...")
352 self.log.debug("IPython not interactive...")
359
353
360 def load_default_config(ipython_dir=None):
354 def load_default_config(ipython_dir=None):
361 """Load the default config file from the default ipython_dir.
355 """Load the default config file from the default ipython_dir.
362
356
363 This is useful for embedded shells.
357 This is useful for embedded shells.
364 """
358 """
365 if ipython_dir is None:
359 if ipython_dir is None:
366 ipython_dir = get_ipython_dir()
360 ipython_dir = get_ipython_dir()
367
361
368 profile_dir = os.path.join(ipython_dir, 'profile_default')
362 profile_dir = os.path.join(ipython_dir, 'profile_default')
369
363
370 config = Config()
364 config = Config()
371 for cf in Application._load_config_files("ipython_config", path=profile_dir):
365 for cf in Application._load_config_files("ipython_config", path=profile_dir):
372 config.update(cf)
366 config.update(cf)
373
367
374 return config
368 return config
375
369
376 launch_new_instance = TerminalIPythonApp.launch_instance
370 launch_new_instance = TerminalIPythonApp.launch_instance
377
371
378
372
379 if __name__ == '__main__':
373 if __name__ == '__main__':
380 launch_new_instance()
374 launch_new_instance()
@@ -1,593 +1,558 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Utilities for path handling.
3 Utilities for path handling.
4 """
4 """
5
5
6 # Copyright (c) IPython Development Team.
6 # Copyright (c) IPython Development Team.
7 # Distributed under the terms of the Modified BSD License.
7 # Distributed under the terms of the Modified BSD License.
8
8
9 import os
9 import os
10 import sys
10 import sys
11 import errno
11 import errno
12 import shutil
12 import shutil
13 import random
13 import random
14 import tempfile
14 import tempfile
15 import glob
15 import glob
16 from warnings import warn
16 from warnings import warn
17 from hashlib import md5
17 from hashlib import md5
18
18
19 import IPython
19 import IPython
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
21 from IPython.utils.process import system
21 from IPython.utils.process import system
22 from IPython.utils.importstring import import_item
22 from IPython.utils.importstring import import_item
23 from IPython.utils import py3compat
23 from IPython.utils import py3compat
24 from IPython.utils.decorators import undoc
25
24 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
25 # Code
27 # Code
26 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
27
29
28 fs_encoding = sys.getfilesystemencoding()
30 fs_encoding = sys.getfilesystemencoding()
29
31
30 def _writable_dir(path):
32 def _writable_dir(path):
31 """Whether `path` is a directory, to which the user has write access."""
33 """Whether `path` is a directory, to which the user has write access."""
32 return os.path.isdir(path) and os.access(path, os.W_OK)
34 return os.path.isdir(path) and os.access(path, os.W_OK)
33
35
34 if sys.platform == 'win32':
36 if sys.platform == 'win32':
35 @skip_doctest
37 @skip_doctest
36 def _get_long_path_name(path):
38 def _get_long_path_name(path):
37 """Get a long path name (expand ~) on Windows using ctypes.
39 """Get a long path name (expand ~) on Windows using ctypes.
38
40
39 Examples
41 Examples
40 --------
42 --------
41
43
42 >>> get_long_path_name('c:\\docume~1')
44 >>> get_long_path_name('c:\\docume~1')
43 u'c:\\\\Documents and Settings'
45 u'c:\\\\Documents and Settings'
44
46
45 """
47 """
46 try:
48 try:
47 import ctypes
49 import ctypes
48 except ImportError:
50 except ImportError:
49 raise ImportError('you need to have ctypes installed for this to work')
51 raise ImportError('you need to have ctypes installed for this to work')
50 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
52 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
51 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
53 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
52 ctypes.c_uint ]
54 ctypes.c_uint ]
53
55
54 buf = ctypes.create_unicode_buffer(260)
56 buf = ctypes.create_unicode_buffer(260)
55 rv = _GetLongPathName(path, buf, 260)
57 rv = _GetLongPathName(path, buf, 260)
56 if rv == 0 or rv > 260:
58 if rv == 0 or rv > 260:
57 return path
59 return path
58 else:
60 else:
59 return buf.value
61 return buf.value
60 else:
62 else:
61 def _get_long_path_name(path):
63 def _get_long_path_name(path):
62 """Dummy no-op."""
64 """Dummy no-op."""
63 return path
65 return path
64
66
65
67
66
68
67 def get_long_path_name(path):
69 def get_long_path_name(path):
68 """Expand a path into its long form.
70 """Expand a path into its long form.
69
71
70 On Windows this expands any ~ in the paths. On other platforms, it is
72 On Windows this expands any ~ in the paths. On other platforms, it is
71 a null operation.
73 a null operation.
72 """
74 """
73 return _get_long_path_name(path)
75 return _get_long_path_name(path)
74
76
75
77
76 def unquote_filename(name, win32=(sys.platform=='win32')):
78 def unquote_filename(name, win32=(sys.platform=='win32')):
77 """ On Windows, remove leading and trailing quotes from filenames.
79 """ On Windows, remove leading and trailing quotes from filenames.
78 """
80 """
79 if win32:
81 if win32:
80 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
81 name = name[1:-1]
83 name = name[1:-1]
82 return name
84 return name
83
85
84 def compress_user(path):
86 def compress_user(path):
85 """Reverse of :func:`os.path.expanduser`
87 """Reverse of :func:`os.path.expanduser`
86 """
88 """
87 home = os.path.expanduser('~')
89 home = os.path.expanduser('~')
88 if path.startswith(home):
90 if path.startswith(home):
89 path = "~" + path[len(home):]
91 path = "~" + path[len(home):]
90 return path
92 return path
91
93
92 def get_py_filename(name, force_win32=None):
94 def get_py_filename(name, force_win32=None):
93 """Return a valid python filename in the current directory.
95 """Return a valid python filename in the current directory.
94
96
95 If the given name is not a file, it adds '.py' and searches again.
97 If the given name is not a file, it adds '.py' and searches again.
96 Raises IOError with an informative message if the file isn't found.
98 Raises IOError with an informative message if the file isn't found.
97
99
98 On Windows, apply Windows semantics to the filename. In particular, remove
100 On Windows, apply Windows semantics to the filename. In particular, remove
99 any quoting that has been applied to it. This option can be forced for
101 any quoting that has been applied to it. This option can be forced for
100 testing purposes.
102 testing purposes.
101 """
103 """
102
104
103 name = os.path.expanduser(name)
105 name = os.path.expanduser(name)
104 if force_win32 is None:
106 if force_win32 is None:
105 win32 = (sys.platform == 'win32')
107 win32 = (sys.platform == 'win32')
106 else:
108 else:
107 win32 = force_win32
109 win32 = force_win32
108 name = unquote_filename(name, win32=win32)
110 name = unquote_filename(name, win32=win32)
109 if not os.path.isfile(name) and not name.endswith('.py'):
111 if not os.path.isfile(name) and not name.endswith('.py'):
110 name += '.py'
112 name += '.py'
111 if os.path.isfile(name):
113 if os.path.isfile(name):
112 return name
114 return name
113 else:
115 else:
114 raise IOError('File `%r` not found.' % name)
116 raise IOError('File `%r` not found.' % name)
115
117
116
118
117 def filefind(filename, path_dirs=None):
119 def filefind(filename, path_dirs=None):
118 """Find a file by looking through a sequence of paths.
120 """Find a file by looking through a sequence of paths.
119
121
120 This iterates through a sequence of paths looking for a file and returns
122 This iterates through a sequence of paths looking for a file and returns
121 the full, absolute path of the first occurence of the file. If no set of
123 the full, absolute path of the first occurence of the file. If no set of
122 path dirs is given, the filename is tested as is, after running through
124 path dirs is given, the filename is tested as is, after running through
123 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
125 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
124
126
125 filefind('myfile.txt')
127 filefind('myfile.txt')
126
128
127 will find the file in the current working dir, but::
129 will find the file in the current working dir, but::
128
130
129 filefind('~/myfile.txt')
131 filefind('~/myfile.txt')
130
132
131 Will find the file in the users home directory. This function does not
133 Will find the file in the users home directory. This function does not
132 automatically try any paths, such as the cwd or the user's home directory.
134 automatically try any paths, such as the cwd or the user's home directory.
133
135
134 Parameters
136 Parameters
135 ----------
137 ----------
136 filename : str
138 filename : str
137 The filename to look for.
139 The filename to look for.
138 path_dirs : str, None or sequence of str
140 path_dirs : str, None or sequence of str
139 The sequence of paths to look for the file in. If None, the filename
141 The sequence of paths to look for the file in. If None, the filename
140 need to be absolute or be in the cwd. If a string, the string is
142 need to be absolute or be in the cwd. If a string, the string is
141 put into a sequence and the searched. If a sequence, walk through
143 put into a sequence and the searched. If a sequence, walk through
142 each element and join with ``filename``, calling :func:`expandvars`
144 each element and join with ``filename``, calling :func:`expandvars`
143 and :func:`expanduser` before testing for existence.
145 and :func:`expanduser` before testing for existence.
144
146
145 Returns
147 Returns
146 -------
148 -------
147 Raises :exc:`IOError` or returns absolute path to file.
149 Raises :exc:`IOError` or returns absolute path to file.
148 """
150 """
149
151
150 # If paths are quoted, abspath gets confused, strip them...
152 # If paths are quoted, abspath gets confused, strip them...
151 filename = filename.strip('"').strip("'")
153 filename = filename.strip('"').strip("'")
152 # If the input is an absolute path, just check it exists
154 # If the input is an absolute path, just check it exists
153 if os.path.isabs(filename) and os.path.isfile(filename):
155 if os.path.isabs(filename) and os.path.isfile(filename):
154 return filename
156 return filename
155
157
156 if path_dirs is None:
158 if path_dirs is None:
157 path_dirs = ("",)
159 path_dirs = ("",)
158 elif isinstance(path_dirs, py3compat.string_types):
160 elif isinstance(path_dirs, py3compat.string_types):
159 path_dirs = (path_dirs,)
161 path_dirs = (path_dirs,)
160
162
161 for path in path_dirs:
163 for path in path_dirs:
162 if path == '.': path = py3compat.getcwd()
164 if path == '.': path = py3compat.getcwd()
163 testname = expand_path(os.path.join(path, filename))
165 testname = expand_path(os.path.join(path, filename))
164 if os.path.isfile(testname):
166 if os.path.isfile(testname):
165 return os.path.abspath(testname)
167 return os.path.abspath(testname)
166
168
167 raise IOError("File %r does not exist in any of the search paths: %r" %
169 raise IOError("File %r does not exist in any of the search paths: %r" %
168 (filename, path_dirs) )
170 (filename, path_dirs) )
169
171
170
172
171 class HomeDirError(Exception):
173 class HomeDirError(Exception):
172 pass
174 pass
173
175
174
176
175 def get_home_dir(require_writable=False):
177 def get_home_dir(require_writable=False):
176 """Return the 'home' directory, as a unicode string.
178 """Return the 'home' directory, as a unicode string.
177
179
178 Uses os.path.expanduser('~'), and checks for writability.
180 Uses os.path.expanduser('~'), and checks for writability.
179
181
180 See stdlib docs for how this is determined.
182 See stdlib docs for how this is determined.
181 $HOME is first priority on *ALL* platforms.
183 $HOME is first priority on *ALL* platforms.
182
184
183 Parameters
185 Parameters
184 ----------
186 ----------
185
187
186 require_writable : bool [default: False]
188 require_writable : bool [default: False]
187 if True:
189 if True:
188 guarantees the return value is a writable directory, otherwise
190 guarantees the return value is a writable directory, otherwise
189 raises HomeDirError
191 raises HomeDirError
190 if False:
192 if False:
191 The path is resolved, but it is not guaranteed to exist or be writable.
193 The path is resolved, but it is not guaranteed to exist or be writable.
192 """
194 """
193
195
194 homedir = os.path.expanduser('~')
196 homedir = os.path.expanduser('~')
195 # Next line will make things work even when /home/ is a symlink to
197 # Next line will make things work even when /home/ is a symlink to
196 # /usr/home as it is on FreeBSD, for example
198 # /usr/home as it is on FreeBSD, for example
197 homedir = os.path.realpath(homedir)
199 homedir = os.path.realpath(homedir)
198
200
199 if not _writable_dir(homedir) and os.name == 'nt':
201 if not _writable_dir(homedir) and os.name == 'nt':
200 # expanduser failed, use the registry to get the 'My Documents' folder.
202 # expanduser failed, use the registry to get the 'My Documents' folder.
201 try:
203 try:
202 try:
204 try:
203 import winreg as wreg # Py 3
205 import winreg as wreg # Py 3
204 except ImportError:
206 except ImportError:
205 import _winreg as wreg # Py 2
207 import _winreg as wreg # Py 2
206 key = wreg.OpenKey(
208 key = wreg.OpenKey(
207 wreg.HKEY_CURRENT_USER,
209 wreg.HKEY_CURRENT_USER,
208 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
210 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
209 )
211 )
210 homedir = wreg.QueryValueEx(key,'Personal')[0]
212 homedir = wreg.QueryValueEx(key,'Personal')[0]
211 key.Close()
213 key.Close()
212 except:
214 except:
213 pass
215 pass
214
216
215 if (not require_writable) or _writable_dir(homedir):
217 if (not require_writable) or _writable_dir(homedir):
216 return py3compat.cast_unicode(homedir, fs_encoding)
218 return py3compat.cast_unicode(homedir, fs_encoding)
217 else:
219 else:
218 raise HomeDirError('%s is not a writable dir, '
220 raise HomeDirError('%s is not a writable dir, '
219 'set $HOME environment variable to override' % homedir)
221 'set $HOME environment variable to override' % homedir)
220
222
221 def get_xdg_dir():
223 def get_xdg_dir():
222 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
224 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
223
225
224 This is only for non-OS X posix (Linux,Unix,etc.) systems.
226 This is only for non-OS X posix (Linux,Unix,etc.) systems.
225 """
227 """
226
228
227 env = os.environ
229 env = os.environ
228
230
229 if os.name == 'posix' and sys.platform != 'darwin':
231 if os.name == 'posix' and sys.platform != 'darwin':
230 # Linux, Unix, AIX, etc.
232 # Linux, Unix, AIX, etc.
231 # use ~/.config if empty OR not set
233 # use ~/.config if empty OR not set
232 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
234 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
233 if xdg and _writable_dir(xdg):
235 if xdg and _writable_dir(xdg):
234 return py3compat.cast_unicode(xdg, fs_encoding)
236 return py3compat.cast_unicode(xdg, fs_encoding)
235
237
236 return None
238 return None
237
239
238
240
239 def get_xdg_cache_dir():
241 def get_xdg_cache_dir():
240 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
242 """Return the XDG_CACHE_HOME, if it is defined and exists, else None.
241
243
242 This is only for non-OS X posix (Linux,Unix,etc.) systems.
244 This is only for non-OS X posix (Linux,Unix,etc.) systems.
243 """
245 """
244
246
245 env = os.environ
247 env = os.environ
246
248
247 if os.name == 'posix' and sys.platform != 'darwin':
249 if os.name == 'posix' and sys.platform != 'darwin':
248 # Linux, Unix, AIX, etc.
250 # Linux, Unix, AIX, etc.
249 # use ~/.cache if empty OR not set
251 # use ~/.cache if empty OR not set
250 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
252 xdg = env.get("XDG_CACHE_HOME", None) or os.path.join(get_home_dir(), '.cache')
251 if xdg and _writable_dir(xdg):
253 if xdg and _writable_dir(xdg):
252 return py3compat.cast_unicode(xdg, fs_encoding)
254 return py3compat.cast_unicode(xdg, fs_encoding)
253
255
254 return None
256 return None
255
257
256
258
257 def get_ipython_dir():
259 def get_ipython_dir():
258 """Get the IPython directory for this platform and user.
260 """Get the IPython directory for this platform and user.
259
261
260 This uses the logic in `get_home_dir` to find the home directory
262 This uses the logic in `get_home_dir` to find the home directory
261 and then adds .ipython to the end of the path.
263 and then adds .ipython to the end of the path.
262 """
264 """
263
265
264 env = os.environ
266 env = os.environ
265 pjoin = os.path.join
267 pjoin = os.path.join
266
268
267
269
268 ipdir_def = '.ipython'
270 ipdir_def = '.ipython'
269
271
270 home_dir = get_home_dir()
272 home_dir = get_home_dir()
271 xdg_dir = get_xdg_dir()
273 xdg_dir = get_xdg_dir()
272
274
273 # import pdb; pdb.set_trace() # dbg
275 # import pdb; pdb.set_trace() # dbg
274 if 'IPYTHON_DIR' in env:
276 if 'IPYTHON_DIR' in env:
275 warn('The environment variable IPYTHON_DIR is deprecated. '
277 warn('The environment variable IPYTHON_DIR is deprecated. '
276 'Please use IPYTHONDIR instead.')
278 'Please use IPYTHONDIR instead.')
277 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
279 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
278 if ipdir is None:
280 if ipdir is None:
279 # not set explicitly, use ~/.ipython
281 # not set explicitly, use ~/.ipython
280 ipdir = pjoin(home_dir, ipdir_def)
282 ipdir = pjoin(home_dir, ipdir_def)
281 if xdg_dir:
283 if xdg_dir:
282 # Several IPython versions (up to 1.x) defaulted to .config/ipython
284 # Several IPython versions (up to 1.x) defaulted to .config/ipython
283 # on Linux. We have decided to go back to using .ipython everywhere
285 # on Linux. We have decided to go back to using .ipython everywhere
284 xdg_ipdir = pjoin(xdg_dir, 'ipython')
286 xdg_ipdir = pjoin(xdg_dir, 'ipython')
285
287
286 if _writable_dir(xdg_ipdir):
288 if _writable_dir(xdg_ipdir):
287 cu = compress_user
289 cu = compress_user
288 if os.path.exists(ipdir):
290 if os.path.exists(ipdir):
289 warn(('Ignoring {0} in favour of {1}. Remove {0} to '
291 warn(('Ignoring {0} in favour of {1}. Remove {0} to '
290 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
292 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
291 elif os.path.islink(xdg_ipdir):
293 elif os.path.islink(xdg_ipdir):
292 warn(('{0} is deprecated. Move link to {1} to '
294 warn(('{0} is deprecated. Move link to {1} to '
293 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
295 'get rid of this message').format(cu(xdg_ipdir), cu(ipdir)))
294 else:
296 else:
295 warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
297 warn('Moving {0} to {1}'.format(cu(xdg_ipdir), cu(ipdir)))
296 shutil.move(xdg_ipdir, ipdir)
298 shutil.move(xdg_ipdir, ipdir)
297
299
298 ipdir = os.path.normpath(os.path.expanduser(ipdir))
300 ipdir = os.path.normpath(os.path.expanduser(ipdir))
299
301
300 if os.path.exists(ipdir) and not _writable_dir(ipdir):
302 if os.path.exists(ipdir) and not _writable_dir(ipdir):
301 # ipdir exists, but is not writable
303 # ipdir exists, but is not writable
302 warn("IPython dir '{0}' is not a writable location,"
304 warn("IPython dir '{0}' is not a writable location,"
303 " using a temp directory.".format(ipdir))
305 " using a temp directory.".format(ipdir))
304 ipdir = tempfile.mkdtemp()
306 ipdir = tempfile.mkdtemp()
305 elif not os.path.exists(ipdir):
307 elif not os.path.exists(ipdir):
306 parent = os.path.dirname(ipdir)
308 parent = os.path.dirname(ipdir)
307 if not _writable_dir(parent):
309 if not _writable_dir(parent):
308 # ipdir does not exist and parent isn't writable
310 # ipdir does not exist and parent isn't writable
309 warn("IPython parent '{0}' is not a writable location,"
311 warn("IPython parent '{0}' is not a writable location,"
310 " using a temp directory.".format(parent))
312 " using a temp directory.".format(parent))
311 ipdir = tempfile.mkdtemp()
313 ipdir = tempfile.mkdtemp()
312
314
313 return py3compat.cast_unicode(ipdir, fs_encoding)
315 return py3compat.cast_unicode(ipdir, fs_encoding)
314
316
315
317
316 def get_ipython_cache_dir():
318 def get_ipython_cache_dir():
317 """Get the cache directory it is created if it does not exist."""
319 """Get the cache directory it is created if it does not exist."""
318 xdgdir = get_xdg_cache_dir()
320 xdgdir = get_xdg_cache_dir()
319 if xdgdir is None:
321 if xdgdir is None:
320 return get_ipython_dir()
322 return get_ipython_dir()
321 ipdir = os.path.join(xdgdir, "ipython")
323 ipdir = os.path.join(xdgdir, "ipython")
322 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
324 if not os.path.exists(ipdir) and _writable_dir(xdgdir):
323 ensure_dir_exists(ipdir)
325 ensure_dir_exists(ipdir)
324 elif not _writable_dir(xdgdir):
326 elif not _writable_dir(xdgdir):
325 return get_ipython_dir()
327 return get_ipython_dir()
326
328
327 return py3compat.cast_unicode(ipdir, fs_encoding)
329 return py3compat.cast_unicode(ipdir, fs_encoding)
328
330
329
331
330 def get_ipython_package_dir():
332 def get_ipython_package_dir():
331 """Get the base directory where IPython itself is installed."""
333 """Get the base directory where IPython itself is installed."""
332 ipdir = os.path.dirname(IPython.__file__)
334 ipdir = os.path.dirname(IPython.__file__)
333 return py3compat.cast_unicode(ipdir, fs_encoding)
335 return py3compat.cast_unicode(ipdir, fs_encoding)
334
336
335
337
336 def get_ipython_module_path(module_str):
338 def get_ipython_module_path(module_str):
337 """Find the path to an IPython module in this version of IPython.
339 """Find the path to an IPython module in this version of IPython.
338
340
339 This will always find the version of the module that is in this importable
341 This will always find the version of the module that is in this importable
340 IPython package. This will always return the path to the ``.py``
342 IPython package. This will always return the path to the ``.py``
341 version of the module.
343 version of the module.
342 """
344 """
343 if module_str == 'IPython':
345 if module_str == 'IPython':
344 return os.path.join(get_ipython_package_dir(), '__init__.py')
346 return os.path.join(get_ipython_package_dir(), '__init__.py')
345 mod = import_item(module_str)
347 mod = import_item(module_str)
346 the_path = mod.__file__.replace('.pyc', '.py')
348 the_path = mod.__file__.replace('.pyc', '.py')
347 the_path = the_path.replace('.pyo', '.py')
349 the_path = the_path.replace('.pyo', '.py')
348 return py3compat.cast_unicode(the_path, fs_encoding)
350 return py3compat.cast_unicode(the_path, fs_encoding)
349
351
350 def locate_profile(profile='default'):
352 def locate_profile(profile='default'):
351 """Find the path to the folder associated with a given profile.
353 """Find the path to the folder associated with a given profile.
352
354
353 I.e. find $IPYTHONDIR/profile_whatever.
355 I.e. find $IPYTHONDIR/profile_whatever.
354 """
356 """
355 from IPython.core.profiledir import ProfileDir, ProfileDirError
357 from IPython.core.profiledir import ProfileDir, ProfileDirError
356 try:
358 try:
357 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
359 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
358 except ProfileDirError:
360 except ProfileDirError:
359 # IOError makes more sense when people are expecting a path
361 # IOError makes more sense when people are expecting a path
360 raise IOError("Couldn't find profile %r" % profile)
362 raise IOError("Couldn't find profile %r" % profile)
361 return pd.location
363 return pd.location
362
364
363 def expand_path(s):
365 def expand_path(s):
364 """Expand $VARS and ~names in a string, like a shell
366 """Expand $VARS and ~names in a string, like a shell
365
367
366 :Examples:
368 :Examples:
367
369
368 In [2]: os.environ['FOO']='test'
370 In [2]: os.environ['FOO']='test'
369
371
370 In [3]: expand_path('variable FOO is $FOO')
372 In [3]: expand_path('variable FOO is $FOO')
371 Out[3]: 'variable FOO is test'
373 Out[3]: 'variable FOO is test'
372 """
374 """
373 # This is a pretty subtle hack. When expand user is given a UNC path
375 # This is a pretty subtle hack. When expand user is given a UNC path
374 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
376 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
375 # the $ to get (\\server\share\%username%). I think it considered $
377 # the $ to get (\\server\share\%username%). I think it considered $
376 # alone an empty var. But, we need the $ to remains there (it indicates
378 # alone an empty var. But, we need the $ to remains there (it indicates
377 # a hidden share).
379 # a hidden share).
378 if os.name=='nt':
380 if os.name=='nt':
379 s = s.replace('$\\', 'IPYTHON_TEMP')
381 s = s.replace('$\\', 'IPYTHON_TEMP')
380 s = os.path.expandvars(os.path.expanduser(s))
382 s = os.path.expandvars(os.path.expanduser(s))
381 if os.name=='nt':
383 if os.name=='nt':
382 s = s.replace('IPYTHON_TEMP', '$\\')
384 s = s.replace('IPYTHON_TEMP', '$\\')
383 return s
385 return s
384
386
385
387
386 def unescape_glob(string):
388 def unescape_glob(string):
387 """Unescape glob pattern in `string`."""
389 """Unescape glob pattern in `string`."""
388 def unescape(s):
390 def unescape(s):
389 for pattern in '*[]!?':
391 for pattern in '*[]!?':
390 s = s.replace(r'\{0}'.format(pattern), pattern)
392 s = s.replace(r'\{0}'.format(pattern), pattern)
391 return s
393 return s
392 return '\\'.join(map(unescape, string.split('\\\\')))
394 return '\\'.join(map(unescape, string.split('\\\\')))
393
395
394
396
395 def shellglob(args):
397 def shellglob(args):
396 """
398 """
397 Do glob expansion for each element in `args` and return a flattened list.
399 Do glob expansion for each element in `args` and return a flattened list.
398
400
399 Unmatched glob pattern will remain as-is in the returned list.
401 Unmatched glob pattern will remain as-is in the returned list.
400
402
401 """
403 """
402 expanded = []
404 expanded = []
403 # Do not unescape backslash in Windows as it is interpreted as
405 # Do not unescape backslash in Windows as it is interpreted as
404 # path separator:
406 # path separator:
405 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
407 unescape = unescape_glob if sys.platform != 'win32' else lambda x: x
406 for a in args:
408 for a in args:
407 expanded.extend(glob.glob(a) or [unescape(a)])
409 expanded.extend(glob.glob(a) or [unescape(a)])
408 return expanded
410 return expanded
409
411
410
412
411 def target_outdated(target,deps):
413 def target_outdated(target,deps):
412 """Determine whether a target is out of date.
414 """Determine whether a target is out of date.
413
415
414 target_outdated(target,deps) -> 1/0
416 target_outdated(target,deps) -> 1/0
415
417
416 deps: list of filenames which MUST exist.
418 deps: list of filenames which MUST exist.
417 target: single filename which may or may not exist.
419 target: single filename which may or may not exist.
418
420
419 If target doesn't exist or is older than any file listed in deps, return
421 If target doesn't exist or is older than any file listed in deps, return
420 true, otherwise return false.
422 true, otherwise return false.
421 """
423 """
422 try:
424 try:
423 target_time = os.path.getmtime(target)
425 target_time = os.path.getmtime(target)
424 except os.error:
426 except os.error:
425 return 1
427 return 1
426 for dep in deps:
428 for dep in deps:
427 dep_time = os.path.getmtime(dep)
429 dep_time = os.path.getmtime(dep)
428 if dep_time > target_time:
430 if dep_time > target_time:
429 #print "For target",target,"Dep failed:",dep # dbg
431 #print "For target",target,"Dep failed:",dep # dbg
430 #print "times (dep,tar):",dep_time,target_time # dbg
432 #print "times (dep,tar):",dep_time,target_time # dbg
431 return 1
433 return 1
432 return 0
434 return 0
433
435
434
436
435 def target_update(target,deps,cmd):
437 def target_update(target,deps,cmd):
436 """Update a target with a given command given a list of dependencies.
438 """Update a target with a given command given a list of dependencies.
437
439
438 target_update(target,deps,cmd) -> runs cmd if target is outdated.
440 target_update(target,deps,cmd) -> runs cmd if target is outdated.
439
441
440 This is just a wrapper around target_outdated() which calls the given
442 This is just a wrapper around target_outdated() which calls the given
441 command if target is outdated."""
443 command if target is outdated."""
442
444
443 if target_outdated(target,deps):
445 if target_outdated(target,deps):
444 system(cmd)
446 system(cmd)
445
447
448 @undoc
446 def filehash(path):
449 def filehash(path):
447 """Make an MD5 hash of a file, ignoring any differences in line
450 """Make an MD5 hash of a file, ignoring any differences in line
448 ending characters."""
451 ending characters."""
452 warn("filehash() is deprecated")
449 with open(path, "rU") as f:
453 with open(path, "rU") as f:
450 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
454 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
451
455
452 # If the config is unmodified from the default, we'll just delete it.
453 # These are consistent for 0.10.x, thankfully. We're not going to worry about
454 # older versions.
455 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
456 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
457
458 def check_for_old_config(ipython_dir=None):
459 """Check for old config files, and present a warning if they exist.
460
461 A link to the docs of the new config is included in the message.
462
463 This should mitigate confusion with the transition to the new
464 config system in 0.11.
465 """
466 if ipython_dir is None:
467 ipython_dir = get_ipython_dir()
468
469 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
470 warned = False
471 for cfg in old_configs:
472 f = os.path.join(ipython_dir, cfg)
473 if os.path.exists(f):
474 if filehash(f) == old_config_md5.get(cfg, ''):
475 os.unlink(f)
476 else:
477 warn("Found old IPython config file {!r} (modified by user)".format(f))
478 warned = True
479
480 if warned:
481 warn("""
482 The IPython configuration system has changed as of 0.11, and these files will
483 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
484 of the new config system.
485 To start configuring IPython, do `ipython profile create`, and edit
486 `ipython_config.py` in <ipython_dir>/profile_default.
487 If you need to leave the old config files in place for an older version of
488 IPython and want to suppress this warning message, set
489 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
490
491 def get_security_file(filename, profile='default'):
456 def get_security_file(filename, profile='default'):
492 """Return the absolute path of a security file given by filename and profile
457 """Return the absolute path of a security file given by filename and profile
493
458
494 This allows users and developers to find security files without
459 This allows users and developers to find security files without
495 knowledge of the IPython directory structure. The search path
460 knowledge of the IPython directory structure. The search path
496 will be ['.', profile.security_dir]
461 will be ['.', profile.security_dir]
497
462
498 Parameters
463 Parameters
499 ----------
464 ----------
500
465
501 filename : str
466 filename : str
502 The file to be found. If it is passed as an absolute path, it will
467 The file to be found. If it is passed as an absolute path, it will
503 simply be returned.
468 simply be returned.
504 profile : str [default: 'default']
469 profile : str [default: 'default']
505 The name of the profile to search. Leaving this unspecified
470 The name of the profile to search. Leaving this unspecified
506 The file to be found. If it is passed as an absolute path, fname will
471 The file to be found. If it is passed as an absolute path, fname will
507 simply be returned.
472 simply be returned.
508
473
509 Returns
474 Returns
510 -------
475 -------
511 Raises :exc:`IOError` if file not found or returns absolute path to file.
476 Raises :exc:`IOError` if file not found or returns absolute path to file.
512 """
477 """
513 # import here, because profiledir also imports from utils.path
478 # import here, because profiledir also imports from utils.path
514 from IPython.core.profiledir import ProfileDir
479 from IPython.core.profiledir import ProfileDir
515 try:
480 try:
516 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
481 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
517 except Exception:
482 except Exception:
518 # will raise ProfileDirError if no such profile
483 # will raise ProfileDirError if no such profile
519 raise IOError("Profile %r not found")
484 raise IOError("Profile %r not found")
520 return filefind(filename, ['.', pd.security_dir])
485 return filefind(filename, ['.', pd.security_dir])
521
486
522
487
523 ENOLINK = 1998
488 ENOLINK = 1998
524
489
525 def link(src, dst):
490 def link(src, dst):
526 """Hard links ``src`` to ``dst``, returning 0 or errno.
491 """Hard links ``src`` to ``dst``, returning 0 or errno.
527
492
528 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
493 Note that the special errno ``ENOLINK`` will be returned if ``os.link`` isn't
529 supported by the operating system.
494 supported by the operating system.
530 """
495 """
531
496
532 if not hasattr(os, "link"):
497 if not hasattr(os, "link"):
533 return ENOLINK
498 return ENOLINK
534 link_errno = 0
499 link_errno = 0
535 try:
500 try:
536 os.link(src, dst)
501 os.link(src, dst)
537 except OSError as e:
502 except OSError as e:
538 link_errno = e.errno
503 link_errno = e.errno
539 return link_errno
504 return link_errno
540
505
541
506
542 def link_or_copy(src, dst):
507 def link_or_copy(src, dst):
543 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
508 """Attempts to hardlink ``src`` to ``dst``, copying if the link fails.
544
509
545 Attempts to maintain the semantics of ``shutil.copy``.
510 Attempts to maintain the semantics of ``shutil.copy``.
546
511
547 Because ``os.link`` does not overwrite files, a unique temporary file
512 Because ``os.link`` does not overwrite files, a unique temporary file
548 will be used if the target already exists, then that file will be moved
513 will be used if the target already exists, then that file will be moved
549 into place.
514 into place.
550 """
515 """
551
516
552 if os.path.isdir(dst):
517 if os.path.isdir(dst):
553 dst = os.path.join(dst, os.path.basename(src))
518 dst = os.path.join(dst, os.path.basename(src))
554
519
555 link_errno = link(src, dst)
520 link_errno = link(src, dst)
556 if link_errno == errno.EEXIST:
521 if link_errno == errno.EEXIST:
557 if os.stat(src).st_ino == os.stat(dst).st_ino:
522 if os.stat(src).st_ino == os.stat(dst).st_ino:
558 # dst is already a hard link to the correct file, so we don't need
523 # dst is already a hard link to the correct file, so we don't need
559 # to do anything else. If we try to link and rename the file
524 # to do anything else. If we try to link and rename the file
560 # anyway, we get duplicate files - see http://bugs.python.org/issue21876
525 # anyway, we get duplicate files - see http://bugs.python.org/issue21876
561 return
526 return
562
527
563 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
528 new_dst = dst + "-temp-%04X" %(random.randint(1, 16**4), )
564 try:
529 try:
565 link_or_copy(src, new_dst)
530 link_or_copy(src, new_dst)
566 except:
531 except:
567 try:
532 try:
568 os.remove(new_dst)
533 os.remove(new_dst)
569 except OSError:
534 except OSError:
570 pass
535 pass
571 raise
536 raise
572 os.rename(new_dst, dst)
537 os.rename(new_dst, dst)
573 elif link_errno != 0:
538 elif link_errno != 0:
574 # Either link isn't supported, or the filesystem doesn't support
539 # Either link isn't supported, or the filesystem doesn't support
575 # linking, or 'src' and 'dst' are on different filesystems.
540 # linking, or 'src' and 'dst' are on different filesystems.
576 shutil.copy(src, dst)
541 shutil.copy(src, dst)
577
542
578 def ensure_dir_exists(path, mode=0o755):
543 def ensure_dir_exists(path, mode=0o755):
579 """ensure that a directory exists
544 """ensure that a directory exists
580
545
581 If it doesn't exist, try to create it and protect against a race condition
546 If it doesn't exist, try to create it and protect against a race condition
582 if another process is doing the same.
547 if another process is doing the same.
583
548
584 The default permissions are 755, which differ from os.makedirs default of 777.
549 The default permissions are 755, which differ from os.makedirs default of 777.
585 """
550 """
586 if not os.path.exists(path):
551 if not os.path.exists(path):
587 try:
552 try:
588 os.makedirs(path, mode=mode)
553 os.makedirs(path, mode=mode)
589 except OSError as e:
554 except OSError as e:
590 if e.errno != errno.EEXIST:
555 if e.errno != errno.EEXIST:
591 raise
556 raise
592 elif not os.path.isdir(path):
557 elif not os.path.isdir(path):
593 raise IOError("%r exists but is not a directory" % path)
558 raise IOError("%r exists but is not a directory" % path)
General Comments 0
You need to be logged in to leave comments. Login now