##// END OF EJS Templates
Merge pull request #8137 from minrk/config-profile...
Matthias Bussonnier -
r20873:aef3f59e merge
parent child Browse files
Show More
@@ -118,6 +118,9 b' class Application(SingletonConfigurable):'
118 option_description = Unicode(option_description)
118 option_description = Unicode(option_description)
119 keyvalue_description = Unicode(keyvalue_description)
119 keyvalue_description = Unicode(keyvalue_description)
120 subcommand_description = Unicode(subcommand_description)
120 subcommand_description = Unicode(subcommand_description)
121
122 python_config_loader_class = PyFileConfigLoader
123 json_config_loader_class = JSONFileConfigLoader
121
124
122 # The usage and example string that goes at the end of the help string.
125 # The usage and example string that goes at the end of the help string.
123 examples = Unicode()
126 examples = Unicode()
@@ -507,8 +510,8 b' class Application(SingletonConfigurable):'
507 path = [path]
510 path = [path]
508 for path in path[::-1]:
511 for path in path[::-1]:
509 # path list is in descending priority order, so load files backwards:
512 # path list is in descending priority order, so load files backwards:
510 pyloader = PyFileConfigLoader(basefilename+'.py', path=path, log=log)
513 pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log)
511 jsonloader = JSONFileConfigLoader(basefilename+'.json', path=path, log=log)
514 jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log)
512 config = None
515 config = None
513 for loader in [pyloader, jsonloader]:
516 for loader in [pyloader, jsonloader]:
514 try:
517 try:
@@ -551,9 +554,7 b' class Application(SingletonConfigurable):'
551
554
552 def generate_config_file(self):
555 def generate_config_file(self):
553 """generate default config file from Configurables"""
556 """generate default config file from Configurables"""
554 lines = ["# Configuration file for %s."%self.name]
557 lines = ["# Configuration file for %s." % self.name]
555 lines.append('')
556 lines.append('c = get_config()')
557 lines.append('')
558 lines.append('')
558 for cls in self._config_classes:
559 for cls in self._config_classes:
559 lines.append(cls.class_config_section())
560 lines.append(cls.class_config_section())
@@ -436,52 +436,31 b' class PyFileConfigLoader(FileConfigLoader):'
436 raise ConfigFileNotFound(str(e))
436 raise ConfigFileNotFound(str(e))
437 self._read_file_as_dict()
437 self._read_file_as_dict()
438 return self.config
438 return self.config
439
439
440
440 def load_subconfig(self, fname, path=None):
441 """Injected into config file namespace as load_subconfig"""
442 if path is None:
443 path = self.path
444
445 loader = self.__class__(fname, path)
446 try:
447 sub_config = loader.load_config()
448 except ConfigFileNotFound:
449 # Pass silently if the sub config is not there,
450 # treat it as an empty config file.
451 pass
452 else:
453 self.config.merge(sub_config)
454
441 def _read_file_as_dict(self):
455 def _read_file_as_dict(self):
442 """Load the config file into self.config, with recursive loading."""
456 """Load the config file into self.config, with recursive loading."""
443 # This closure is made available in the namespace that is used
444 # to exec the config file. It allows users to call
445 # load_subconfig('myconfig.py') to load config files recursively.
446 # It needs to be a closure because it has references to self.path
447 # and self.config. The sub-config is loaded with the same path
448 # as the parent, but it uses an empty config which is then merged
449 # with the parents.
450
451 # If a profile is specified, the config file will be loaded
452 # from that profile
453
454 def load_subconfig(fname, profile=None):
455 # import here to prevent circular imports
456 from IPython.core.profiledir import ProfileDir, ProfileDirError
457 if profile is not None:
458 try:
459 profile_dir = ProfileDir.find_profile_dir_by_name(
460 get_ipython_dir(),
461 profile,
462 )
463 except ProfileDirError:
464 return
465 path = profile_dir.location
466 else:
467 path = self.path
468 loader = PyFileConfigLoader(fname, path)
469 try:
470 sub_config = loader.load_config()
471 except ConfigFileNotFound:
472 # Pass silently if the sub config is not there. This happens
473 # when a user s using a profile, but not the default config.
474 pass
475 else:
476 self.config.merge(sub_config)
477
478 # Again, this needs to be a closure and should be used in config
479 # files to get the config being loaded.
480 def get_config():
457 def get_config():
458 """Unnecessary now, but a deprecation warning is more trouble than it's worth."""
481 return self.config
459 return self.config
482
460
483 namespace = dict(
461 namespace = dict(
484 load_subconfig=load_subconfig,
462 c=self.config,
463 load_subconfig=self.load_subconfig,
485 get_config=get_config,
464 get_config=get_config,
486 __file__=self.full_filename,
465 __file__=self.full_filename,
487 )
466 )
@@ -8,7 +8,6 b' import json'
8 import os
8 import os
9
9
10 from IPython.config import LoggingConfigurable
10 from IPython.config import LoggingConfigurable
11 from IPython.utils.path import locate_profile
12 from IPython.utils.py3compat import PY3
11 from IPython.utils.py3compat import PY3
13 from IPython.utils.traitlets import Unicode
12 from IPython.utils.traitlets import Unicode
14
13
@@ -35,22 +34,12 b' def recursive_update(target, new):'
35
34
36
35
37 class BaseJSONConfigManager(LoggingConfigurable):
36 class BaseJSONConfigManager(LoggingConfigurable):
38 """General config manager
37 """General JSON config manager
39
38
40 Deals with persisting/storing config in a json file
39 Deals with persisting/storing config in a json file
41 in IPython profile
42 """
40 """
43
41
44 profile_dir = Unicode()
42 config_dir = Unicode('.')
45 def _profile_dir_default(self):
46 return locate_profile()
47
48 @property
49 def config_dir(self):
50 return self._config_dir()
51
52 def _config_dir(self):
53 return self.profile_dir
54
43
55 def ensure_config_dir_exists(self):
44 def ensure_config_dir_exists(self):
56 try:
45 try:
@@ -20,7 +20,7 b' import shutil'
20 import sys
20 import sys
21
21
22 from IPython.config.application import Application, catch_config_error
22 from IPython.config.application import Application, catch_config_error
23 from IPython.config.loader import ConfigFileNotFound
23 from IPython.config.loader import ConfigFileNotFound, PyFileConfigLoader
24 from IPython.core import release, crashhandler
24 from IPython.core import release, crashhandler
25 from IPython.core.profiledir import ProfileDir, ProfileDirError
25 from IPython.core.profiledir import ProfileDir, ProfileDirError
26 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
26 from IPython.utils.path import get_ipython_dir, get_ipython_package_dir, ensure_dir_exists
@@ -63,6 +63,19 b' base_flags = dict('
63 """)
63 """)
64 )
64 )
65
65
66 class ProfileAwareConfigLoader(PyFileConfigLoader):
67 """A Python file config loader that is aware of IPython profiles."""
68 def load_subconfig(self, fname, path=None, profile=None):
69 if profile is not None:
70 try:
71 profile_dir = ProfileDir.find_profile_dir_by_name(
72 get_ipython_dir(),
73 profile,
74 )
75 except ProfileDirError:
76 return
77 path = profile_dir.location
78 return super(ProfileAwareConfigLoader, self).load_subconfig(fname, path=path)
66
79
67 class BaseIPythonApplication(Application):
80 class BaseIPythonApplication(Application):
68
81
@@ -73,6 +86,9 b' class BaseIPythonApplication(Application):'
73 aliases = Dict(base_aliases)
86 aliases = Dict(base_aliases)
74 flags = Dict(base_flags)
87 flags = Dict(base_flags)
75 classes = List([ProfileDir])
88 classes = List([ProfileDir])
89
90 # enable `load_subconfig('cfg.py', profile='name')`
91 python_config_loader_class = ProfileAwareConfigLoader
76
92
77 # Track whether the config_file has changed,
93 # Track whether the config_file has changed,
78 # because some logic happens only if we aren't using the default.
94 # because some logic happens only if we aren't using the default.
1 NO CONTENT: file renamed from IPython/config/profile/README_STARTUP to IPython/core/profile/README_STARTUP
NO CONTENT: file renamed from IPython/config/profile/README_STARTUP to IPython/core/profile/README_STARTUP
@@ -112,7 +112,7 b' def list_profiles_in(path):'
112
112
113 def list_bundled_profiles():
113 def list_bundled_profiles():
114 """list profiles that are bundled with IPython."""
114 """list profiles that are bundled with IPython."""
115 path = os.path.join(get_ipython_package_dir(), u'config', u'profile')
115 path = os.path.join(get_ipython_package_dir(), u'core', u'profile')
116 files = os.listdir(path)
116 files = os.listdir(path)
117 profiles = []
117 profiles = []
118 for profile in files:
118 for profile in files:
@@ -114,7 +114,7 b' class ProfileDir(LoggingConfigurable):'
114 self._mkdir(self.startup_dir)
114 self._mkdir(self.startup_dir)
115
115
116 readme = os.path.join(self.startup_dir, 'README')
116 readme = os.path.join(self.startup_dir, 'README')
117 src = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'README_STARTUP')
117 src = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'README_STARTUP')
118
118
119 if not os.path.exists(src):
119 if not os.path.exists(src):
120 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
120 self.log.warn("Could not copy README_STARTUP to startup dir. Source file %s does not exist.", src)
@@ -169,7 +169,7 b' class ProfileDir(LoggingConfigurable):'
169 if os.path.isfile(dst) and not overwrite:
169 if os.path.isfile(dst) and not overwrite:
170 return False
170 return False
171 if path is None:
171 if path is None:
172 path = os.path.join(get_ipython_package_dir(), u'config', u'profile', u'default')
172 path = os.path.join(get_ipython_package_dir(), u'core', u'profile', u'default')
173 src = os.path.join(path, config_file)
173 src = os.path.join(path, config_file)
174 shutil.copy(src, dst)
174 shutil.copy(src, dst)
175 return True
175 return True
@@ -149,9 +149,8 b' def test_list_profiles_in():'
149
149
150 def test_list_bundled_profiles():
150 def test_list_bundled_profiles():
151 # This variable will need to be updated when a new profile gets bundled
151 # This variable will need to be updated when a new profile gets bundled
152 bundled_true = [u'cluster', u'math', u'pysh', u'sympy']
153 bundled = sorted(list_bundled_profiles())
152 bundled = sorted(list_bundled_profiles())
154 nt.assert_equal(bundled, bundled_true)
153 nt.assert_equal(bundled, [])
155
154
156
155
157 def test_profile_create_ipython_dir():
156 def test_profile_create_ipython_dir():
@@ -3,12 +3,19 b''
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 import os
7
8 from IPython.config.manager import BaseJSONConfigManager
6 from IPython.config.manager import BaseJSONConfigManager
7 from IPython.utils.path import locate_profile
8 from IPython.utils.traitlets import Unicode
9
9
10 class ConfigManager(BaseJSONConfigManager):
10 class ConfigManager(BaseJSONConfigManager):
11 """Config Manager used for storing notebook frontend config"""
11 """Config Manager used for storing notebook frontend config"""
12
13 profile = Unicode('default', config=True)
14
15 profile_dir = Unicode(config=True)
16
17 def _profile_dir_default(self):
18 return locate_profile(self.profile)
12
19
13 def _config_dir(self):
20 def _config_dir_default(self):
14 return os.path.join(self.profile_dir, 'nbconfig')
21 return self.profile_dir
@@ -183,7 +183,7 b' def find_package_data():'
183 os.chdir(cwd)
183 os.chdir(cwd)
184
184
185 package_data = {
185 package_data = {
186 'IPython.config.profile' : ['README*', '*/*.py'],
186 'IPython.core' : ['profile/README*'],
187 'IPython.core.tests' : ['*.png', '*.jpg'],
187 'IPython.core.tests' : ['*.png', '*.jpg'],
188 'IPython.lib.tests' : ['*.wav'],
188 'IPython.lib.tests' : ['*.wav'],
189 'IPython.testing.plugin' : ['*.txt'],
189 'IPython.testing.plugin' : ['*.txt'],
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
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