Show More
@@ -19,10 +19,11 b' Authors:' | |||||
19 | # Imports |
|
19 | # Imports | |
20 | #----------------------------------------------------------------------------- |
|
20 | #----------------------------------------------------------------------------- | |
21 |
|
21 | |||
22 | from copy import deepcopy |
|
|||
23 | import logging |
|
22 | import logging | |
|
23 | import os | |||
24 | import re |
|
24 | import re | |
25 | import sys |
|
25 | import sys | |
|
26 | from copy import deepcopy | |||
26 |
|
27 | |||
27 | from IPython.config.configurable import SingletonConfigurable |
|
28 | from IPython.config.configurable import SingletonConfigurable | |
28 | from IPython.config.loader import ( |
|
29 | from IPython.config.loader import ( | |
@@ -98,9 +99,13 b' class Application(SingletonConfigurable):' | |||||
98 | version = Unicode(u'0.0') |
|
99 | version = Unicode(u'0.0') | |
99 |
|
100 | |||
100 | # The log level for the application |
|
101 | # The log level for the application | |
101 | log_level = Enum((0,10,20,30,40,50), default_value=logging.WARN, |
|
102 | log_level = Enum((0,10,20,30,40,50,'DEBUG','INFO','WARN','ERROR','CRITICAL'), | |
|
103 | default_value=logging.WARN, | |||
102 |
|
|
104 | config=True, | |
103 |
|
|
105 | help="Set the log level by value or name.") | |
|
106 | def _log_level_changed(self, name, old, new): | |||
|
107 | if isinstance(new, basestring): | |||
|
108 | self.log_level = getattr(logging, new) | |||
104 |
|
109 | |||
105 | # the alias map for configurables |
|
110 | # the alias map for configurables | |
106 | aliases = Dict(dict(log_level='Application.log_level')) |
|
111 | aliases = Dict(dict(log_level='Application.log_level')) | |
@@ -337,6 +342,16 b' class Application(SingletonConfigurable):' | |||||
337 | config = loader.load_config() |
|
342 | config = loader.load_config() | |
338 | self.update_config(config) |
|
343 | self.update_config(config) | |
339 |
|
344 | |||
|
345 | def generate_config_file(self): | |||
|
346 | """generate default config file from Configurables""" | |||
|
347 | lines = ["# Configuration file for %s."%self.name] | |||
|
348 | lines.append('') | |||
|
349 | lines.append('c = get_config()') | |||
|
350 | lines.append('') | |||
|
351 | for cls in self.classes: | |||
|
352 | lines.append(cls.class_config_section()) | |||
|
353 | return '\n'.join(lines) | |||
|
354 | ||||
340 | def exit(self, exit_status=0): |
|
355 | def exit(self, exit_status=0): | |
341 | self.log.debug("Exiting application: %s" % self.name) |
|
356 | self.log.debug("Exiting application: %s" % self.name) | |
342 | sys.exit(exit_status) |
|
357 | sys.exit(exit_status) |
@@ -180,6 +180,38 b' class Configurable(HasTraits):' | |||||
180 | """Get the help string for a single trait and print it.""" |
|
180 | """Get the help string for a single trait and print it.""" | |
181 | print cls.class_get_help() |
|
181 | print cls.class_get_help() | |
182 |
|
182 | |||
|
183 | @classmethod | |||
|
184 | def class_config_section(cls): | |||
|
185 | """Get the config class config section""" | |||
|
186 | def c(s): | |||
|
187 | """return a commented, wrapped block.""" | |||
|
188 | s = '\n\n'.join(wrap_paragraphs(s, 78)) | |||
|
189 | ||||
|
190 | return '# ' + s.replace('\n', '\n# ') | |||
|
191 | ||||
|
192 | # section header | |||
|
193 | breaker = '#' + '-'*78 | |||
|
194 | s = "# %s configuration"%cls.__name__ | |||
|
195 | lines = [breaker, s, breaker, ''] | |||
|
196 | # get the description trait | |||
|
197 | desc = cls.class_traits().get('description') | |||
|
198 | if desc: | |||
|
199 | desc = desc.default_value | |||
|
200 | else: | |||
|
201 | # no description trait, use __doc__ | |||
|
202 | desc = getattr(cls, '__doc__', '') | |||
|
203 | if desc: | |||
|
204 | lines.append(c(desc)) | |||
|
205 | lines.append('') | |||
|
206 | ||||
|
207 | for name,trait in cls.class_traits(config=True).iteritems(): | |||
|
208 | help = trait.get_metadata('help') or '' | |||
|
209 | lines.append(c(help)) | |||
|
210 | lines.append('# c.%s.%s = %r'%(cls.__name__, name, trait.get_default_value())) | |||
|
211 | lines.append('') | |||
|
212 | return '\n'.join(lines) | |||
|
213 | ||||
|
214 | ||||
183 |
|
215 | |||
184 | class SingletonConfigurable(Configurable): |
|
216 | class SingletonConfigurable(Configurable): | |
185 | """A configurable that only allows one instance. |
|
217 | """A configurable that only allows one instance. |
@@ -82,6 +82,8 b' class BaseIPythonApplication(Application):' | |||||
82 | config_file_specified = Bool(False) |
|
82 | config_file_specified = Bool(False) | |
83 |
|
83 | |||
84 | config_file_name = Unicode(u'ipython_config.py') |
|
84 | config_file_name = Unicode(u'ipython_config.py') | |
|
85 | def _config_file_name_default(self): | |||
|
86 | return self.name.replace('-','_') + u'_config.py' | |||
85 | def _config_file_name_changed(self, name, old, new): |
|
87 | def _config_file_name_changed(self, name, old, new): | |
86 | if new != old: |
|
88 | if new != old: | |
87 | self.config_file_specified = True |
|
89 | self.config_file_specified = True | |
@@ -103,7 +105,6 b' class BaseIPythonApplication(Application):' | |||||
103 | get_ipython_package_dir(), u'config', u'profile', new |
|
105 | get_ipython_package_dir(), u'config', u'profile', new | |
104 | ) |
|
106 | ) | |
105 |
|
|
107 | ||
106 |
|
||||
107 | ipython_dir = Unicode(get_ipython_dir(), config=True, |
|
108 | ipython_dir = Unicode(get_ipython_dir(), config=True, | |
108 | help=""" |
|
109 | help=""" | |
109 | The name of the IPython directory. This directory is used for logging |
|
110 | The name of the IPython directory. This directory is used for logging | |
@@ -123,7 +124,11 b' class BaseIPythonApplication(Application):' | |||||
123 | return [u'ipython_config.py'] |
|
124 | return [u'ipython_config.py'] | |
124 |
|
125 | |||
125 | copy_config_files = Bool(False, config=True, |
|
126 | copy_config_files = Bool(False, config=True, | |
126 |
help="""Whether to |
|
127 | help="""Whether to install the default config files into the profile dir. | |
|
128 | If a new profile is being created, and IPython contains config files for that | |||
|
129 | profile, then they will be staged into the new directory. Otherwise, | |||
|
130 | default config files will be automatically generated. | |||
|
131 | """) | |||
127 |
|
132 | |||
128 | # The class to use as the crash handler. |
|
133 | # The class to use as the crash handler. | |
129 | crash_handler_class = Type(crashhandler.CrashHandler) |
|
134 | crash_handler_class = Type(crashhandler.CrashHandler) | |
@@ -162,6 +167,21 b' class BaseIPythonApplication(Application):' | |||||
162 | printed on screen. For testing, the suppress_errors option is set |
|
167 | printed on screen. For testing, the suppress_errors option is set | |
163 | to False, so errors will make tests fail. |
|
168 | to False, so errors will make tests fail. | |
164 | """ |
|
169 | """ | |
|
170 | base_config = 'ipython_config.py' | |||
|
171 | self.log.debug("Attempting to load config file: %s" % | |||
|
172 | base_config) | |||
|
173 | try: | |||
|
174 | Application.load_config_file( | |||
|
175 | self, | |||
|
176 | base_config, | |||
|
177 | path=self.config_file_paths | |||
|
178 | ) | |||
|
179 | except IOError: | |||
|
180 | # ignore errors loading parent | |||
|
181 | pass | |||
|
182 | if self.config_file_name == base_config: | |||
|
183 | # don't load secondary config | |||
|
184 | return | |||
165 | self.log.debug("Attempting to load config file: %s" % |
|
185 | self.log.debug("Attempting to load config file: %s" % | |
166 | self.config_file_name) |
|
186 | self.config_file_name) | |
167 | try: |
|
187 | try: | |
@@ -235,21 +255,32 b' class BaseIPythonApplication(Application):' | |||||
235 | if self.copy_config_files: |
|
255 | if self.copy_config_files: | |
236 | path = self.builtin_profile_dir |
|
256 | path = self.builtin_profile_dir | |
237 | src = self.profile |
|
257 | src = self.profile | |
238 | if not os.path.exists(path): |
|
|||
239 | # use default if new profile doesn't have a preset |
|
|||
240 | path = None |
|
|||
241 | src = 'default' |
|
|||
242 |
|
258 | |||
243 | self.log.debug("Staging %s config files into %r [overwrite=%s]"%( |
|
259 | cfg = self.config_file_name | |
244 | src, self.profile_dir.location, self.overwrite) |
|
260 | if path and os.path.exists(os.path.join(path, cfg)): | |
|
261 | self.log.warn("Staging %r from %s into %r [overwrite=%s]"%( | |||
|
262 | cfg, src, self.profile_dir.location, self.overwrite) | |||
245 | ) |
|
263 | ) | |
246 |
|
||||
247 | for cfg in self.config_files: |
|
|||
248 | self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite) |
|
264 | self.profile_dir.copy_config_file(cfg, path=path, overwrite=self.overwrite) | |
|
265 | else: | |||
|
266 | self.stage_default_config_file() | |||
|
267 | ||||
|
268 | def stage_default_config_file(self): | |||
|
269 | """auto generate default config file, and stage it into the profile.""" | |||
|
270 | s = self.generate_config_file() | |||
|
271 | fname = os.path.join(self.profile_dir.location, self.config_file_name) | |||
|
272 | if self.overwrite or not os.path.exists(fname): | |||
|
273 | self.log.warn("Generating default config file: %r"%(fname)) | |||
|
274 | with open(fname, 'w') as f: | |||
|
275 | f.write(s) | |||
|
276 | ||||
249 |
|
277 | |||
250 | def initialize(self, argv=None): |
|
278 | def initialize(self, argv=None): | |
251 | self.init_crash_handler() |
|
279 | self.init_crash_handler() | |
252 | self.parse_command_line(argv) |
|
280 | self.parse_command_line(argv) | |
|
281 | if self.subapp is not None: | |||
|
282 | # stop here if subapp is taking over | |||
|
283 | return | |||
253 | cl_config = self.config |
|
284 | cl_config = self.config | |
254 | self.init_profile_dir() |
|
285 | self.init_profile_dir() | |
255 | self.init_config_files() |
|
286 | self.init_config_files() |
@@ -163,6 +163,42 b' class ProfileCreate(BaseIPythonApplication):' | |||||
163 |
|
163 | |||
164 | classes = [ProfileDir] |
|
164 | classes = [ProfileDir] | |
165 |
|
165 | |||
|
166 | def init_config_files(self): | |||
|
167 | super(ProfileCreate, self).init_config_files() | |||
|
168 | # use local imports, since these classes may import from here | |||
|
169 | from IPython.frontend.terminal.ipapp import TerminalIPythonApp | |||
|
170 | apps = [TerminalIPythonApp] | |||
|
171 | try: | |||
|
172 | from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp | |||
|
173 | except ImportError: | |||
|
174 | pass | |||
|
175 | else: | |||
|
176 | apps.append(IPythonQtConsoleApp) | |||
|
177 | if self.cluster: | |||
|
178 | from IPython.parallel.apps.ipcontrollerapp import IPControllerApp | |||
|
179 | from IPython.parallel.apps.ipengineapp import IPEngineApp | |||
|
180 | from IPython.parallel.apps.ipclusterapp import IPClusterStart | |||
|
181 | from IPython.parallel.apps.iploggerapp import IPLoggerApp | |||
|
182 | apps.extend([ | |||
|
183 | IPControllerApp, | |||
|
184 | IPEngineApp, | |||
|
185 | IPClusterStart, | |||
|
186 | IPLoggerApp, | |||
|
187 | ]) | |||
|
188 | for App in apps: | |||
|
189 | app = App() | |||
|
190 | app.config.update(self.config) | |||
|
191 | app.log = self.log | |||
|
192 | app.overwrite = self.overwrite | |||
|
193 | app.copy_config_files=True | |||
|
194 | app.profile = self.profile | |||
|
195 | app.init_profile_dir() | |||
|
196 | app.init_config_files() | |||
|
197 | print 'tic' | |||
|
198 | ||||
|
199 | def stage_default_config_file(self): | |||
|
200 | pass | |||
|
201 | ||||
166 | class ProfileApp(Application): |
|
202 | class ProfileApp(Application): | |
167 | name = u'ipython-profile' |
|
203 | name = u'ipython-profile' | |
168 | description = profile_help |
|
204 | description = profile_help |
@@ -208,9 +208,8 b' class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):' | |||||
208 | "Create and manage IPython profiles.") |
|
208 | "Create and manage IPython profiles.") | |
209 | )) |
|
209 | )) | |
210 |
|
210 | |||
211 | # *do* autocreate requested profile |
|
211 | # *do* autocreate requested profile, but don't create the config file. | |
212 | auto_create=Bool(True) |
|
212 | auto_create=Bool(True) | |
213 | copy_config_files=Bool(True) |
|
|||
214 | # configurables |
|
213 | # configurables | |
215 | ignore_old_config=Bool(False, config=True, |
|
214 | ignore_old_config=Bool(False, config=True, | |
216 | help="Suppress warning messages about legacy config files" |
|
215 | help="Suppress warning messages about legacy config files" |
@@ -322,7 +322,7 b' class IPClusterStart(IPClusterEngines):' | |||||
322 | classes = List() |
|
322 | classes = List() | |
323 | def _classes_default(self,): |
|
323 | def _classes_default(self,): | |
324 | from IPython.parallel.apps import launcher |
|
324 | from IPython.parallel.apps import launcher | |
325 | return [ProfileDir]+launcher.all_launchers |
|
325 | return [ProfileDir] + [IPClusterEngines] + launcher.all_launchers | |
326 |
|
326 | |||
327 | clean_logs = Bool(True, config=True, |
|
327 | clean_logs = Bool(True, config=True, | |
328 | help="whether to cleanup old logs before starting") |
|
328 | help="whether to cleanup old logs before starting") | |
@@ -410,12 +410,11 b' class IPClusterStart(IPClusterEngines):' | |||||
410 |
|
410 | |||
411 | base='IPython.parallel.apps.ipclusterapp.IPCluster' |
|
411 | base='IPython.parallel.apps.ipclusterapp.IPCluster' | |
412 |
|
412 | |||
413 |
class IP |
|
413 | class IPClusterApp(Application): | |
414 | name = u'ipcluster' |
|
414 | name = u'ipcluster' | |
415 | description = _description |
|
415 | description = _description | |
416 |
|
416 | |||
417 | subcommands = {'create' : (base+'Create', create_help), |
|
417 | subcommands = { | |
418 | 'list' : (base+'List', list_help), |
|
|||
419 | 'start' : (base+'Start', start_help), |
|
418 | 'start' : (base+'Start', start_help), | |
420 | 'stop' : (base+'Stop', stop_help), |
|
419 | 'stop' : (base+'Stop', stop_help), | |
421 | 'engines' : (base+'Engines', engines_help), |
|
420 | 'engines' : (base+'Engines', engines_help), |
@@ -103,7 +103,7 b' class MPI(Configurable):' | |||||
103 |
|
103 | |||
104 | class IPEngineApp(BaseParallelApplication): |
|
104 | class IPEngineApp(BaseParallelApplication): | |
105 |
|
105 | |||
106 |
|
|
106 | name = Unicode(u'ipengine') | |
107 | description = Unicode(_description) |
|
107 | description = Unicode(_description) | |
108 | config_file_name = Unicode(default_config_file_name) |
|
108 | config_file_name = Unicode(default_config_file_name) | |
109 | classes = List([ProfileDir, Session, EngineFactory, Kernel, MPI]) |
|
109 | classes = List([ProfileDir, Session, EngineFactory, Kernel, MPI]) |
@@ -61,7 +61,7 b" aliases.update(dict(url='LogWatcher.url', topics='LogWatcher.topics'))" | |||||
61 |
|
61 | |||
62 | class IPLoggerApp(BaseParallelApplication): |
|
62 | class IPLoggerApp(BaseParallelApplication): | |
63 |
|
63 | |||
64 |
name = u'iplogger |
|
64 | name = u'iplogger' | |
65 | description = _description |
|
65 | description = _description | |
66 | config_file_name = Unicode(default_config_file_name) |
|
66 | config_file_name = Unicode(default_config_file_name) | |
67 |
|
67 |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
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