##// END OF EJS Templates
Revert to using single default profile for Python 2 and 3.
Thomas Kluyver -
Show More
@@ -1,321 +1,319 b''
1 1 # encoding: utf-8
2 2 """
3 3 An application for IPython.
4 4
5 5 All top-level applications should use the classes in this module for
6 6 handling configuration and creating componenets.
7 7
8 8 The job of an :class:`Application` is to create the master configuration
9 9 object and then create the configurable objects, passing the config to them.
10 10
11 11 Authors:
12 12
13 13 * Brian Granger
14 14 * Fernando Perez
15 15 * Min RK
16 16
17 17 """
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Copyright (C) 2008-2011 The IPython Development Team
21 21 #
22 22 # Distributed under the terms of the BSD License. The full license is in
23 23 # the file COPYING, distributed as part of this software.
24 24 #-----------------------------------------------------------------------------
25 25
26 26 #-----------------------------------------------------------------------------
27 27 # Imports
28 28 #-----------------------------------------------------------------------------
29 29
30 30 import atexit
31 31 import glob
32 32 import logging
33 33 import os
34 34 import shutil
35 35 import sys
36 36
37 37 from IPython.config.application import Application, catch_config_error
38 38 from IPython.config.configurable import Configurable
39 39 from IPython.config.loader import Config, ConfigFileNotFound
40 40 from IPython.core import release, crashhandler
41 41 from IPython.core.profiledir import ProfileDir, ProfileDirError
42 42 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
43 43 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict
44 44 from IPython.utils import py3compat
45 45
46 46 #-----------------------------------------------------------------------------
47 47 # Classes and functions
48 48 #-----------------------------------------------------------------------------
49 49
50 50
51 51 #-----------------------------------------------------------------------------
52 52 # Base Application Class
53 53 #-----------------------------------------------------------------------------
54 54
55 55 # aliases and flags
56 56
57 57 base_aliases = {
58 58 'profile' : 'BaseIPythonApplication.profile',
59 59 'ipython-dir' : 'BaseIPythonApplication.ipython_dir',
60 60 'log-level' : 'Application.log_level',
61 61 }
62 62
63 63 base_flags = dict(
64 64 debug = ({'Application' : {'log_level' : logging.DEBUG}},
65 65 "set log level to logging.DEBUG (maximize logging output)"),
66 66 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
67 67 "set log level to logging.CRITICAL (minimize logging output)"),
68 68 init = ({'BaseIPythonApplication' : {
69 69 'copy_config_files' : True,
70 70 'auto_create' : True}
71 71 }, """Initialize profile with default config files. This is equivalent
72 72 to running `ipython profile create <profile>` prior to startup.
73 73 """)
74 74 )
75 75
76 76
77 77 class BaseIPythonApplication(Application):
78 78
79 79 name = Unicode(u'ipython')
80 80 description = Unicode(u'IPython: an enhanced interactive Python shell.')
81 81 version = Unicode(release.version)
82 82
83 83 aliases = Dict(base_aliases)
84 84 flags = Dict(base_flags)
85 85 classes = List([ProfileDir])
86 86
87 87 # Track whether the config_file has changed,
88 88 # because some logic happens only if we aren't using the default.
89 89 config_file_specified = Bool(False)
90 90
91 91 config_file_name = Unicode(u'ipython_config.py')
92 92 def _config_file_name_default(self):
93 93 return self.name.replace('-','_') + u'_config.py'
94 94 def _config_file_name_changed(self, name, old, new):
95 95 if new != old:
96 96 self.config_file_specified = True
97 97
98 98 # The directory that contains IPython's builtin profiles.
99 99 builtin_profile_dir = Unicode(
100 100 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
101 101 )
102 102
103 103 config_file_paths = List(Unicode)
104 104 def _config_file_paths_default(self):
105 105 return [os.getcwdu()]
106 106
107 profile = Unicode(u'', config=True,
107 profile = Unicode(u'default', config=True,
108 108 help="""The IPython profile to use."""
109 109 )
110 def _profile_default(self):
111 return "python3" if py3compat.PY3 else "default"
112 110
113 111 def _profile_changed(self, name, old, new):
114 112 self.builtin_profile_dir = os.path.join(
115 113 get_ipython_package_dir(), u'config', u'profile', new
116 114 )
117 115
118 116 ipython_dir = Unicode(get_ipython_dir(), config=True,
119 117 help="""
120 118 The name of the IPython directory. This directory is used for logging
121 119 configuration (through profiles), history storage, etc. The default
122 120 is usually $HOME/.ipython. This options can also be specified through
123 121 the environment variable IPYTHON_DIR.
124 122 """
125 123 )
126 124
127 125 overwrite = Bool(False, config=True,
128 126 help="""Whether to overwrite existing config files when copying""")
129 127 auto_create = Bool(False, config=True,
130 128 help="""Whether to create profile dir if it doesn't exist""")
131 129
132 130 config_files = List(Unicode)
133 131 def _config_files_default(self):
134 132 return [u'ipython_config.py']
135 133
136 134 copy_config_files = Bool(False, config=True,
137 135 help="""Whether to install the default config files into the profile dir.
138 136 If a new profile is being created, and IPython contains config files for that
139 137 profile, then they will be staged into the new directory. Otherwise,
140 138 default config files will be automatically generated.
141 139 """)
142 140
143 141 # The class to use as the crash handler.
144 142 crash_handler_class = Type(crashhandler.CrashHandler)
145 143
146 144 def __init__(self, **kwargs):
147 145 super(BaseIPythonApplication, self).__init__(**kwargs)
148 146 # ensure even default IPYTHON_DIR exists
149 147 if not os.path.exists(self.ipython_dir):
150 148 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
151 149
152 150 #-------------------------------------------------------------------------
153 151 # Various stages of Application creation
154 152 #-------------------------------------------------------------------------
155 153
156 154 def init_crash_handler(self):
157 155 """Create a crash handler, typically setting sys.excepthook to it."""
158 156 self.crash_handler = self.crash_handler_class(self)
159 157 sys.excepthook = self.crash_handler
160 158 def unset_crashhandler():
161 159 sys.excepthook = sys.__excepthook__
162 160 atexit.register(unset_crashhandler)
163 161
164 162 def _ipython_dir_changed(self, name, old, new):
165 163 if old in sys.path:
166 164 sys.path.remove(old)
167 165 sys.path.append(os.path.abspath(new))
168 166 if not os.path.isdir(new):
169 167 os.makedirs(new, mode=0777)
170 168 readme = os.path.join(new, 'README')
171 169 if not os.path.exists(readme):
172 170 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
173 171 shutil.copy(os.path.join(path, 'README'), readme)
174 172 self.log.debug("IPYTHON_DIR set to: %s" % new)
175 173
176 174 def load_config_file(self, suppress_errors=True):
177 175 """Load the config file.
178 176
179 177 By default, errors in loading config are handled, and a warning
180 178 printed on screen. For testing, the suppress_errors option is set
181 179 to False, so errors will make tests fail.
182 180 """
183 181 self.log.debug("Searching path %s for config files", self.config_file_paths)
184 182 base_config = 'ipython_config.py'
185 183 self.log.debug("Attempting to load config file: %s" %
186 184 base_config)
187 185 try:
188 186 Application.load_config_file(
189 187 self,
190 188 base_config,
191 189 path=self.config_file_paths
192 190 )
193 191 except ConfigFileNotFound:
194 192 # ignore errors loading parent
195 193 self.log.debug("Config file %s not found", base_config)
196 194 pass
197 195 if self.config_file_name == base_config:
198 196 # don't load secondary config
199 197 return
200 198 self.log.debug("Attempting to load config file: %s" %
201 199 self.config_file_name)
202 200 try:
203 201 Application.load_config_file(
204 202 self,
205 203 self.config_file_name,
206 204 path=self.config_file_paths
207 205 )
208 206 except ConfigFileNotFound:
209 207 # Only warn if the default config file was NOT being used.
210 208 if self.config_file_specified:
211 209 msg = self.log.warn
212 210 else:
213 211 msg = self.log.debug
214 212 msg("Config file not found, skipping: %s", self.config_file_name)
215 213 except:
216 214 # For testing purposes.
217 215 if not suppress_errors:
218 216 raise
219 217 self.log.warn("Error loading config file: %s" %
220 218 self.config_file_name, exc_info=True)
221 219
222 220 def init_profile_dir(self):
223 221 """initialize the profile dir"""
224 222 try:
225 223 # location explicitly specified:
226 224 location = self.config.ProfileDir.location
227 225 except AttributeError:
228 226 # location not specified, find by profile name
229 227 try:
230 228 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
231 229 except ProfileDirError:
232 230 # not found, maybe create it (always create default profile)
233 if self.auto_create or self.profile==self._profile_default():
231 if self.auto_create or self.profile=='default':
234 232 try:
235 233 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
236 234 except ProfileDirError:
237 235 self.log.fatal("Could not create profile: %r"%self.profile)
238 236 self.exit(1)
239 237 else:
240 238 self.log.info("Created profile dir: %r"%p.location)
241 239 else:
242 240 self.log.fatal("Profile %r not found."%self.profile)
243 241 self.exit(1)
244 242 else:
245 243 self.log.info("Using existing profile dir: %r"%p.location)
246 244 else:
247 245 # location is fully specified
248 246 try:
249 247 p = ProfileDir.find_profile_dir(location, self.config)
250 248 except ProfileDirError:
251 249 # not found, maybe create it
252 250 if self.auto_create:
253 251 try:
254 252 p = ProfileDir.create_profile_dir(location, self.config)
255 253 except ProfileDirError:
256 254 self.log.fatal("Could not create profile directory: %r"%location)
257 255 self.exit(1)
258 256 else:
259 257 self.log.info("Creating new profile dir: %r"%location)
260 258 else:
261 259 self.log.fatal("Profile directory %r not found."%location)
262 260 self.exit(1)
263 261 else:
264 262 self.log.info("Using existing profile dir: %r"%location)
265 263
266 264 self.profile_dir = p
267 265 self.config_file_paths.append(p.location)
268 266
269 267 def init_config_files(self):
270 268 """[optionally] copy default config files into profile dir."""
271 269 # copy config files
272 270 path = self.builtin_profile_dir
273 271 if self.copy_config_files:
274 272 src = self.profile
275 273
276 274 cfg = self.config_file_name
277 275 if path and os.path.exists(os.path.join(path, cfg)):
278 276 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
279 277 cfg, src, self.profile_dir.location, self.overwrite)
280 278 )
281 279 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
282 280 else:
283 281 self.stage_default_config_file()
284 282 else:
285 283 # Still stage *bundled* config files, but not generated ones
286 284 # This is necessary for `ipython profile=sympy` to load the profile
287 285 # on the first go
288 286 files = glob.glob(os.path.join(path, '*.py'))
289 287 for fullpath in files:
290 288 cfg = os.path.basename(fullpath)
291 289 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
292 290 # file was copied
293 291 self.log.warn("Staging bundled %s from %s into %r"%(
294 292 cfg, self.profile, self.profile_dir.location)
295 293 )
296 294
297 295
298 296 def stage_default_config_file(self):
299 297 """auto generate default config file, and stage it into the profile."""
300 298 s = self.generate_config_file()
301 299 fname = os.path.join(self.profile_dir.location, self.config_file_name)
302 300 if self.overwrite or not os.path.exists(fname):
303 301 self.log.warn("Generating default config file: %r"%(fname))
304 302 with open(fname, 'w') as f:
305 303 f.write(s)
306 304
307 305 @catch_config_error
308 306 def initialize(self, argv=None):
309 307 # don't hook up crash handler before parsing command-line
310 308 self.parse_command_line(argv)
311 309 self.init_crash_handler()
312 310 if self.subapp is not None:
313 311 # stop here if subapp is taking over
314 312 return
315 313 cl_config = self.config
316 314 self.init_profile_dir()
317 315 self.init_config_files()
318 316 self.load_config_file()
319 317 # enforce cl-opts override configfile opts:
320 318 self.update_config(cl_config)
321 319
General Comments 0
You need to be logged in to leave comments. Login now