##// END OF EJS Templates
Revert to using single default profile for Python 2 and 3.
Thomas Kluyver -
Show More
@@ -1,321 +1,319
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'', 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 def _profile_default(self):
111 return "python3" if py3compat.PY3 else "default"
112
110
113 def _profile_changed(self, name, old, new):
111 def _profile_changed(self, name, old, new):
114 self.builtin_profile_dir = os.path.join(
112 self.builtin_profile_dir = os.path.join(
115 get_ipython_package_dir(), u'config', u'profile', new
113 get_ipython_package_dir(), u'config', u'profile', new
116 )
114 )
117
115
118 ipython_dir = Unicode(get_ipython_dir(), config=True,
116 ipython_dir = Unicode(get_ipython_dir(), config=True,
119 help="""
117 help="""
120 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
121 configuration (through profiles), history storage, etc. The default
119 configuration (through profiles), history storage, etc. The default
122 is usually $HOME/.ipython. This options can also be specified through
120 is usually $HOME/.ipython. This options can also be specified through
123 the environment variable IPYTHON_DIR.
121 the environment variable IPYTHON_DIR.
124 """
122 """
125 )
123 )
126
124
127 overwrite = Bool(False, config=True,
125 overwrite = Bool(False, config=True,
128 help="""Whether to overwrite existing config files when copying""")
126 help="""Whether to overwrite existing config files when copying""")
129 auto_create = Bool(False, config=True,
127 auto_create = Bool(False, config=True,
130 help="""Whether to create profile dir if it doesn't exist""")
128 help="""Whether to create profile dir if it doesn't exist""")
131
129
132 config_files = List(Unicode)
130 config_files = List(Unicode)
133 def _config_files_default(self):
131 def _config_files_default(self):
134 return [u'ipython_config.py']
132 return [u'ipython_config.py']
135
133
136 copy_config_files = Bool(False, config=True,
134 copy_config_files = Bool(False, config=True,
137 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.
138 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
139 profile, then they will be staged into the new directory. Otherwise,
137 profile, then they will be staged into the new directory. Otherwise,
140 default config files will be automatically generated.
138 default config files will be automatically generated.
141 """)
139 """)
142
140
143 # The class to use as the crash handler.
141 # The class to use as the crash handler.
144 crash_handler_class = Type(crashhandler.CrashHandler)
142 crash_handler_class = Type(crashhandler.CrashHandler)
145
143
146 def __init__(self, **kwargs):
144 def __init__(self, **kwargs):
147 super(BaseIPythonApplication, self).__init__(**kwargs)
145 super(BaseIPythonApplication, self).__init__(**kwargs)
148 # ensure even default IPYTHON_DIR exists
146 # ensure even default IPYTHON_DIR exists
149 if not os.path.exists(self.ipython_dir):
147 if not os.path.exists(self.ipython_dir):
150 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
148 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
151
149
152 #-------------------------------------------------------------------------
150 #-------------------------------------------------------------------------
153 # Various stages of Application creation
151 # Various stages of Application creation
154 #-------------------------------------------------------------------------
152 #-------------------------------------------------------------------------
155
153
156 def init_crash_handler(self):
154 def init_crash_handler(self):
157 """Create a crash handler, typically setting sys.excepthook to it."""
155 """Create a crash handler, typically setting sys.excepthook to it."""
158 self.crash_handler = self.crash_handler_class(self)
156 self.crash_handler = self.crash_handler_class(self)
159 sys.excepthook = self.crash_handler
157 sys.excepthook = self.crash_handler
160 def unset_crashhandler():
158 def unset_crashhandler():
161 sys.excepthook = sys.__excepthook__
159 sys.excepthook = sys.__excepthook__
162 atexit.register(unset_crashhandler)
160 atexit.register(unset_crashhandler)
163
161
164 def _ipython_dir_changed(self, name, old, new):
162 def _ipython_dir_changed(self, name, old, new):
165 if old in sys.path:
163 if old in sys.path:
166 sys.path.remove(old)
164 sys.path.remove(old)
167 sys.path.append(os.path.abspath(new))
165 sys.path.append(os.path.abspath(new))
168 if not os.path.isdir(new):
166 if not os.path.isdir(new):
169 os.makedirs(new, mode=0777)
167 os.makedirs(new, mode=0777)
170 readme = os.path.join(new, 'README')
168 readme = os.path.join(new, 'README')
171 if not os.path.exists(readme):
169 if not os.path.exists(readme):
172 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
170 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
173 shutil.copy(os.path.join(path, 'README'), readme)
171 shutil.copy(os.path.join(path, 'README'), readme)
174 self.log.debug("IPYTHON_DIR set to: %s" % new)
172 self.log.debug("IPYTHON_DIR set to: %s" % new)
175
173
176 def load_config_file(self, suppress_errors=True):
174 def load_config_file(self, suppress_errors=True):
177 """Load the config file.
175 """Load the config file.
178
176
179 By default, errors in loading config are handled, and a warning
177 By default, errors in loading config are handled, and a warning
180 printed on screen. For testing, the suppress_errors option is set
178 printed on screen. For testing, the suppress_errors option is set
181 to False, so errors will make tests fail.
179 to False, so errors will make tests fail.
182 """
180 """
183 self.log.debug("Searching path %s for config files", self.config_file_paths)
181 self.log.debug("Searching path %s for config files", self.config_file_paths)
184 base_config = 'ipython_config.py'
182 base_config = 'ipython_config.py'
185 self.log.debug("Attempting to load config file: %s" %
183 self.log.debug("Attempting to load config file: %s" %
186 base_config)
184 base_config)
187 try:
185 try:
188 Application.load_config_file(
186 Application.load_config_file(
189 self,
187 self,
190 base_config,
188 base_config,
191 path=self.config_file_paths
189 path=self.config_file_paths
192 )
190 )
193 except ConfigFileNotFound:
191 except ConfigFileNotFound:
194 # ignore errors loading parent
192 # ignore errors loading parent
195 self.log.debug("Config file %s not found", base_config)
193 self.log.debug("Config file %s not found", base_config)
196 pass
194 pass
197 if self.config_file_name == base_config:
195 if self.config_file_name == base_config:
198 # don't load secondary config
196 # don't load secondary config
199 return
197 return
200 self.log.debug("Attempting to load config file: %s" %
198 self.log.debug("Attempting to load config file: %s" %
201 self.config_file_name)
199 self.config_file_name)
202 try:
200 try:
203 Application.load_config_file(
201 Application.load_config_file(
204 self,
202 self,
205 self.config_file_name,
203 self.config_file_name,
206 path=self.config_file_paths
204 path=self.config_file_paths
207 )
205 )
208 except ConfigFileNotFound:
206 except ConfigFileNotFound:
209 # Only warn if the default config file was NOT being used.
207 # Only warn if the default config file was NOT being used.
210 if self.config_file_specified:
208 if self.config_file_specified:
211 msg = self.log.warn
209 msg = self.log.warn
212 else:
210 else:
213 msg = self.log.debug
211 msg = self.log.debug
214 msg("Config file not found, skipping: %s", self.config_file_name)
212 msg("Config file not found, skipping: %s", self.config_file_name)
215 except:
213 except:
216 # For testing purposes.
214 # For testing purposes.
217 if not suppress_errors:
215 if not suppress_errors:
218 raise
216 raise
219 self.log.warn("Error loading config file: %s" %
217 self.log.warn("Error loading config file: %s" %
220 self.config_file_name, exc_info=True)
218 self.config_file_name, exc_info=True)
221
219
222 def init_profile_dir(self):
220 def init_profile_dir(self):
223 """initialize the profile dir"""
221 """initialize the profile dir"""
224 try:
222 try:
225 # location explicitly specified:
223 # location explicitly specified:
226 location = self.config.ProfileDir.location
224 location = self.config.ProfileDir.location
227 except AttributeError:
225 except AttributeError:
228 # location not specified, find by profile name
226 # location not specified, find by profile name
229 try:
227 try:
230 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
228 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
231 except ProfileDirError:
229 except ProfileDirError:
232 # not found, maybe create it (always create default profile)
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 try:
232 try:
235 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
233 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
236 except ProfileDirError:
234 except ProfileDirError:
237 self.log.fatal("Could not create profile: %r"%self.profile)
235 self.log.fatal("Could not create profile: %r"%self.profile)
238 self.exit(1)
236 self.exit(1)
239 else:
237 else:
240 self.log.info("Created profile dir: %r"%p.location)
238 self.log.info("Created profile dir: %r"%p.location)
241 else:
239 else:
242 self.log.fatal("Profile %r not found."%self.profile)
240 self.log.fatal("Profile %r not found."%self.profile)
243 self.exit(1)
241 self.exit(1)
244 else:
242 else:
245 self.log.info("Using existing profile dir: %r"%p.location)
243 self.log.info("Using existing profile dir: %r"%p.location)
246 else:
244 else:
247 # location is fully specified
245 # location is fully specified
248 try:
246 try:
249 p = ProfileDir.find_profile_dir(location, self.config)
247 p = ProfileDir.find_profile_dir(location, self.config)
250 except ProfileDirError:
248 except ProfileDirError:
251 # not found, maybe create it
249 # not found, maybe create it
252 if self.auto_create:
250 if self.auto_create:
253 try:
251 try:
254 p = ProfileDir.create_profile_dir(location, self.config)
252 p = ProfileDir.create_profile_dir(location, self.config)
255 except ProfileDirError:
253 except ProfileDirError:
256 self.log.fatal("Could not create profile directory: %r"%location)
254 self.log.fatal("Could not create profile directory: %r"%location)
257 self.exit(1)
255 self.exit(1)
258 else:
256 else:
259 self.log.info("Creating new profile dir: %r"%location)
257 self.log.info("Creating new profile dir: %r"%location)
260 else:
258 else:
261 self.log.fatal("Profile directory %r not found."%location)
259 self.log.fatal("Profile directory %r not found."%location)
262 self.exit(1)
260 self.exit(1)
263 else:
261 else:
264 self.log.info("Using existing profile dir: %r"%location)
262 self.log.info("Using existing profile dir: %r"%location)
265
263
266 self.profile_dir = p
264 self.profile_dir = p
267 self.config_file_paths.append(p.location)
265 self.config_file_paths.append(p.location)
268
266
269 def init_config_files(self):
267 def init_config_files(self):
270 """[optionally] copy default config files into profile dir."""
268 """[optionally] copy default config files into profile dir."""
271 # copy config files
269 # copy config files
272 path = self.builtin_profile_dir
270 path = self.builtin_profile_dir
273 if self.copy_config_files:
271 if self.copy_config_files:
274 src = self.profile
272 src = self.profile
275
273
276 cfg = self.config_file_name
274 cfg = self.config_file_name
277 if path and os.path.exists(os.path.join(path, cfg)):
275 if path and os.path.exists(os.path.join(path, cfg)):
278 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
276 self.log.warn("Staging %r from %s into %r [overwrite=%s]"%(
279 cfg, src, self.profile_dir.location, self.overwrite)
277 cfg, src, self.profile_dir.location, self.overwrite)
280 )
278 )
281 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
279 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
282 else:
280 else:
283 self.stage_default_config_file()
281 self.stage_default_config_file()
284 else:
282 else:
285 # Still stage *bundled* config files, but not generated ones
283 # Still stage *bundled* config files, but not generated ones
286 # This is necessary for `ipython profile=sympy` to load the profile
284 # This is necessary for `ipython profile=sympy` to load the profile
287 # on the first go
285 # on the first go
288 files = glob.glob(os.path.join(path, '*.py'))
286 files = glob.glob(os.path.join(path, '*.py'))
289 for fullpath in files:
287 for fullpath in files:
290 cfg = os.path.basename(fullpath)
288 cfg = os.path.basename(fullpath)
291 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
289 if self.profile_dir.copy_config_file(cfg, path=path, overwrite=False):
292 # file was copied
290 # file was copied
293 self.log.warn("Staging bundled %s from %s into %r"%(
291 self.log.warn("Staging bundled %s from %s into %r"%(
294 cfg, self.profile, self.profile_dir.location)
292 cfg, self.profile, self.profile_dir.location)
295 )
293 )
296
294
297
295
298 def stage_default_config_file(self):
296 def stage_default_config_file(self):
299 """auto generate default config file, and stage it into the profile."""
297 """auto generate default config file, and stage it into the profile."""
300 s = self.generate_config_file()
298 s = self.generate_config_file()
301 fname = os.path.join(self.profile_dir.location, self.config_file_name)
299 fname = os.path.join(self.profile_dir.location, self.config_file_name)
302 if self.overwrite or not os.path.exists(fname):
300 if self.overwrite or not os.path.exists(fname):
303 self.log.warn("Generating default config file: %r"%(fname))
301 self.log.warn("Generating default config file: %r"%(fname))
304 with open(fname, 'w') as f:
302 with open(fname, 'w') as f:
305 f.write(s)
303 f.write(s)
306
304
307 @catch_config_error
305 @catch_config_error
308 def initialize(self, argv=None):
306 def initialize(self, argv=None):
309 # don't hook up crash handler before parsing command-line
307 # don't hook up crash handler before parsing command-line
310 self.parse_command_line(argv)
308 self.parse_command_line(argv)
311 self.init_crash_handler()
309 self.init_crash_handler()
312 if self.subapp is not None:
310 if self.subapp is not None:
313 # stop here if subapp is taking over
311 # stop here if subapp is taking over
314 return
312 return
315 cl_config = self.config
313 cl_config = self.config
316 self.init_profile_dir()
314 self.init_profile_dir()
317 self.init_config_files()
315 self.init_config_files()
318 self.load_config_file()
316 self.load_config_file()
319 # enforce cl-opts override configfile opts:
317 # enforce cl-opts override configfile opts:
320 self.update_config(cl_config)
318 self.update_config(cl_config)
321
319
General Comments 0
You need to be logged in to leave comments. Login now