##// END OF EJS Templates
Prefer IPYTHONDIR over IPYTHON_DIR.
Bradley M. Froehle -
Show More
@@ -1,336 +1,336 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 An application for IPython.
3 An application for IPython.
4
4
5 All top-level applications should use the classes in this module for
5 All top-level applications should use the classes in this module for
6 handling configuration and creating componenets.
6 handling configuration and creating componenets.
7
7
8 The job of an :class:`Application` is to create the master configuration
8 The job of an :class:`Application` is to create the master configuration
9 object and then create the configurable objects, passing the config to them.
9 object and then create the configurable objects, passing the config to them.
10
10
11 Authors:
11 Authors:
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15 * Min RK
16
16
17 """
17 """
18
18
19 #-----------------------------------------------------------------------------
19 #-----------------------------------------------------------------------------
20 # Copyright (C) 2008-2011 The IPython Development Team
20 # Copyright (C) 2008-2011 The IPython Development Team
21 #
21 #
22 # Distributed under the terms of the BSD License. The full license is in
22 # Distributed under the terms of the BSD License. The full license is in
23 # the file COPYING, distributed as part of this software.
23 # the file COPYING, distributed as part of this software.
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Imports
27 # Imports
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 import atexit
30 import atexit
31 import glob
31 import glob
32 import logging
32 import logging
33 import os
33 import os
34 import shutil
34 import shutil
35 import sys
35 import sys
36
36
37 from IPython.config.application import Application, catch_config_error
37 from IPython.config.application import Application, catch_config_error
38 from IPython.config.configurable import Configurable
38 from IPython.config.configurable import Configurable
39 from IPython.config.loader import Config, ConfigFileNotFound
39 from IPython.config.loader import Config, ConfigFileNotFound
40 from IPython.core import release, crashhandler
40 from IPython.core import release, crashhandler
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
41 from IPython.core.profiledir import ProfileDir, ProfileDirError
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict
43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict
44 from IPython.utils import py3compat
44 from IPython.utils import py3compat
45
45
46 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
47 # Classes and functions
47 # Classes and functions
48 #-----------------------------------------------------------------------------
48 #-----------------------------------------------------------------------------
49
49
50
50
51 #-----------------------------------------------------------------------------
51 #-----------------------------------------------------------------------------
52 # Base Application Class
52 # Base Application Class
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54
54
55 # aliases and flags
55 # aliases and flags
56
56
57 base_aliases = {
57 base_aliases = {
58 'profile' : 'BaseIPythonApplication.profile',
58 'profile' : 'BaseIPythonApplication.profile',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 'log-level' : 'Application.log_level',
60 'log-level' : 'Application.log_level',
61 }
61 }
62
62
63 base_flags = dict(
63 base_flags = dict(
64 debug = ({'Application' : {'log_level' : logging.DEBUG}},
64 debug = ({'Application' : {'log_level' : logging.DEBUG}},
65 "set log level to logging.DEBUG (maximize logging output)"),
65 "set log level to logging.DEBUG (maximize logging output)"),
66 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
66 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
67 "set log level to logging.CRITICAL (minimize logging output)"),
67 "set log level to logging.CRITICAL (minimize logging output)"),
68 init = ({'BaseIPythonApplication' : {
68 init = ({'BaseIPythonApplication' : {
69 'copy_config_files' : True,
69 'copy_config_files' : True,
70 'auto_create' : True}
70 'auto_create' : True}
71 }, """Initialize profile with default config files. This is equivalent
71 }, """Initialize profile with default config files. This is equivalent
72 to running `ipython profile create <profile>` prior to startup.
72 to running `ipython profile create <profile>` prior to startup.
73 """)
73 """)
74 )
74 )
75
75
76
76
77 class BaseIPythonApplication(Application):
77 class BaseIPythonApplication(Application):
78
78
79 name = Unicode(u'ipython')
79 name = Unicode(u'ipython')
80 description = Unicode(u'IPython: an enhanced interactive Python shell.')
80 description = Unicode(u'IPython: an enhanced interactive Python shell.')
81 version = Unicode(release.version)
81 version = Unicode(release.version)
82
82
83 aliases = Dict(base_aliases)
83 aliases = Dict(base_aliases)
84 flags = Dict(base_flags)
84 flags = Dict(base_flags)
85 classes = List([ProfileDir])
85 classes = List([ProfileDir])
86
86
87 # Track whether the config_file has changed,
87 # Track whether the config_file has changed,
88 # because some logic happens only if we aren't using the default.
88 # because some logic happens only if we aren't using the default.
89 config_file_specified = Bool(False)
89 config_file_specified = Bool(False)
90
90
91 config_file_name = Unicode(u'ipython_config.py')
91 config_file_name = Unicode(u'ipython_config.py')
92 def _config_file_name_default(self):
92 def _config_file_name_default(self):
93 return self.name.replace('-','_') + u'_config.py'
93 return self.name.replace('-','_') + u'_config.py'
94 def _config_file_name_changed(self, name, old, new):
94 def _config_file_name_changed(self, name, old, new):
95 if new != old:
95 if new != old:
96 self.config_file_specified = True
96 self.config_file_specified = True
97
97
98 # The directory that contains IPython's builtin profiles.
98 # The directory that contains IPython's builtin profiles.
99 builtin_profile_dir = Unicode(
99 builtin_profile_dir = Unicode(
100 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
100 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
101 )
101 )
102
102
103 config_file_paths = List(Unicode)
103 config_file_paths = List(Unicode)
104 def _config_file_paths_default(self):
104 def _config_file_paths_default(self):
105 return [os.getcwdu()]
105 return [os.getcwdu()]
106
106
107 profile = Unicode(u'default', config=True,
107 profile = Unicode(u'default', config=True,
108 help="""The IPython profile to use."""
108 help="""The IPython profile to use."""
109 )
109 )
110
110
111 def _profile_changed(self, name, old, new):
111 def _profile_changed(self, name, old, new):
112 self.builtin_profile_dir = os.path.join(
112 self.builtin_profile_dir = os.path.join(
113 get_ipython_package_dir(), u'config', u'profile', new
113 get_ipython_package_dir(), u'config', u'profile', new
114 )
114 )
115
115
116 ipython_dir = Unicode(get_ipython_dir(), config=True,
116 ipython_dir = Unicode(get_ipython_dir(), config=True,
117 help="""
117 help="""
118 The name of the IPython directory. This directory is used for logging
118 The name of the IPython directory. This directory is used for logging
119 configuration (through profiles), history storage, etc. The default
119 configuration (through profiles), history storage, etc. The default
120 is usually $HOME/.ipython. This options can also be specified through
120 is usually $HOME/.ipython. This options can also be specified through
121 the environment variable IPYTHONDIR.
121 the environment variable IPYTHONDIR.
122 """
122 """
123 )
123 )
124
124
125 overwrite = Bool(False, config=True,
125 overwrite = Bool(False, config=True,
126 help="""Whether to overwrite existing config files when copying""")
126 help="""Whether to overwrite existing config files when copying""")
127 auto_create = Bool(False, config=True,
127 auto_create = Bool(False, config=True,
128 help="""Whether to create profile dir if it doesn't exist""")
128 help="""Whether to create profile dir if it doesn't exist""")
129
129
130 config_files = List(Unicode)
130 config_files = List(Unicode)
131 def _config_files_default(self):
131 def _config_files_default(self):
132 return [u'ipython_config.py']
132 return [u'ipython_config.py']
133
133
134 copy_config_files = Bool(False, config=True,
134 copy_config_files = Bool(False, config=True,
135 help="""Whether to install the default config files into the profile dir.
135 help="""Whether to install the default config files into the profile dir.
136 If a new profile is being created, and IPython contains config files for that
136 If a new profile is being created, and IPython contains config files for that
137 profile, then they will be staged into the new directory. Otherwise,
137 profile, then they will be staged into the new directory. Otherwise,
138 default config files will be automatically generated.
138 default config files will be automatically generated.
139 """)
139 """)
140
140
141 verbose_crash = Bool(False, config=True,
141 verbose_crash = Bool(False, config=True,
142 help="""Create a massive crash report when IPython enconters what may be an
142 help="""Create a massive crash report when IPython enconters what may be an
143 internal error. The default is to append a short message to the
143 internal error. The default is to append a short message to the
144 usual traceback""")
144 usual traceback""")
145
145
146 # The class to use as the crash handler.
146 # The class to use as the crash handler.
147 crash_handler_class = Type(crashhandler.CrashHandler)
147 crash_handler_class = Type(crashhandler.CrashHandler)
148
148
149 def __init__(self, **kwargs):
149 def __init__(self, **kwargs):
150 super(BaseIPythonApplication, self).__init__(**kwargs)
150 super(BaseIPythonApplication, self).__init__(**kwargs)
151 # ensure even default IPYTHONDIR exists
151 # ensure even default IPYTHONDIR exists
152 if not os.path.exists(self.ipython_dir):
152 if not os.path.exists(self.ipython_dir):
153 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
153 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
154
154
155 #-------------------------------------------------------------------------
155 #-------------------------------------------------------------------------
156 # Various stages of Application creation
156 # Various stages of Application creation
157 #-------------------------------------------------------------------------
157 #-------------------------------------------------------------------------
158
158
159 def init_crash_handler(self):
159 def init_crash_handler(self):
160 """Create a crash handler, typically setting sys.excepthook to it."""
160 """Create a crash handler, typically setting sys.excepthook to it."""
161 self.crash_handler = self.crash_handler_class(self)
161 self.crash_handler = self.crash_handler_class(self)
162 sys.excepthook = self.excepthook
162 sys.excepthook = self.excepthook
163 def unset_crashhandler():
163 def unset_crashhandler():
164 sys.excepthook = sys.__excepthook__
164 sys.excepthook = sys.__excepthook__
165 atexit.register(unset_crashhandler)
165 atexit.register(unset_crashhandler)
166
166
167 def excepthook(self, etype, evalue, tb):
167 def excepthook(self, etype, evalue, tb):
168 """this is sys.excepthook after init_crashhandler
168 """this is sys.excepthook after init_crashhandler
169
169
170 set self.verbose_crash=True to use our full crashhandler, instead of
170 set self.verbose_crash=True to use our full crashhandler, instead of
171 a regular traceback with a short message (crash_handler_lite)
171 a regular traceback with a short message (crash_handler_lite)
172 """
172 """
173
173
174 if self.verbose_crash:
174 if self.verbose_crash:
175 return self.crash_handler(etype, evalue, tb)
175 return self.crash_handler(etype, evalue, tb)
176 else:
176 else:
177 return crashhandler.crash_handler_lite(etype, evalue, tb)
177 return crashhandler.crash_handler_lite(etype, evalue, tb)
178
178
179 def _ipython_dir_changed(self, name, old, new):
179 def _ipython_dir_changed(self, name, old, new):
180 if old in sys.path:
180 if old in sys.path:
181 sys.path.remove(old)
181 sys.path.remove(old)
182 sys.path.append(os.path.abspath(new))
182 sys.path.append(os.path.abspath(new))
183 if not os.path.isdir(new):
183 if not os.path.isdir(new):
184 os.makedirs(new, mode=0777)
184 os.makedirs(new, mode=0777)
185 readme = os.path.join(new, 'README')
185 readme = os.path.join(new, 'README')
186 if not os.path.exists(readme):
186 if not os.path.exists(readme):
187 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
187 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
188 shutil.copy(os.path.join(path, 'README'), readme)
188 shutil.copy(os.path.join(path, 'README'), readme)
189 self.log.debug("IPYTHON_DIR set to: %s" % new)
189 self.log.debug("IPYTHONDIR set to: %s" % new)
190
190
191 def load_config_file(self, suppress_errors=True):
191 def load_config_file(self, suppress_errors=True):
192 """Load the config file.
192 """Load the config file.
193
193
194 By default, errors in loading config are handled, and a warning
194 By default, errors in loading config are handled, and a warning
195 printed on screen. For testing, the suppress_errors option is set
195 printed on screen. For testing, the suppress_errors option is set
196 to False, so errors will make tests fail.
196 to False, so errors will make tests fail.
197 """
197 """
198 self.log.debug("Searching path %s for config files", self.config_file_paths)
198 self.log.debug("Searching path %s for config files", self.config_file_paths)
199 base_config = 'ipython_config.py'
199 base_config = 'ipython_config.py'
200 self.log.debug("Attempting to load config file: %s" %
200 self.log.debug("Attempting to load config file: %s" %
201 base_config)
201 base_config)
202 try:
202 try:
203 Application.load_config_file(
203 Application.load_config_file(
204 self,
204 self,
205 base_config,
205 base_config,
206 path=self.config_file_paths
206 path=self.config_file_paths
207 )
207 )
208 except ConfigFileNotFound:
208 except ConfigFileNotFound:
209 # ignore errors loading parent
209 # ignore errors loading parent
210 self.log.debug("Config file %s not found", base_config)
210 self.log.debug("Config file %s not found", base_config)
211 pass
211 pass
212 if self.config_file_name == base_config:
212 if self.config_file_name == base_config:
213 # don't load secondary config
213 # don't load secondary config
214 return
214 return
215 self.log.debug("Attempting to load config file: %s" %
215 self.log.debug("Attempting to load config file: %s" %
216 self.config_file_name)
216 self.config_file_name)
217 try:
217 try:
218 Application.load_config_file(
218 Application.load_config_file(
219 self,
219 self,
220 self.config_file_name,
220 self.config_file_name,
221 path=self.config_file_paths
221 path=self.config_file_paths
222 )
222 )
223 except ConfigFileNotFound:
223 except ConfigFileNotFound:
224 # Only warn if the default config file was NOT being used.
224 # Only warn if the default config file was NOT being used.
225 if self.config_file_specified:
225 if self.config_file_specified:
226 msg = self.log.warn
226 msg = self.log.warn
227 else:
227 else:
228 msg = self.log.debug
228 msg = self.log.debug
229 msg("Config file not found, skipping: %s", self.config_file_name)
229 msg("Config file not found, skipping: %s", self.config_file_name)
230 except:
230 except:
231 # For testing purposes.
231 # For testing purposes.
232 if not suppress_errors:
232 if not suppress_errors:
233 raise
233 raise
234 self.log.warn("Error loading config file: %s" %
234 self.log.warn("Error loading config file: %s" %
235 self.config_file_name, exc_info=True)
235 self.config_file_name, exc_info=True)
236
236
237 def init_profile_dir(self):
237 def init_profile_dir(self):
238 """initialize the profile dir"""
238 """initialize the profile dir"""
239 try:
239 try:
240 # location explicitly specified:
240 # location explicitly specified:
241 location = self.config.ProfileDir.location
241 location = self.config.ProfileDir.location
242 except AttributeError:
242 except AttributeError:
243 # location not specified, find by profile name
243 # location not specified, find by profile name
244 try:
244 try:
245 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
245 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
246 except ProfileDirError:
246 except ProfileDirError:
247 # not found, maybe create it (always create default profile)
247 # not found, maybe create it (always create default profile)
248 if self.auto_create or self.profile=='default':
248 if self.auto_create or self.profile=='default':
249 try:
249 try:
250 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
250 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
251 except ProfileDirError:
251 except ProfileDirError:
252 self.log.fatal("Could not create profile: %r"%self.profile)
252 self.log.fatal("Could not create profile: %r"%self.profile)
253 self.exit(1)
253 self.exit(1)
254 else:
254 else:
255 self.log.info("Created profile dir: %r"%p.location)
255 self.log.info("Created profile dir: %r"%p.location)
256 else:
256 else:
257 self.log.fatal("Profile %r not found."%self.profile)
257 self.log.fatal("Profile %r not found."%self.profile)
258 self.exit(1)
258 self.exit(1)
259 else:
259 else:
260 self.log.info("Using existing profile dir: %r"%p.location)
260 self.log.info("Using existing profile dir: %r"%p.location)
261 else:
261 else:
262 # location is fully specified
262 # location is fully specified
263 try:
263 try:
264 p = ProfileDir.find_profile_dir(location, self.config)
264 p = ProfileDir.find_profile_dir(location, self.config)
265 except ProfileDirError:
265 except ProfileDirError:
266 # not found, maybe create it
266 # not found, maybe create it
267 if self.auto_create:
267 if self.auto_create:
268 try:
268 try:
269 p = ProfileDir.create_profile_dir(location, self.config)
269 p = ProfileDir.create_profile_dir(location, self.config)
270 except ProfileDirError:
270 except ProfileDirError:
271 self.log.fatal("Could not create profile directory: %r"%location)
271 self.log.fatal("Could not create profile directory: %r"%location)
272 self.exit(1)
272 self.exit(1)
273 else:
273 else:
274 self.log.info("Creating new profile dir: %r"%location)
274 self.log.info("Creating new profile dir: %r"%location)
275 else:
275 else:
276 self.log.fatal("Profile directory %r not found."%location)
276 self.log.fatal("Profile directory %r not found."%location)
277 self.exit(1)
277 self.exit(1)
278 else:
278 else:
279 self.log.info("Using existing profile dir: %r"%location)
279 self.log.info("Using existing profile dir: %r"%location)
280
280
281 self.profile_dir = p
281 self.profile_dir = p
282 self.config_file_paths.append(p.location)
282 self.config_file_paths.append(p.location)
283
283
284 def init_config_files(self):
284 def init_config_files(self):
285 """[optionally] copy default config files into profile dir."""
285 """[optionally] copy default config files into profile dir."""
286 # copy config files
286 # copy config files
287 path = self.builtin_profile_dir
287 path = self.builtin_profile_dir
288 if self.copy_config_files:
288 if self.copy_config_files:
289 src = self.profile
289 src = self.profile
290
290
291 cfg = self.config_file_name
291 cfg = self.config_file_name
292 if path and os.path.exists(os.path.join(path, cfg)):
292 if path and os.path.exists(os.path.join(path, cfg)):
293 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
293 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
294 cfg, src, self.profile_dir.location, self.overwrite)
294 cfg, src, self.profile_dir.location, self.overwrite)
295 )
295 )
296 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
296 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
297 else:
297 else:
298 self.stage_default_config_file()
298 self.stage_default_config_file()
299 else:
299 else:
300 # Still stage *bundled* config files, but not generated ones
300 # Still stage *bundled* config files, but not generated ones
301 # This is necessary for `ipython profile=sympy` to load the profile
301 # This is necessary for `ipython profile=sympy` to load the profile
302 # on the first go
302 # on the first go
303 files = glob.glob(os.path.join(path, '*.py'))
303 files = glob.glob(os.path.join(path, '*.py'))
304 for fullpath in files:
304 for fullpath in files:
305 cfg = os.path.basename(fullpath)
305 cfg = os.path.basename(fullpath)
306 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
306 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
307 # file was copied
307 # file was copied
308 self.log.warn("Staging bundled %s from %s into %r"%(
308 self.log.warn("Staging bundled %s from %s into %r"%(
309 cfg, self.profile, self.profile_dir.location)
309 cfg, self.profile, self.profile_dir.location)
310 )
310 )
311
311
312
312
313 def stage_default_config_file(self):
313 def stage_default_config_file(self):
314 """auto generate default config file, and stage it into the profile."""
314 """auto generate default config file, and stage it into the profile."""
315 s = self.generate_config_file()
315 s = self.generate_config_file()
316 fname = os.path.join(self.profile_dir.location, self.config_file_name)
316 fname = os.path.join(self.profile_dir.location, self.config_file_name)
317 if self.overwrite or not os.path.exists(fname):
317 if self.overwrite or not os.path.exists(fname):
318 self.log.warn("Generating default config file: %r"%(fname))
318 self.log.warn("Generating default config file: %r"%(fname))
319 with open(fname, 'w') as f:
319 with open(fname, 'w') as f:
320 f.write(s)
320 f.write(s)
321
321
322 @catch_config_error
322 @catch_config_error
323 def initialize(self, argv=None):
323 def initialize(self, argv=None):
324 # don't hook up crash handler before parsing command-line
324 # don't hook up crash handler before parsing command-line
325 self.parse_command_line(argv)
325 self.parse_command_line(argv)
326 self.init_crash_handler()
326 self.init_crash_handler()
327 if self.subapp is not None:
327 if self.subapp is not None:
328 # stop here if subapp is taking over
328 # stop here if subapp is taking over
329 return
329 return
330 cl_config = self.config
330 cl_config = self.config
331 self.init_profile_dir()
331 self.init_profile_dir()
332 self.init_config_files()
332 self.init_config_files()
333 self.load_config_file()
333 self.load_config_file()
334 # enforce cl-opts override configfile opts:
334 # enforce cl-opts override configfile opts:
335 self.update_config(cl_config)
335 self.update_config(cl_config)
336
336
@@ -1,464 +1,464 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 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2011 The IPython Development Team
7 # Copyright (C) 2008-2011 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import os
17 import os
18 import sys
18 import sys
19 import tempfile
19 import tempfile
20 import warnings
20 import warnings
21 from hashlib import md5
21 from hashlib import md5
22
22
23 import IPython
23 import IPython
24 from IPython.utils.process import system
24 from IPython.utils.process import system
25 from IPython.utils.importstring import import_item
25 from IPython.utils.importstring import import_item
26 from IPython.utils import py3compat
26 from IPython.utils import py3compat
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Code
29 # Code
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32 fs_encoding = sys.getfilesystemencoding()
32 fs_encoding = sys.getfilesystemencoding()
33
33
34 def _get_long_path_name(path):
34 def _get_long_path_name(path):
35 """Dummy no-op."""
35 """Dummy no-op."""
36 return path
36 return path
37
37
38 def _writable_dir(path):
38 def _writable_dir(path):
39 """Whether `path` is a directory, to which the user has write access."""
39 """Whether `path` is a directory, to which the user has write access."""
40 return os.path.isdir(path) and os.access(path, os.W_OK)
40 return os.path.isdir(path) and os.access(path, os.W_OK)
41
41
42 if sys.platform == 'win32':
42 if sys.platform == 'win32':
43 def _get_long_path_name(path):
43 def _get_long_path_name(path):
44 """Get a long path name (expand ~) on Windows using ctypes.
44 """Get a long path name (expand ~) on Windows using ctypes.
45
45
46 Examples
46 Examples
47 --------
47 --------
48
48
49 >>> get_long_path_name('c:\\docume~1')
49 >>> get_long_path_name('c:\\docume~1')
50 u'c:\\\\Documents and Settings'
50 u'c:\\\\Documents and Settings'
51
51
52 """
52 """
53 try:
53 try:
54 import ctypes
54 import ctypes
55 except ImportError:
55 except ImportError:
56 raise ImportError('you need to have ctypes installed for this to work')
56 raise ImportError('you need to have ctypes installed for this to work')
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
57 _GetLongPathName = ctypes.windll.kernel32.GetLongPathNameW
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
58 _GetLongPathName.argtypes = [ctypes.c_wchar_p, ctypes.c_wchar_p,
59 ctypes.c_uint ]
59 ctypes.c_uint ]
60
60
61 buf = ctypes.create_unicode_buffer(260)
61 buf = ctypes.create_unicode_buffer(260)
62 rv = _GetLongPathName(path, buf, 260)
62 rv = _GetLongPathName(path, buf, 260)
63 if rv == 0 or rv > 260:
63 if rv == 0 or rv > 260:
64 return path
64 return path
65 else:
65 else:
66 return buf.value
66 return buf.value
67
67
68
68
69 def get_long_path_name(path):
69 def get_long_path_name(path):
70 """Expand a path into its long form.
70 """Expand a path into its long form.
71
71
72 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
73 a null operation.
73 a null operation.
74 """
74 """
75 return _get_long_path_name(path)
75 return _get_long_path_name(path)
76
76
77
77
78 def unquote_filename(name, win32=(sys.platform=='win32')):
78 def unquote_filename(name, win32=(sys.platform=='win32')):
79 """ On Windows, remove leading and trailing quotes from filenames.
79 """ On Windows, remove leading and trailing quotes from filenames.
80 """
80 """
81 if win32:
81 if win32:
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
82 if name.startswith(("'", '"')) and name.endswith(("'", '"')):
83 name = name[1:-1]
83 name = name[1:-1]
84 return name
84 return name
85
85
86
86
87 def get_py_filename(name, force_win32=None):
87 def get_py_filename(name, force_win32=None):
88 """Return a valid python filename in the current directory.
88 """Return a valid python filename in the current directory.
89
89
90 If the given name is not a file, it adds '.py' and searches again.
90 If the given name is not a file, it adds '.py' and searches again.
91 Raises IOError with an informative message if the file isn't found.
91 Raises IOError with an informative message if the file isn't found.
92
92
93 On Windows, apply Windows semantics to the filename. In particular, remove
93 On Windows, apply Windows semantics to the filename. In particular, remove
94 any quoting that has been applied to it. This option can be forced for
94 any quoting that has been applied to it. This option can be forced for
95 testing purposes.
95 testing purposes.
96 """
96 """
97
97
98 name = os.path.expanduser(name)
98 name = os.path.expanduser(name)
99 if force_win32 is None:
99 if force_win32 is None:
100 win32 = (sys.platform == 'win32')
100 win32 = (sys.platform == 'win32')
101 else:
101 else:
102 win32 = force_win32
102 win32 = force_win32
103 name = unquote_filename(name, win32=win32)
103 name = unquote_filename(name, win32=win32)
104 if not os.path.isfile(name) and not name.endswith('.py'):
104 if not os.path.isfile(name) and not name.endswith('.py'):
105 name += '.py'
105 name += '.py'
106 if os.path.isfile(name):
106 if os.path.isfile(name):
107 return name
107 return name
108 else:
108 else:
109 raise IOError,'File `%r` not found.' % name
109 raise IOError,'File `%r` not found.' % name
110
110
111
111
112 def filefind(filename, path_dirs=None):
112 def filefind(filename, path_dirs=None):
113 """Find a file by looking through a sequence of paths.
113 """Find a file by looking through a sequence of paths.
114
114
115 This iterates through a sequence of paths looking for a file and returns
115 This iterates through a sequence of paths looking for a file and returns
116 the full, absolute path of the first occurence of the file. If no set of
116 the full, absolute path of the first occurence of the file. If no set of
117 path dirs is given, the filename is tested as is, after running through
117 path dirs is given, the filename is tested as is, after running through
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
118 :func:`expandvars` and :func:`expanduser`. Thus a simple call::
119
119
120 filefind('myfile.txt')
120 filefind('myfile.txt')
121
121
122 will find the file in the current working dir, but::
122 will find the file in the current working dir, but::
123
123
124 filefind('~/myfile.txt')
124 filefind('~/myfile.txt')
125
125
126 Will find the file in the users home directory. This function does not
126 Will find the file in the users home directory. This function does not
127 automatically try any paths, such as the cwd or the user's home directory.
127 automatically try any paths, such as the cwd or the user's home directory.
128
128
129 Parameters
129 Parameters
130 ----------
130 ----------
131 filename : str
131 filename : str
132 The filename to look for.
132 The filename to look for.
133 path_dirs : str, None or sequence of str
133 path_dirs : str, None or sequence of str
134 The sequence of paths to look for the file in. If None, the filename
134 The sequence of paths to look for the file in. If None, the filename
135 need to be absolute or be in the cwd. If a string, the string is
135 need to be absolute or be in the cwd. If a string, the string is
136 put into a sequence and the searched. If a sequence, walk through
136 put into a sequence and the searched. If a sequence, walk through
137 each element and join with ``filename``, calling :func:`expandvars`
137 each element and join with ``filename``, calling :func:`expandvars`
138 and :func:`expanduser` before testing for existence.
138 and :func:`expanduser` before testing for existence.
139
139
140 Returns
140 Returns
141 -------
141 -------
142 Raises :exc:`IOError` or returns absolute path to file.
142 Raises :exc:`IOError` or returns absolute path to file.
143 """
143 """
144
144
145 # If paths are quoted, abspath gets confused, strip them...
145 # If paths are quoted, abspath gets confused, strip them...
146 filename = filename.strip('"').strip("'")
146 filename = filename.strip('"').strip("'")
147 # If the input is an absolute path, just check it exists
147 # If the input is an absolute path, just check it exists
148 if os.path.isabs(filename) and os.path.isfile(filename):
148 if os.path.isabs(filename) and os.path.isfile(filename):
149 return filename
149 return filename
150
150
151 if path_dirs is None:
151 if path_dirs is None:
152 path_dirs = ("",)
152 path_dirs = ("",)
153 elif isinstance(path_dirs, basestring):
153 elif isinstance(path_dirs, basestring):
154 path_dirs = (path_dirs,)
154 path_dirs = (path_dirs,)
155
155
156 for path in path_dirs:
156 for path in path_dirs:
157 if path == '.': path = os.getcwdu()
157 if path == '.': path = os.getcwdu()
158 testname = expand_path(os.path.join(path, filename))
158 testname = expand_path(os.path.join(path, filename))
159 if os.path.isfile(testname):
159 if os.path.isfile(testname):
160 return os.path.abspath(testname)
160 return os.path.abspath(testname)
161
161
162 raise IOError("File %r does not exist in any of the search paths: %r" %
162 raise IOError("File %r does not exist in any of the search paths: %r" %
163 (filename, path_dirs) )
163 (filename, path_dirs) )
164
164
165
165
166 class HomeDirError(Exception):
166 class HomeDirError(Exception):
167 pass
167 pass
168
168
169
169
170 def get_home_dir(require_writable=False):
170 def get_home_dir(require_writable=False):
171 """Return the 'home' directory, as a unicode string.
171 """Return the 'home' directory, as a unicode string.
172
172
173 * First, check for frozen env in case of py2exe
173 * First, check for frozen env in case of py2exe
174 * Otherwise, defer to os.path.expanduser('~')
174 * Otherwise, defer to os.path.expanduser('~')
175
175
176 See stdlib docs for how this is determined.
176 See stdlib docs for how this is determined.
177 $HOME is first priority on *ALL* platforms.
177 $HOME is first priority on *ALL* platforms.
178
178
179 Parameters
179 Parameters
180 ----------
180 ----------
181
181
182 require_writable : bool [default: False]
182 require_writable : bool [default: False]
183 if True:
183 if True:
184 guarantees the return value is a writable directory, otherwise
184 guarantees the return value is a writable directory, otherwise
185 raises HomeDirError
185 raises HomeDirError
186 if False:
186 if False:
187 The path is resolved, but it is not guaranteed to exist or be writable.
187 The path is resolved, but it is not guaranteed to exist or be writable.
188 """
188 """
189
189
190 # first, check py2exe distribution root directory for _ipython.
190 # first, check py2exe distribution root directory for _ipython.
191 # This overrides all. Normally does not exist.
191 # This overrides all. Normally does not exist.
192
192
193 if hasattr(sys, "frozen"): #Is frozen by py2exe
193 if hasattr(sys, "frozen"): #Is frozen by py2exe
194 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
194 if '\\library.zip\\' in IPython.__file__.lower():#libraries compressed to zip-file
195 root, rest = IPython.__file__.lower().split('library.zip')
195 root, rest = IPython.__file__.lower().split('library.zip')
196 else:
196 else:
197 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
197 root=os.path.join(os.path.split(IPython.__file__)[0],"../../")
198 root=os.path.abspath(root).rstrip('\\')
198 root=os.path.abspath(root).rstrip('\\')
199 if _writable_dir(os.path.join(root, '_ipython')):
199 if _writable_dir(os.path.join(root, '_ipython')):
200 os.environ["IPYKITROOT"] = root
200 os.environ["IPYKITROOT"] = root
201 return py3compat.cast_unicode(root, fs_encoding)
201 return py3compat.cast_unicode(root, fs_encoding)
202
202
203 homedir = os.path.expanduser('~')
203 homedir = os.path.expanduser('~')
204 # Next line will make things work even when /home/ is a symlink to
204 # Next line will make things work even when /home/ is a symlink to
205 # /usr/home as it is on FreeBSD, for example
205 # /usr/home as it is on FreeBSD, for example
206 homedir = os.path.realpath(homedir)
206 homedir = os.path.realpath(homedir)
207
207
208 if not _writable_dir(homedir) and os.name == 'nt':
208 if not _writable_dir(homedir) and os.name == 'nt':
209 # expanduser failed, use the registry to get the 'My Documents' folder.
209 # expanduser failed, use the registry to get the 'My Documents' folder.
210 try:
210 try:
211 import _winreg as wreg
211 import _winreg as wreg
212 key = wreg.OpenKey(
212 key = wreg.OpenKey(
213 wreg.HKEY_CURRENT_USER,
213 wreg.HKEY_CURRENT_USER,
214 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
214 "Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
215 )
215 )
216 homedir = wreg.QueryValueEx(key,'Personal')[0]
216 homedir = wreg.QueryValueEx(key,'Personal')[0]
217 key.Close()
217 key.Close()
218 except:
218 except:
219 pass
219 pass
220
220
221 if (not require_writable) or _writable_dir(homedir):
221 if (not require_writable) or _writable_dir(homedir):
222 return py3compat.cast_unicode(homedir, fs_encoding)
222 return py3compat.cast_unicode(homedir, fs_encoding)
223 else:
223 else:
224 raise HomeDirError('%s is not a writable dir, '
224 raise HomeDirError('%s is not a writable dir, '
225 'set $HOME environment variable to override' % homedir)
225 'set $HOME environment variable to override' % homedir)
226
226
227 def get_xdg_dir():
227 def get_xdg_dir():
228 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
228 """Return the XDG_CONFIG_HOME, if it is defined and exists, else None.
229
229
230 This is only for posix (Linux,Unix,OS X, etc) systems.
230 This is only for posix (Linux,Unix,OS X, etc) systems.
231 """
231 """
232
232
233 env = os.environ
233 env = os.environ
234
234
235 if os.name == 'posix':
235 if os.name == 'posix':
236 # Linux, Unix, AIX, OS X
236 # Linux, Unix, AIX, OS X
237 # use ~/.config if empty OR not set
237 # use ~/.config if empty OR not set
238 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
238 xdg = env.get("XDG_CONFIG_HOME", None) or os.path.join(get_home_dir(), '.config')
239 if xdg and _writable_dir(xdg):
239 if xdg and _writable_dir(xdg):
240 return py3compat.cast_unicode(xdg, fs_encoding)
240 return py3compat.cast_unicode(xdg, fs_encoding)
241
241
242 return None
242 return None
243
243
244
244
245 def get_ipython_dir():
245 def get_ipython_dir():
246 """Get the IPython directory for this platform and user.
246 """Get the IPython directory for this platform and user.
247
247
248 This uses the logic in `get_home_dir` to find the home directory
248 This uses the logic in `get_home_dir` to find the home directory
249 and then adds .ipython to the end of the path.
249 and then adds .ipython to the end of the path.
250 """
250 """
251
251
252 env = os.environ
252 env = os.environ
253 pjoin = os.path.join
253 pjoin = os.path.join
254
254
255
255
256 ipdir_def = '.ipython'
256 ipdir_def = '.ipython'
257 xdg_def = 'ipython'
257 xdg_def = 'ipython'
258
258
259 home_dir = get_home_dir()
259 home_dir = get_home_dir()
260 xdg_dir = get_xdg_dir()
260 xdg_dir = get_xdg_dir()
261
261
262 # import pdb; pdb.set_trace() # dbg
262 # import pdb; pdb.set_trace() # dbg
263 ipdir = env.get('IPYTHON_DIR', env.get('IPYTHONDIR', None))
263 ipdir = env.get('IPYTHONDIR', env.get('IPYTHON_DIR', None))
264 if ipdir is None:
264 if ipdir is None:
265 # not set explicitly, use XDG_CONFIG_HOME or HOME
265 # not set explicitly, use XDG_CONFIG_HOME or HOME
266 home_ipdir = pjoin(home_dir, ipdir_def)
266 home_ipdir = pjoin(home_dir, ipdir_def)
267 if xdg_dir:
267 if xdg_dir:
268 # use XDG, as long as the user isn't already
268 # use XDG, as long as the user isn't already
269 # using $HOME/.ipython and *not* XDG/ipython
269 # using $HOME/.ipython and *not* XDG/ipython
270
270
271 xdg_ipdir = pjoin(xdg_dir, xdg_def)
271 xdg_ipdir = pjoin(xdg_dir, xdg_def)
272
272
273 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
273 if _writable_dir(xdg_ipdir) or not _writable_dir(home_ipdir):
274 ipdir = xdg_ipdir
274 ipdir = xdg_ipdir
275
275
276 if ipdir is None:
276 if ipdir is None:
277 # not using XDG
277 # not using XDG
278 ipdir = home_ipdir
278 ipdir = home_ipdir
279
279
280 ipdir = os.path.normpath(os.path.expanduser(ipdir))
280 ipdir = os.path.normpath(os.path.expanduser(ipdir))
281
281
282 if os.path.exists(ipdir) and not _writable_dir(ipdir):
282 if os.path.exists(ipdir) and not _writable_dir(ipdir):
283 # ipdir exists, but is not writable
283 # ipdir exists, but is not writable
284 warnings.warn("IPython dir '%s' is not a writable location,"
284 warnings.warn("IPython dir '%s' is not a writable location,"
285 " using a temp directory."%ipdir)
285 " using a temp directory."%ipdir)
286 ipdir = tempfile.mkdtemp()
286 ipdir = tempfile.mkdtemp()
287 elif not os.path.exists(ipdir):
287 elif not os.path.exists(ipdir):
288 parent = ipdir.rsplit(os.path.sep, 1)[0]
288 parent = ipdir.rsplit(os.path.sep, 1)[0]
289 if not _writable_dir(parent):
289 if not _writable_dir(parent):
290 # ipdir does not exist and parent isn't writable
290 # ipdir does not exist and parent isn't writable
291 warnings.warn("IPython parent '%s' is not a writable location,"
291 warnings.warn("IPython parent '%s' is not a writable location,"
292 " using a temp directory."%parent)
292 " using a temp directory."%parent)
293 ipdir = tempfile.mkdtemp()
293 ipdir = tempfile.mkdtemp()
294
294
295 return py3compat.cast_unicode(ipdir, fs_encoding)
295 return py3compat.cast_unicode(ipdir, fs_encoding)
296
296
297
297
298 def get_ipython_package_dir():
298 def get_ipython_package_dir():
299 """Get the base directory where IPython itself is installed."""
299 """Get the base directory where IPython itself is installed."""
300 ipdir = os.path.dirname(IPython.__file__)
300 ipdir = os.path.dirname(IPython.__file__)
301 return py3compat.cast_unicode(ipdir, fs_encoding)
301 return py3compat.cast_unicode(ipdir, fs_encoding)
302
302
303
303
304 def get_ipython_module_path(module_str):
304 def get_ipython_module_path(module_str):
305 """Find the path to an IPython module in this version of IPython.
305 """Find the path to an IPython module in this version of IPython.
306
306
307 This will always find the version of the module that is in this importable
307 This will always find the version of the module that is in this importable
308 IPython package. This will always return the path to the ``.py``
308 IPython package. This will always return the path to the ``.py``
309 version of the module.
309 version of the module.
310 """
310 """
311 if module_str == 'IPython':
311 if module_str == 'IPython':
312 return os.path.join(get_ipython_package_dir(), '__init__.py')
312 return os.path.join(get_ipython_package_dir(), '__init__.py')
313 mod = import_item(module_str)
313 mod = import_item(module_str)
314 the_path = mod.__file__.replace('.pyc', '.py')
314 the_path = mod.__file__.replace('.pyc', '.py')
315 the_path = the_path.replace('.pyo', '.py')
315 the_path = the_path.replace('.pyo', '.py')
316 return py3compat.cast_unicode(the_path, fs_encoding)
316 return py3compat.cast_unicode(the_path, fs_encoding)
317
317
318 def locate_profile(profile='default'):
318 def locate_profile(profile='default'):
319 """Find the path to the folder associated with a given profile.
319 """Find the path to the folder associated with a given profile.
320
320
321 I.e. find $IPYTHONDIR/profile_whatever.
321 I.e. find $IPYTHONDIR/profile_whatever.
322 """
322 """
323 from IPython.core.profiledir import ProfileDir, ProfileDirError
323 from IPython.core.profiledir import ProfileDir, ProfileDirError
324 try:
324 try:
325 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
325 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
326 except ProfileDirError:
326 except ProfileDirError:
327 # IOError makes more sense when people are expecting a path
327 # IOError makes more sense when people are expecting a path
328 raise IOError("Couldn't find profile %r" % profile)
328 raise IOError("Couldn't find profile %r" % profile)
329 return pd.location
329 return pd.location
330
330
331 def expand_path(s):
331 def expand_path(s):
332 """Expand $VARS and ~names in a string, like a shell
332 """Expand $VARS and ~names in a string, like a shell
333
333
334 :Examples:
334 :Examples:
335
335
336 In [2]: os.environ['FOO']='test'
336 In [2]: os.environ['FOO']='test'
337
337
338 In [3]: expand_path('variable FOO is $FOO')
338 In [3]: expand_path('variable FOO is $FOO')
339 Out[3]: 'variable FOO is test'
339 Out[3]: 'variable FOO is test'
340 """
340 """
341 # This is a pretty subtle hack. When expand user is given a UNC path
341 # This is a pretty subtle hack. When expand user is given a UNC path
342 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
342 # on Windows (\\server\share$\%username%), os.path.expandvars, removes
343 # the $ to get (\\server\share\%username%). I think it considered $
343 # the $ to get (\\server\share\%username%). I think it considered $
344 # alone an empty var. But, we need the $ to remains there (it indicates
344 # alone an empty var. But, we need the $ to remains there (it indicates
345 # a hidden share).
345 # a hidden share).
346 if os.name=='nt':
346 if os.name=='nt':
347 s = s.replace('$\\', 'IPYTHON_TEMP')
347 s = s.replace('$\\', 'IPYTHON_TEMP')
348 s = os.path.expandvars(os.path.expanduser(s))
348 s = os.path.expandvars(os.path.expanduser(s))
349 if os.name=='nt':
349 if os.name=='nt':
350 s = s.replace('IPYTHON_TEMP', '$\\')
350 s = s.replace('IPYTHON_TEMP', '$\\')
351 return s
351 return s
352
352
353
353
354 def target_outdated(target,deps):
354 def target_outdated(target,deps):
355 """Determine whether a target is out of date.
355 """Determine whether a target is out of date.
356
356
357 target_outdated(target,deps) -> 1/0
357 target_outdated(target,deps) -> 1/0
358
358
359 deps: list of filenames which MUST exist.
359 deps: list of filenames which MUST exist.
360 target: single filename which may or may not exist.
360 target: single filename which may or may not exist.
361
361
362 If target doesn't exist or is older than any file listed in deps, return
362 If target doesn't exist or is older than any file listed in deps, return
363 true, otherwise return false.
363 true, otherwise return false.
364 """
364 """
365 try:
365 try:
366 target_time = os.path.getmtime(target)
366 target_time = os.path.getmtime(target)
367 except os.error:
367 except os.error:
368 return 1
368 return 1
369 for dep in deps:
369 for dep in deps:
370 dep_time = os.path.getmtime(dep)
370 dep_time = os.path.getmtime(dep)
371 if dep_time > target_time:
371 if dep_time > target_time:
372 #print "For target",target,"Dep failed:",dep # dbg
372 #print "For target",target,"Dep failed:",dep # dbg
373 #print "times (dep,tar):",dep_time,target_time # dbg
373 #print "times (dep,tar):",dep_time,target_time # dbg
374 return 1
374 return 1
375 return 0
375 return 0
376
376
377
377
378 def target_update(target,deps,cmd):
378 def target_update(target,deps,cmd):
379 """Update a target with a given command given a list of dependencies.
379 """Update a target with a given command given a list of dependencies.
380
380
381 target_update(target,deps,cmd) -> runs cmd if target is outdated.
381 target_update(target,deps,cmd) -> runs cmd if target is outdated.
382
382
383 This is just a wrapper around target_outdated() which calls the given
383 This is just a wrapper around target_outdated() which calls the given
384 command if target is outdated."""
384 command if target is outdated."""
385
385
386 if target_outdated(target,deps):
386 if target_outdated(target,deps):
387 system(cmd)
387 system(cmd)
388
388
389 def filehash(path):
389 def filehash(path):
390 """Make an MD5 hash of a file, ignoring any differences in line
390 """Make an MD5 hash of a file, ignoring any differences in line
391 ending characters."""
391 ending characters."""
392 with open(path, "rU") as f:
392 with open(path, "rU") as f:
393 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
393 return md5(py3compat.str_to_bytes(f.read())).hexdigest()
394
394
395 # If the config is unmodified from the default, we'll just delete it.
395 # If the config is unmodified from the default, we'll just delete it.
396 # These are consistent for 0.10.x, thankfully. We're not going to worry about
396 # These are consistent for 0.10.x, thankfully. We're not going to worry about
397 # older versions.
397 # older versions.
398 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
398 old_config_md5 = {'ipy_user_conf.py': 'fc108bedff4b9a00f91fa0a5999140d3',
399 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
399 'ipythonrc': '12a68954f3403eea2eec09dc8fe5a9b5'}
400
400
401 def check_for_old_config(ipython_dir=None):
401 def check_for_old_config(ipython_dir=None):
402 """Check for old config files, and present a warning if they exist.
402 """Check for old config files, and present a warning if they exist.
403
403
404 A link to the docs of the new config is included in the message.
404 A link to the docs of the new config is included in the message.
405
405
406 This should mitigate confusion with the transition to the new
406 This should mitigate confusion with the transition to the new
407 config system in 0.11.
407 config system in 0.11.
408 """
408 """
409 if ipython_dir is None:
409 if ipython_dir is None:
410 ipython_dir = get_ipython_dir()
410 ipython_dir = get_ipython_dir()
411
411
412 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
412 old_configs = ['ipy_user_conf.py', 'ipythonrc', 'ipython_config.py']
413 warned = False
413 warned = False
414 for cfg in old_configs:
414 for cfg in old_configs:
415 f = os.path.join(ipython_dir, cfg)
415 f = os.path.join(ipython_dir, cfg)
416 if os.path.exists(f):
416 if os.path.exists(f):
417 if filehash(f) == old_config_md5.get(cfg, ''):
417 if filehash(f) == old_config_md5.get(cfg, ''):
418 os.unlink(f)
418 os.unlink(f)
419 else:
419 else:
420 warnings.warn("Found old IPython config file %r (modified by user)"%f)
420 warnings.warn("Found old IPython config file %r (modified by user)"%f)
421 warned = True
421 warned = True
422
422
423 if warned:
423 if warned:
424 warnings.warn("""
424 warnings.warn("""
425 The IPython configuration system has changed as of 0.11, and these files will
425 The IPython configuration system has changed as of 0.11, and these files will
426 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
426 be ignored. See http://ipython.github.com/ipython-doc/dev/config for details
427 of the new config system.
427 of the new config system.
428 To start configuring IPython, do `ipython profile create`, and edit
428 To start configuring IPython, do `ipython profile create`, and edit
429 `ipython_config.py` in <ipython_dir>/profile_default.
429 `ipython_config.py` in <ipython_dir>/profile_default.
430 If you need to leave the old config files in place for an older version of
430 If you need to leave the old config files in place for an older version of
431 IPython and want to suppress this warning message, set
431 IPython and want to suppress this warning message, set
432 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
432 `c.InteractiveShellApp.ignore_old_config=True` in the new config.""")
433
433
434 def get_security_file(filename, profile='default'):
434 def get_security_file(filename, profile='default'):
435 """Return the absolute path of a security file given by filename and profile
435 """Return the absolute path of a security file given by filename and profile
436
436
437 This allows users and developers to find security files without
437 This allows users and developers to find security files without
438 knowledge of the IPython directory structure. The search path
438 knowledge of the IPython directory structure. The search path
439 will be ['.', profile.security_dir]
439 will be ['.', profile.security_dir]
440
440
441 Parameters
441 Parameters
442 ----------
442 ----------
443
443
444 filename : str
444 filename : str
445 The file to be found. If it is passed as an absolute path, it will
445 The file to be found. If it is passed as an absolute path, it will
446 simply be returned.
446 simply be returned.
447 profile : str [default: 'default']
447 profile : str [default: 'default']
448 The name of the profile to search. Leaving this unspecified
448 The name of the profile to search. Leaving this unspecified
449 The file to be found. If it is passed as an absolute path, fname will
449 The file to be found. If it is passed as an absolute path, fname will
450 simply be returned.
450 simply be returned.
451
451
452 Returns
452 Returns
453 -------
453 -------
454 Raises :exc:`IOError` if file not found or returns absolute path to file.
454 Raises :exc:`IOError` if file not found or returns absolute path to file.
455 """
455 """
456 # import here, because profiledir also imports from utils.path
456 # import here, because profiledir also imports from utils.path
457 from IPython.core.profiledir import ProfileDir
457 from IPython.core.profiledir import ProfileDir
458 try:
458 try:
459 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
459 pd = ProfileDir.find_profile_dir_by_name(get_ipython_dir(), profile)
460 except Exception:
460 except Exception:
461 # will raise ProfileDirError if no such profile
461 # will raise ProfileDirError if no such profile
462 raise IOError("Profile %r not found")
462 raise IOError("Profile %r not found")
463 return filefind(filename, ['.', pd.security_dir])
463 return filefind(filename, ['.', pd.security_dir])
464
464
General Comments 0
You need to be logged in to leave comments. Login now