Show More
@@ -118,6 +118,9 b' class Application(SingletonConfigurable):' | |||
|
118 | 118 | option_description = Unicode(option_description) |
|
119 | 119 | keyvalue_description = Unicode(keyvalue_description) |
|
120 | 120 | subcommand_description = Unicode(subcommand_description) |
|
121 | ||
|
122 | python_config_loader_class = PyFileConfigLoader | |
|
123 | json_config_loader_class = JSONFileConfigLoader | |
|
121 | 124 | |
|
122 | 125 | # The usage and example string that goes at the end of the help string. |
|
123 | 126 | examples = Unicode() |
@@ -507,8 +510,8 b' class Application(SingletonConfigurable):' | |||
|
507 | 510 | path = [path] |
|
508 | 511 | for path in path[::-1]: |
|
509 | 512 | # path list is in descending priority order, so load files backwards: |
|
510 |
pyloader = |
|
|
511 |
jsonloader = |
|
|
513 | pyloader = cls.python_config_loader_class(basefilename+'.py', path=path, log=log) | |
|
514 | jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log) | |
|
512 | 515 | config = None |
|
513 | 516 | for loader in [pyloader, jsonloader]: |
|
514 | 517 | try: |
@@ -436,52 +436,29 b' class PyFileConfigLoader(FileConfigLoader):' | |||
|
436 | 436 | raise ConfigFileNotFound(str(e)) |
|
437 | 437 | self._read_file_as_dict() |
|
438 | 438 | return self.config |
|
439 | ||
|
440 | ||
|
439 | ||
|
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 | 455 | def _read_file_as_dict(self): |
|
442 | 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 | 457 | def get_config(): |
|
481 | 458 | return self.config |
|
482 | ||
|
459 | ||
|
483 | 460 | namespace = dict( |
|
484 | load_subconfig=load_subconfig, | |
|
461 | load_subconfig=self.load_subconfig, | |
|
485 | 462 | get_config=get_config, |
|
486 | 463 | __file__=self.full_filename, |
|
487 | 464 | ) |
@@ -20,7 +20,7 b' import shutil' | |||
|
20 | 20 | import sys |
|
21 | 21 | |
|
22 | 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 | 24 | from IPython.core import release, crashhandler |
|
25 | 25 | from IPython.core.profiledir import ProfileDir, ProfileDirError |
|
26 | 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 | 80 | class BaseIPythonApplication(Application): |
|
68 | 81 | |
@@ -73,6 +86,9 b' class BaseIPythonApplication(Application):' | |||
|
73 | 86 | aliases = Dict(base_aliases) |
|
74 | 87 | flags = Dict(base_flags) |
|
75 | 88 | classes = List([ProfileDir]) |
|
89 | ||
|
90 | # enable `load_subconfig('cfg.py', profile='name')` | |
|
91 | python_config_loader_class = ProfileAwareConfigLoader | |
|
76 | 92 | |
|
77 | 93 | # Track whether the config_file has changed, |
|
78 | 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