##// END OF EJS Templates
rename core.newapplication -> core.application
MinRK -
Show More
This diff has been collapsed as it changes many lines, (719 lines changed) Show them Hide them
@@ -12,6 +12,7 b' Authors:'
12
12
13 * Brian Granger
13 * Brian Granger
14 * Fernando Perez
14 * Fernando Perez
15 * Min RK
15
16
16 Notes
17 Notes
17 -----
18 -----
@@ -30,439 +31,399 b' Notes'
30
31
31 import logging
32 import logging
32 import os
33 import os
34 import shutil
33 import sys
35 import sys
34
36
37 from IPython.config.application import Application
38 from IPython.config.configurable import Configurable
39 from IPython.config.loader import Config
35 from IPython.core import release, crashhandler
40 from IPython.core import release, crashhandler
36 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir
41 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, expand_path
37 from IPython.config.loader import (
42 from IPython.utils.traitlets import List, Unicode, Type, Bool, Dict
38 PyFileConfigLoader,
39 ArgParseConfigLoader,
40 Config,
41 )
42
43
43 #-----------------------------------------------------------------------------
44 #-----------------------------------------------------------------------------
44 # Classes and functions
45 # Classes and functions
45 #-----------------------------------------------------------------------------
46 #-----------------------------------------------------------------------------
46
47
47 class ApplicationError(Exception):
48
49 #-----------------------------------------------------------------------------
50 # Module errors
51 #-----------------------------------------------------------------------------
52
53 class ProfileDirError(Exception):
48 pass
54 pass
49
55
50
56
51 class BaseAppConfigLoader(ArgParseConfigLoader):
57 #-----------------------------------------------------------------------------
52 """Default command line options for IPython based applications."""
58 # Class for managing profile directories
53
59 #-----------------------------------------------------------------------------
54 def _add_ipython_dir(self, parser):
55 """Add the --ipython-dir option to the parser."""
56 paa = parser.add_argument
57 paa('--ipython-dir',
58 dest='Global.ipython_dir',type=unicode,
59 help=
60 """Set to override default location of the IPython directory
61 IPYTHON_DIR, stored as Global.ipython_dir. This can also be
62 specified through the environment variable IPYTHON_DIR.""",
63 metavar='Global.ipython_dir')
64
65 def _add_log_level(self, parser):
66 """Add the --log-level option to the parser."""
67 paa = parser.add_argument
68 paa('--log-level',
69 dest="Global.log_level",type=int,
70 help='Set the log level (0,10,20,30,40,50). Default is 30.',
71 metavar='Global.log_level')
72
73 def _add_version(self, parser):
74 """Add the --version option to the parser."""
75 parser.add_argument('--version', action="version",
76 version=self.version)
77
78 def _add_arguments(self):
79 self._add_ipython_dir(self.parser)
80 self._add_log_level(self.parser)
81 try: # Old versions of argparse don't have a version action
82 self._add_version(self.parser)
83 except Exception:
84 pass
85
86
87 class Application(object):
88 """Load a config, construct configurables and set them running.
89
90 The configuration of an application can be done via three different Config
91 objects, which are loaded and ultimately merged into a single one used
92 from that point on by the app. These are:
93
94 1. default_config: internal defaults, implemented in code.
95 2. file_config: read from the filesystem.
96 3. command_line_config: read from the system's command line flags.
97
98 During initialization, 3 is actually read before 2, since at the
99 command-line one may override the location of the file to be read. But the
100 above is the order in which the merge is made.
101 """
102
60
103 name = u'ipython'
61 class ProfileDir(Configurable):
104 description = 'IPython: an enhanced interactive Python shell.'
62 """An object to manage the profile directory and its resources.
105 #: Usage message printed by argparse. If None, auto-generate
106 usage = None
107 #: The command line config loader. Subclass of ArgParseConfigLoader.
108 command_line_loader = BaseAppConfigLoader
109 #: The name of the config file to load, determined at runtime
110 config_file_name = None
111 #: The name of the default config file. Track separately from the actual
112 #: name because some logic happens only if we aren't using the default.
113 default_config_file_name = u'ipython_config.py'
114 default_log_level = logging.WARN
115 #: Set by --profile option
116 profile_name = None
117 #: User's ipython directory, typically ~/.ipython or ~/.config/ipython/
118 ipython_dir = None
119 #: Internal defaults, implemented in code.
120 default_config = None
121 #: Read from the filesystem.
122 file_config = None
123 #: Read from the system's command line flags.
124 command_line_config = None
125 #: The final config that will be passed to the main object.
126 master_config = None
127 #: A reference to the argv to be used (typically ends up being sys.argv[1:])
128 argv = None
129 #: extra arguments computed by the command-line loader
130 extra_args = None
131 #: The class to use as the crash handler.
132 crash_handler_class = crashhandler.CrashHandler
133
134 # Private attributes
135 _exiting = False
136 _initialized = False
137
138 def __init__(self, argv=None):
139 self.argv = sys.argv[1:] if argv is None else argv
140 self.init_logger()
141
142 def init_logger(self):
143 self.log = logging.getLogger(self.__class__.__name__)
144 # This is used as the default until the command line arguments are read.
145 self.log.setLevel(self.default_log_level)
146 self._log_handler = logging.StreamHandler()
147 self._log_formatter = logging.Formatter("[%(name)s] %(message)s")
148 self._log_handler.setFormatter(self._log_formatter)
149 self.log.addHandler(self._log_handler)
150
151 def _set_log_level(self, level):
152 self.log.setLevel(level)
153
154 def _get_log_level(self):
155 return self.log.level
156
157 log_level = property(_get_log_level, _set_log_level)
158
159 def initialize(self):
160 """Initialize the application.
161
162 Loads all configuration information and sets all application state, but
163 does not start any relevant processing (typically some kind of event
164 loop).
165
166 Once this method has been called, the application is flagged as
167 initialized and the method becomes a no-op."""
168
169 if self._initialized:
170 return
171
63
172 # The first part is protected with an 'attempt' wrapper, that will log
64 The profile directory is used by all IPython applications, to manage
173 # failures with the basic system traceback machinery. Once our crash
65 configuration, logging and security.
174 # handler is in place, we can let any subsequent exception propagate,
175 # as our handler will log it with much better detail than the default.
176 self.attempt(self.create_crash_handler)
177
178 # Configuration phase
179 # Default config (internally hardwired in application code)
180 self.create_default_config()
181 self.log_default_config()
182 self.set_default_config_log_level()
183
184 # Command-line config
185 self.pre_load_command_line_config()
186 self.load_command_line_config()
187 self.set_command_line_config_log_level()
188 self.post_load_command_line_config()
189 self.log_command_line_config()
190
191 # Find resources needed for filesystem access, using information from
192 # the above two
193 self.find_ipython_dir()
194 self.find_resources()
195 self.find_config_file_name()
196 self.find_config_file_paths()
197
198 # File-based config
199 self.pre_load_file_config()
200 self.load_file_config()
201 self.set_file_config_log_level()
202 self.post_load_file_config()
203 self.log_file_config()
204
205 # Merge all config objects into a single one the app can then use
206 self.merge_configs()
207 self.log_master_config()
208
209 # Construction phase
210 self.pre_construct()
211 self.construct()
212 self.post_construct()
213
214 # Done, flag as such and
215 self._initialized = True
216
217 def start(self):
218 """Start the application."""
219 self.initialize()
220 self.start_app()
221
66
222 #-------------------------------------------------------------------------
67 This object knows how to find, create and manage these directories. This
223 # Various stages of Application creation
68 should be used by any code that wants to handle profiles.
224 #-------------------------------------------------------------------------
69 """
225
70
226 def create_crash_handler(self):
71 security_dir_name = Unicode('security')
227 """Create a crash handler, typically setting sys.excepthook to it."""
72 log_dir_name = Unicode('log')
228 self.crash_handler = self.crash_handler_class(self)
73 pid_dir_name = Unicode('pid')
229 sys.excepthook = self.crash_handler
74 security_dir = Unicode(u'')
75 log_dir = Unicode(u'')
76 pid_dir = Unicode(u'')
77
78 location = Unicode(u'', config=True,
79 help="""Set the profile location directly. This overrides the logic used by the
80 `profile` option.""",
81 )
230
82
231 def create_default_config(self):
83 _location_isset = Bool(False) # flag for detecting multiply set location
232 """Create defaults that can't be set elsewhere.
233
84
234 For the most part, we try to set default in the class attributes
85 def _location_changed(self, name, old, new):
235 of Configurables. But, defaults the top-level Application (which is
86 if self._location_isset:
236 not a HasTraits or Configurables) are not set in this way. Instead
87 raise RuntimeError("Cannot set profile location more than once.")
237 we set them here. The Global section is for variables like this that
88 self._location_isset = True
238 don't belong to a particular configurable.
89 if not os.path.isdir(new):
239 """
90 os.makedirs(new)
240 c = Config()
91
241 c.Global.ipython_dir = get_ipython_dir()
92 # ensure config files exist:
242 c.Global.log_level = self.log_level
93 self.security_dir = os.path.join(new, self.security_dir_name)
243 self.default_config = c
94 self.log_dir = os.path.join(new, self.log_dir_name)
95 self.pid_dir = os.path.join(new, self.pid_dir_name)
96 self.check_dirs()
244
97
245 def log_default_config(self):
98 def _log_dir_changed(self, name, old, new):
246 self.log.debug('Default config loaded:')
99 self.check_log_dir()
247 self.log.debug(repr(self.default_config))
248
100
249 def set_default_config_log_level(self):
101 def check_log_dir(self):
250 try:
102 if not os.path.isdir(self.log_dir):
251 self.log_level = self.default_config.Global.log_level
103 os.mkdir(self.log_dir)
252 except AttributeError:
253 # Fallback to the default_log_level class attribute
254 pass
255
256 def create_command_line_config(self):
257 """Create and return a command line config loader."""
258 return self.command_line_loader(
259 self.argv,
260 description=self.description,
261 version=release.version,
262 usage=self.usage
263 )
264
104
265 def pre_load_command_line_config(self):
105 def _security_dir_changed(self, name, old, new):
266 """Do actions just before loading the command line config."""
106 self.check_security_dir()
267 pass
268
107
269 def load_command_line_config(self):
108 def check_security_dir(self):
270 """Load the command line config."""
109 if not os.path.isdir(self.security_dir):
271 loader = self.create_command_line_config()
110 os.mkdir(self.security_dir, 0700)
272 self.command_line_config = loader.load_config()
111 else:
273 self.extra_args = loader.get_extra_args()
112 os.chmod(self.security_dir, 0700)
274
113
275 def set_command_line_config_log_level(self):
114 def _pid_dir_changed(self, name, old, new):
276 try:
115 self.check_pid_dir()
277 self.log_level = self.command_line_config.Global.log_level
278 except AttributeError:
279 pass
280
116
281 def post_load_command_line_config(self):
117 def check_pid_dir(self):
282 """Do actions just after loading the command line config."""
118 if not os.path.isdir(self.pid_dir):
283 pass
119 os.mkdir(self.pid_dir, 0700)
120 else:
121 os.chmod(self.pid_dir, 0700)
284
122
285 def log_command_line_config(self):
123 def check_dirs(self):
286 self.log.debug("Command line config loaded:")
124 self.check_security_dir()
287 self.log.debug(repr(self.command_line_config))
125 self.check_log_dir()
126 self.check_pid_dir()
288
127
289 def find_ipython_dir(self):
128 def copy_config_file(self, config_file, path=None, overwrite=False):
290 """Set the IPython directory.
129 """Copy a default config file into the active profile directory.
291
130
292 This sets ``self.ipython_dir``, but the actual value that is passed to
131 Default configuration files are kept in :mod:`IPython.config.default`.
293 the application is kept in either ``self.default_config`` or
132 This function moves these from that location to the working profile
294 ``self.command_line_config``. This also adds ``self.ipython_dir`` to
133 directory.
295 ``sys.path`` so config files there can be referenced by other config
296 files.
297 """
134 """
298
135 dst = os.path.join(self.location, config_file)
299 try:
136 if os.path.isfile(dst) and not overwrite:
300 self.ipython_dir = self.command_line_config.Global.ipython_dir
137 return
301 except AttributeError:
138 if path is None:
302 self.ipython_dir = self.default_config.Global.ipython_dir
139 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
303 sys.path.append(os.path.abspath(self.ipython_dir))
140 src = os.path.join(path, config_file)
304 if not os.path.isdir(self.ipython_dir):
141 shutil.copy(src, dst)
305 os.makedirs(self.ipython_dir, mode=0777)
142
306 self.log.debug("IPYTHON_DIR set to: %s" % self.ipython_dir)
143 @classmethod
307
144 def create_profile_dir(cls, profile_dir, config=None):
308 def find_resources(self):
145 """Create a new profile directory given a full path.
309 """Find other resources that need to be in place.
146
310
147 Parameters
311 Things like cluster directories need to be in place to find the
148 ----------
312 config file. These happen right after the IPython directory has
149 profile_dir : str
313 been set.
150 The full path to the profile directory. If it does exist, it will
151 be used. If not, it will be created.
152 """
153 return cls(location=profile_dir, config=config)
154
155 @classmethod
156 def create_profile_dir_by_name(cls, path, name=u'default', config=None):
157 """Create a profile dir by profile name and path.
158
159 Parameters
160 ----------
161 path : unicode
162 The path (directory) to put the profile directory in.
163 name : unicode
164 The name of the profile. The name of the profile directory will
165 be "profile_<profile>".
314 """
166 """
315 pass
167 if not os.path.isdir(path):
168 raise ProfileDirError('Directory not found: %s' % path)
169 profile_dir = os.path.join(path, u'profile_' + name)
170 return cls(location=profile_dir, config=config)
171
172 @classmethod
173 def find_profile_dir_by_name(cls, ipython_dir, name=u'default', config=None):
174 """Find an existing profile dir by profile name, return its ProfileDir.
175
176 This searches through a sequence of paths for a profile dir. If it
177 is not found, a :class:`ProfileDirError` exception will be raised.
178
179 The search path algorithm is:
180 1. ``os.getcwd()``
181 2. ``ipython_dir``
182
183 Parameters
184 ----------
185 ipython_dir : unicode or str
186 The IPython directory to use.
187 name : unicode or str
188 The name of the profile. The name of the profile directory
189 will be "profile_<profile>".
190 """
191 dirname = u'profile_' + name
192 paths = [os.getcwdu(), ipython_dir]
193 for p in paths:
194 profile_dir = os.path.join(p, dirname)
195 if os.path.isdir(profile_dir):
196 return cls(location=profile_dir, config=config)
197 else:
198 raise ProfileDirError('Profile directory not found in paths: %s' % dirname)
316
199
317 def find_config_file_name(self):
200 @classmethod
318 """Find the config file name for this application.
201 def find_profile_dir(cls, profile_dir, config=None):
202 """Find/create a profile dir and return its ProfileDir.
319
203
320 This must set ``self.config_file_name`` to the filename of the
204 This will create the profile directory if it doesn't exist.
321 config file to use (just the filename). The search paths for the
322 config file are set in :meth:`find_config_file_paths` and then passed
323 to the config file loader where they are resolved to an absolute path.
324
205
325 If a profile has been set at the command line, this will resolve it.
206 Parameters
207 ----------
208 profile_dir : unicode or str
209 The path of the profile directory. This is expanded using
210 :func:`IPython.utils.genutils.expand_path`.
326 """
211 """
327 try:
212 profile_dir = expand_path(profile_dir)
328 self.config_file_name = self.command_line_config.Global.config_file
213 if not os.path.isdir(profile_dir):
329 except AttributeError:
214 raise ProfileDirError('Profile directory not found: %s' % profile_dir)
330 pass
215 return cls(location=profile_dir, config=config)
331 else:
332 return
333
216
334 try:
335 self.profile_name = self.command_line_config.Global.profile
336 except AttributeError:
337 # Just use the default as there is no profile
338 self.config_file_name = self.default_config_file_name
339 else:
340 # Use the default config file name and profile name if set
341 # to determine the used config file name.
342 name_parts = self.default_config_file_name.split('.')
343 name_parts.insert(1, u'_' + self.profile_name + u'.')
344 self.config_file_name = ''.join(name_parts)
345
217
346 def find_config_file_paths(self):
218 #-----------------------------------------------------------------------------
347 """Set the search paths for resolving the config file.
219 # Base Application Class
220 #-----------------------------------------------------------------------------
221
222 # aliases and flags
223
224 base_aliases = dict(
225 profile='BaseIPythonApplication.profile',
226 ipython_dir='BaseIPythonApplication.ipython_dir',
227 )
348
228
349 This must set ``self.config_file_paths`` to a sequence of search
229 base_flags = dict(
350 paths to pass to the config file loader.
230 debug = ({'Application' : {'log_level' : logging.DEBUG}},
231 "set log level to logging.DEBUG (maximize logging output)"),
232 quiet = ({'Application' : {'log_level' : logging.CRITICAL}},
233 "set log level to logging.CRITICAL (minimize logging output)"),
234 init = ({'BaseIPythonApplication' : {
235 'copy_config_files' : True,
236 'auto_create' : True}
237 }, "Initialize profile with default config files")
238 )
239
240
241 class BaseIPythonApplication(Application):
242
243 name = Unicode(u'ipython')
244 description = Unicode(u'IPython: an enhanced interactive Python shell.')
245 version = Unicode(release.version)
246
247 aliases = Dict(base_aliases)
248 flags = Dict(base_flags)
249
250 # Track whether the config_file has changed,
251 # because some logic happens only if we aren't using the default.
252 config_file_specified = Bool(False)
253
254 config_file_name = Unicode(u'ipython_config.py')
255 def _config_file_name_changed(self, name, old, new):
256 if new != old:
257 self.config_file_specified = True
258
259 # The directory that contains IPython's builtin profiles.
260 builtin_profile_dir = Unicode(
261 os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
262 )
263
264 config_file_paths = List(Unicode)
265 def _config_file_paths_default(self):
266 return [os.getcwdu()]
267
268 profile = Unicode(u'default', config=True,
269 help="""The IPython profile to use."""
270 )
271 def _profile_changed(self, name, old, new):
272 self.builtin_profile_dir = os.path.join(
273 get_ipython_package_dir(), u'config', u'profile', new
274 )
275
276
277 ipython_dir = Unicode(get_ipython_dir(), config=True,
278 help="""
279 The name of the IPython directory. This directory is used for logging
280 configuration (through profiles), history storage, etc. The default
281 is usually $HOME/.ipython. This options can also be specified through
282 the environment variable IPYTHON_DIR.
351 """
283 """
352 # Include our own profiles directory last, so that users can still find
284 )
353 # our shipped copies of builtin profiles even if they don't have them
285
354 # in their local ipython directory.
286 overwrite = Bool(False, config=True,
355 prof_dir = os.path.join(get_ipython_package_dir(), 'config', 'profile')
287 help="""Whether to overwrite existing config files when copying""")
356 self.config_file_paths = (os.getcwdu(), self.ipython_dir, prof_dir)
288 auto_create = Bool(False, config=True,
289 help="""Whether to create profile dir if it doesn't exist""")
290
291 config_files = List(Unicode)
292 def _config_files_default(self):
293 return [u'ipython_config.py']
294
295 copy_config_files = Bool(False, config=True,
296 help="""Whether to copy the default config files into the profile dir.""")
297
298 # The class to use as the crash handler.
299 crash_handler_class = Type(crashhandler.CrashHandler)
300
301 def __init__(self, **kwargs):
302 super(BaseIPythonApplication, self).__init__(**kwargs)
303 # ensure even default IPYTHON_DIR exists
304 if not os.path.exists(self.ipython_dir):
305 self._ipython_dir_changed('ipython_dir', self.ipython_dir, self.ipython_dir)
306
307 #-------------------------------------------------------------------------
308 # Various stages of Application creation
309 #-------------------------------------------------------------------------
357
310
358 def pre_load_file_config(self):
311 def init_crash_handler(self):
359 """Do actions before the config file is loaded."""
312 """Create a crash handler, typically setting sys.excepthook to it."""
360 pass
313 self.crash_handler = self.crash_handler_class(self)
314 sys.excepthook = self.crash_handler
361
315
362 def load_file_config(self, suppress_errors=True):
316 def _ipython_dir_changed(self, name, old, new):
317 if old in sys.path:
318 sys.path.remove(old)
319 sys.path.append(os.path.abspath(new))
320 if not os.path.isdir(new):
321 os.makedirs(new, mode=0777)
322 readme = os.path.join(new, 'README')
323 if not os.path.exists(readme):
324 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
325 shutil.copy(os.path.join(path, 'README'), readme)
326 self.log.debug("IPYTHON_DIR set to: %s" % new)
327
328 def load_config_file(self, suppress_errors=True):
363 """Load the config file.
329 """Load the config file.
364
330
365 This tries to load the config file from disk. If successful, the
366 ``CONFIG_FILE`` config variable is set to the resolved config file
367 location. If not successful, an empty config is used.
368
369 By default, errors in loading config are handled, and a warning
331 By default, errors in loading config are handled, and a warning
370 printed on screen. For testing, the suppress_errors option is set
332 printed on screen. For testing, the suppress_errors option is set
371 to False, so errors will make tests fail.
333 to False, so errors will make tests fail.
372 """
334 """
373 self.log.debug("Attempting to load config file: %s" %
335 self.log.debug("Attempting to load config file: %s" %
374 self.config_file_name)
336 self.config_file_name)
375 loader = PyFileConfigLoader(self.config_file_name,
376 path=self.config_file_paths)
377 try:
337 try:
378 self.file_config = loader.load_config()
338 Application.load_config_file(
379 self.file_config.Global.config_file = loader.full_filename
339 self,
340 self.config_file_name,
341 path=self.config_file_paths
342 )
380 except IOError:
343 except IOError:
381 # Only warn if the default config file was NOT being used.
344 # Only warn if the default config file was NOT being used.
382 if not self.config_file_name==self.default_config_file_name:
345 if self.config_file_specified:
383 self.log.warn("Config file not found, skipping: %s" %
346 self.log.warn("Config file not found, skipping: %s" %
384 self.config_file_name, exc_info=True)
347 self.config_file_name)
385 self.file_config = Config()
386 except:
348 except:
387 if not suppress_errors: # For testing purposes
349 # For testing purposes.
350 if not suppress_errors:
388 raise
351 raise
389 self.log.warn("Error loading config file: %s" %
352 self.log.warn("Error loading config file: %s" %
390 self.config_file_name, exc_info=True)
353 self.config_file_name, exc_info=True)
391 self.file_config = Config()
392
354
393 def set_file_config_log_level(self):
355 def init_profile_dir(self):
394 # We need to keeep self.log_level updated. But we only use the value
356 """initialize the profile dir"""
395 # of the file_config if a value was not specified at the command
357 try:
396 # line, because the command line overrides everything.
358 # location explicitly specified:
397 if not hasattr(self.command_line_config.Global, 'log_level'):
359 location = self.config.ProfileDir.location
360 except AttributeError:
361 # location not specified, find by profile name
398 try:
362 try:
399 self.log_level = self.file_config.Global.log_level
363 p = ProfileDir.find_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
400 except AttributeError:
364 except ProfileDirError:
401 pass # Use existing value
365 # not found, maybe create it (always create default profile)
402
366 if self.auto_create or self.profile=='default':
403 def post_load_file_config(self):
367 try:
404 """Do actions after the config file is loaded."""
368 p = ProfileDir.create_profile_dir_by_name(self.ipython_dir, self.profile, self.config)
405 pass
369 except ProfileDirError:
406
370 self.log.fatal("Could not create profile: %r"%self.profile)
407 def log_file_config(self):
371 self.exit(1)
408 if hasattr(self.file_config.Global, 'config_file'):
372 else:
409 self.log.debug("Config file loaded: %s" %
373 self.log.info("Created profile dir: %r"%p.location)
410 self.file_config.Global.config_file)
374 else:
411 self.log.debug(repr(self.file_config))
375 self.log.fatal("Profile %r not found."%self.profile)
412
376 self.exit(1)
413 def merge_configs(self):
377 else:
414 """Merge the default, command line and file config objects."""
378 self.log.info("Using existing profile dir: %r"%p.location)
415 config = Config()
416 config._merge(self.default_config)
417 config._merge(self.file_config)
418 config._merge(self.command_line_config)
419
420 # XXX fperez - propose to Brian we rename master_config to simply
421 # config, I think this is going to be heavily used in examples and
422 # application code and the name is shorter/easier to find/remember.
423 # For now, just alias it...
424 self.master_config = config
425 self.config = config
426
427 def log_master_config(self):
428 self.log.debug("Master config created:")
429 self.log.debug(repr(self.master_config))
430
431 def pre_construct(self):
432 """Do actions after the config has been built, but before construct."""
433 pass
434
435 def construct(self):
436 """Construct the main objects that make up this app."""
437 self.log.debug("Constructing main objects for application")
438
439 def post_construct(self):
440 """Do actions after construct, but before starting the app."""
441 pass
442
443 def start_app(self):
444 """Actually start the app."""
445 self.log.debug("Starting application")
446
447 #-------------------------------------------------------------------------
448 # Utility methods
449 #-------------------------------------------------------------------------
450
451 def exit(self, exit_status=0):
452 if self._exiting:
453 pass
454 else:
379 else:
455 self.log.debug("Exiting application: %s" % self.name)
380 # location is fully specified
456 self._exiting = True
381 try:
457 sys.exit(exit_status)
382 p = ProfileDir.find_profile_dir(location, self.config)
458
383 except ProfileDirError:
459 def attempt(self, func):
384 # not found, maybe create it
460 try:
385 if self.auto_create:
461 func()
386 try:
462 except SystemExit:
387 p = ProfileDir.create_profile_dir(location, self.config)
463 raise
388 except ProfileDirError:
464 except:
389 self.log.fatal("Could not create profile directory: %r"%location)
465 self.log.critical("Aborting application: %s" % self.name,
390 self.exit(1)
466 exc_info=True)
391 else:
467 self.exit(0)
392 self.log.info("Creating new profile dir: %r"%location)
393 else:
394 self.log.fatal("Profile directory %r not found."%location)
395 self.exit(1)
396 else:
397 self.log.info("Using existing profile dir: %r"%location)
398
399 self.profile_dir = p
400 self.config_file_paths.append(p.location)
401
402 def init_config_files(self):
403 """[optionally] copy default config files into profile dir."""
404 # copy config files
405 if self.copy_config_files:
406 path = self.builtin_profile_dir
407 src = self.profile
408 if not os.path.exists(path):
409 # use default if new profile doesn't have a preset
410 path = None
411 src = 'default'
412
413 self.log.debug("Staging %s config files into %r [overwrite=%s]"%(
414 src, self.profile_dir.location, self.overwrite)
415 )
416
417 for cfg in self.config_files:
418 self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite)
419
420 def initialize(self, argv=None):
421 self.init_crash_handler()
422 self.parse_command_line(argv)
423 cl_config = self.config
424 self.init_profile_dir()
425 self.init_config_files()
426 self.load_config_file()
427 # enforce cl-opts override configfile opts:
428 self.update_config(cl_config)
468
429
@@ -54,7 +54,7 b' from IPython.core.inputsplitter import IPythonInputSplitter'
54 from IPython.core.logger import Logger
54 from IPython.core.logger import Logger
55 from IPython.core.macro import Macro
55 from IPython.core.macro import Macro
56 from IPython.core.magic import Magic
56 from IPython.core.magic import Magic
57 from IPython.core.newapplication import ProfileDir
57 from IPython.core.application import ProfileDir
58 from IPython.core.payload import PayloadManager
58 from IPython.core.payload import PayloadManager
59 from IPython.core.plugin import PluginManager
59 from IPython.core.plugin import PluginManager
60 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
60 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
@@ -344,7 +344,7 b' class InteractiveShell(SingletonConfigurable, Magic):'
344 payload_manager = Instance('IPython.core.payload.PayloadManager')
344 payload_manager = Instance('IPython.core.payload.PayloadManager')
345 history_manager = Instance('IPython.core.history.HistoryManager')
345 history_manager = Instance('IPython.core.history.HistoryManager')
346
346
347 profile_dir = Instance('IPython.core.newapplication.ProfileDir')
347 profile_dir = Instance('IPython.core.application.ProfileDir')
348 @property
348 @property
349 def profile(self):
349 def profile(self):
350 if self.profile_dir is not None:
350 if self.profile_dir is not None:
@@ -46,7 +46,7 b' from IPython.core import debugger, oinspect'
46 from IPython.core.error import TryNext
46 from IPython.core.error import TryNext
47 from IPython.core.error import UsageError
47 from IPython.core.error import UsageError
48 from IPython.core.fakemodule import FakeModule
48 from IPython.core.fakemodule import FakeModule
49 from IPython.core.newapplication import ProfileDir
49 from IPython.core.application import ProfileDir
50 from IPython.core.macro import Macro
50 from IPython.core.macro import Macro
51 from IPython.core import page
51 from IPython.core import page
52 from IPython.core.prefilter import ESC_MAGIC
52 from IPython.core.prefilter import ESC_MAGIC
@@ -1,7 +1,7 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 A mixin for :class:`~IPython.core.newapplication.Application` classes that
4 A mixin for :class:`~IPython.core.application.Application` classes that
5 launch InteractiveShell instances, load extensions, etc.
5 launch InteractiveShell instances, load extensions, etc.
6
6
7 Authors
7 Authors
@@ -4,7 +4,7 b''
4 import os
4 import os
5 import tempfile
5 import tempfile
6
6
7 from IPython.core.application import Application
7 from IPython.core.application import BaseIPythonApplication
8 from IPython.testing import decorators as testdec
8 from IPython.testing import decorators as testdec
9
9
10 @testdec.onlyif_unicode_paths
10 @testdec.onlyif_unicode_paths
@@ -16,22 +16,11 b' def test_unicode_cwd():'
16 os.chdir(wd)
16 os.chdir(wd)
17 #raise Exception(repr(os.getcwd()))
17 #raise Exception(repr(os.getcwd()))
18 try:
18 try:
19 app = Application()
19 app = BaseIPythonApplication()
20 # The lines below are copied from Application.initialize()
20 # The lines below are copied from Application.initialize()
21 app.create_default_config()
21 app.init_profile_dir()
22 app.log_default_config()
22 app.init_config_files()
23 app.set_default_config_log_level()
23 app.load_config_file(suppress_errors=False)
24
25 # Find resources needed for filesystem access, using information from
26 # the above two
27 app.find_ipython_dir()
28 app.find_resources()
29 app.find_config_file_name()
30 app.find_config_file_paths()
31
32 # File-based config
33 app.pre_load_file_config()
34 app.load_file_config(suppress_errors=False)
35 finally:
24 finally:
36 os.chdir(old_wd)
25 os.chdir(old_wd)
37
26
@@ -48,22 +37,11 b' def test_unicode_ipdir():'
48 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
37 old_ipdir2 = os.environ.pop("IPYTHON_DIR", None)
49 os.environ["IPYTHONDIR"] = ipdir.encode("utf-8")
38 os.environ["IPYTHONDIR"] = ipdir.encode("utf-8")
50 try:
39 try:
51 app = Application()
40 app = BaseIPythonApplication()
52 # The lines below are copied from Application.initialize()
41 # The lines below are copied from Application.initialize()
53 app.create_default_config()
42 app.init_profile_dir()
54 app.log_default_config()
43 app.init_config_files()
55 app.set_default_config_log_level()
44 app.load_config_file(suppress_errors=False)
56
57 # Find resources needed for filesystem access, using information from
58 # the above two
59 app.find_ipython_dir()
60 app.find_resources()
61 app.find_config_file_name()
62 app.find_config_file_paths()
63
64 # File-based config
65 app.pre_load_file_config()
66 app.load_file_config(suppress_errors=False)
67 finally:
45 finally:
68 if old_ipdir1:
46 if old_ipdir1:
69 os.environ["IPYTHONDIR"] = old_ipdir1
47 os.environ["IPYTHONDIR"] = old_ipdir1
@@ -27,7 +27,7 b' from pygments.styles import get_all_styles'
27
27
28 # Local imports
28 # Local imports
29 from IPython.config.application import boolean_flag
29 from IPython.config.application import boolean_flag
30 from IPython.core.newapplication import ProfileDir, BaseIPythonApplication
30 from IPython.core.application import ProfileDir, BaseIPythonApplication
31 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
31 from IPython.frontend.qt.console.frontend_widget import FrontendWidget
32 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
32 from IPython.frontend.qt.console.ipython_widget import IPythonWidget
33 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
33 from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
@@ -1,7 +1,7 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.newapplication.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 Authors
7 Authors
@@ -37,7 +37,7 b' from IPython.core import release'
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.crashhandler import CrashHandler
38 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.formatters import PlainTextFormatter
39 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.newapplication import (
40 from IPython.core.application import (
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
42 )
42 )
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
@@ -32,7 +32,7 b' from subprocess import Popen, PIPE'
32
32
33 from IPython.core import release
33 from IPython.core import release
34 from IPython.core.crashhandler import CrashHandler
34 from IPython.core.crashhandler import CrashHandler
35 from IPython.core.newapplication import (
35 from IPython.core.application import (
36 BaseIPythonApplication,
36 BaseIPythonApplication,
37 base_aliases as base_ip_aliases,
37 base_aliases as base_ip_aliases,
38 base_flags as base_ip_flags
38 base_flags as base_ip_flags
@@ -33,7 +33,7 b' from zmq.eventloop import ioloop'
33
33
34 from IPython.config.application import Application, boolean_flag
34 from IPython.config.application import Application, boolean_flag
35 from IPython.config.loader import Config
35 from IPython.config.loader import Config
36 from IPython.core.newapplication import BaseIPythonApplication, ProfileDir
36 from IPython.core.application import BaseIPythonApplication, ProfileDir
37 from IPython.utils.daemonize import daemonize
37 from IPython.utils.daemonize import daemonize
38 from IPython.utils.importstring import import_item
38 from IPython.utils.importstring import import_item
39 from IPython.utils.traitlets import Int, Unicode, Bool, CFloat, Dict, List
39 from IPython.utils.traitlets import Int, Unicode, Bool, CFloat, Dict, List
@@ -37,7 +37,7 b' from zmq.log.handlers import PUBHandler'
37 from zmq.utils import jsonapi as json
37 from zmq.utils import jsonapi as json
38
38
39 from IPython.config.application import boolean_flag
39 from IPython.config.application import boolean_flag
40 from IPython.core.newapplication import ProfileDir
40 from IPython.core.application import ProfileDir
41
41
42 from IPython.parallel.apps.baseapp import (
42 from IPython.parallel.apps.baseapp import (
43 BaseParallelApplication,
43 BaseParallelApplication,
@@ -28,7 +28,7 b' import sys'
28 import zmq
28 import zmq
29 from zmq.eventloop import ioloop
29 from zmq.eventloop import ioloop
30
30
31 from IPython.core.newapplication import ProfileDir
31 from IPython.core.application import ProfileDir
32 from IPython.parallel.apps.baseapp import BaseParallelApplication
32 from IPython.parallel.apps.baseapp import BaseParallelApplication
33 from IPython.zmq.log import EnginePUBHandler
33 from IPython.zmq.log import EnginePUBHandler
34
34
@@ -25,7 +25,7 b' import sys'
25
25
26 import zmq
26 import zmq
27
27
28 from IPython.core.newapplication import ProfileDir
28 from IPython.core.application import ProfileDir
29 from IPython.utils.traitlets import Bool, Dict, Unicode
29 from IPython.utils.traitlets import Bool, Dict, Unicode
30
30
31 from IPython.parallel.apps.baseapp import (
31 from IPython.parallel.apps.baseapp import (
@@ -40,7 +40,7 b' from IPython.parallel import util'
40 from IPython.zmq.session import Session, Message
40 from IPython.zmq.session import Session, Message
41
41
42 from .asyncresult import AsyncResult, AsyncHubResult
42 from .asyncresult import AsyncResult, AsyncHubResult
43 from IPython.core.newapplication import ProfileDir, ProfileDirError
43 from IPython.core.application import ProfileDir, ProfileDirError
44 from .view import DirectView, LoadBalancedView
44 from .view import DirectView, LoadBalancedView
45
45
46 #--------------------------------------------------------------------------
46 #--------------------------------------------------------------------------
@@ -141,7 +141,7 b' class SQLiteDB(BaseDB):'
141 self.table = '_'+self.session.replace('-','_')
141 self.table = '_'+self.session.replace('-','_')
142 if not self.location:
142 if not self.location:
143 # get current profile
143 # get current profile
144 from IPython.core.newapplication import BaseIPythonApplication
144 from IPython.core.application import BaseIPythonApplication
145 if BaseIPythonApplication.initialized():
145 if BaseIPythonApplication.initialized():
146 app = BaseIPythonApplication.instance()
146 app = BaseIPythonApplication.instance()
147 if app.profile_dir is not None:
147 if app.profile_dir is not None:
@@ -28,7 +28,7 b' import zmq'
28 # Local imports.
28 # Local imports.
29 from IPython.config.configurable import Configurable
29 from IPython.config.configurable import Configurable
30 from IPython.config.application import boolean_flag
30 from IPython.config.application import boolean_flag
31 from IPython.core.newapplication import ProfileDir
31 from IPython.core.application import ProfileDir
32 from IPython.core.shellapp import (
32 from IPython.core.shellapp import (
33 InteractiveShellApp, shell_flags, shell_aliases
33 InteractiveShellApp, shell_flags, shell_aliases
34 )
34 )
@@ -25,7 +25,7 b' import zmq'
25
25
26 # IPython imports.
26 # IPython imports.
27 from IPython.core.ultratb import FormattedTB
27 from IPython.core.ultratb import FormattedTB
28 from IPython.core.newapplication import (
28 from IPython.core.application import (
29 BaseIPythonApplication, base_flags, base_aliases
29 BaseIPythonApplication, base_flags, base_aliases
30 )
30 )
31 from IPython.utils import io
31 from IPython.utils import io
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now