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 = |
|
513 | pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log) | |
511 |
jsonloader = |
|
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: |
@@ -436,52 +436,29 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(): | |
481 | return self.config |
|
458 | return self.config | |
482 |
|
459 | |||
483 | namespace = dict( |
|
460 | namespace = dict( | |
484 | load_subconfig=load_subconfig, |
|
461 | load_subconfig=self.load_subconfig, | |
485 | get_config=get_config, |
|
462 | get_config=get_config, | |
486 | __file__=self.full_filename, |
|
463 | __file__=self.full_filename, | |
487 | ) |
|
464 | ) |
@@ -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. |
General Comments 0
You need to be logged in to leave comments.
Login now