-
-
Notifications
You must be signed in to change notification settings - Fork 203
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
setting this value will skip Application start and show loaded config on stdout, instead. if show_config[_json is given, it will be json-formatted
- Loading branch information
Showing
1 changed file
with
82 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,11 +8,16 @@ | |
|
||
from collections import defaultdict, OrderedDict | ||
from copy import deepcopy | ||
import io | ||
import json | ||
import logging | ||
import os | ||
import pprint | ||
import re | ||
import sys | ||
|
||
from decorator import decorator | ||
|
||
from traitlets.config.configurable import Configurable, SingletonConfigurable | ||
from traitlets.config.loader import ( | ||
KVArgParseConfigLoader, PyFileConfigLoader, Config, ArgumentError, ConfigFileNotFound, JSONFileConfigLoader | ||
|
@@ -236,23 +241,29 @@ def _log_default(self): | |
#: the alias map for configurables | ||
#: Keys might strings or tuples for additional options; single-letter alias accessed like `-v`. | ||
#: Values might be like "Class.trait" strings of two-tuples: (Class.trait, help-text). | ||
aliases = Dict({'log-level' : 'Application.log_level'}) | ||
aliases = {'log-level' : 'Application.log_level'} | ||
|
||
# flags for loading Configurables or store_const style flags | ||
# flags are loaded from this dict by '--key' flags | ||
# this must be a dict of two-tuples, the first element being the Config/dict | ||
# and the second being the help string for the flag | ||
flags = Dict() | ||
@observe('flags') | ||
@observe_compat | ||
def _flags_changed(self, change): | ||
"""ensure flags dict is valid""" | ||
new = change.new | ||
for key, value in new.items(): | ||
assert len(value) == 2, "Bad flag: %r:%s" % (key, value) | ||
assert isinstance(value[0], (dict, Config)), "Bad flag: %r:%s" % (key, value) | ||
assert isinstance(value[1], six.string_types), "Bad flag: %r:%s" % (key, value) | ||
|
||
flags = { | ||
'debug': { | ||
'Application': { | ||
'log_level': logging.DEBUG, | ||
}, | ||
}, | ||
'show-config': { | ||
'Application': { | ||
'show_config': True, | ||
}, | ||
}, | ||
'show-config-json': { | ||
'Application': { | ||
'show_config_json': True, | ||
}, | ||
}, | ||
} | ||
|
||
# subcommands for launching other applications | ||
# if this is not empty, this will be a parent Application | ||
|
@@ -274,6 +285,25 @@ def _flags_changed(self, change): | |
""" | ||
) | ||
|
||
_loaded_config_files = List() | ||
|
||
show_config = Bool( | ||
help="Instead of starting the Application, dump configuration to stdout" | ||
).tag(config=True) | ||
|
||
show_config_json = Bool( | ||
help="Instead of starting the Application, dump configuration to stdout (as JSON)" | ||
).tag(config=True) | ||
|
||
@observe('show_config_json') | ||
def _show_config_json_changed(self, change): | ||
self.show_config = change.new | ||
|
||
@observe('show_config') | ||
def _show_config_changed(self, change): | ||
if change.new: | ||
self._save_start = self.start | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
minrk
Author
Member
|
||
self.start = self.start_show_config | ||
|
||
def __init__(self, **kwargs): | ||
SingletonConfigurable.__init__(self, **kwargs) | ||
|
@@ -311,6 +341,35 @@ def start(self): | |
if self.subapp is not None: | ||
return self.subapp.start() | ||
|
||
def start_show_config(self): | ||
"""start function used when show_config is True""" | ||
if self.show_config_json: | ||
json.dump(self.config, sys.stdout, | ||
indent=1, sort_keys=True, default=repr) | ||
return | ||
|
||
if self._loaded_config_files: | ||
print("Loaded config files:") | ||
for f in self._loaded_config_files: | ||
print(' ' + f) | ||
print() | ||
|
||
for classname in sorted(self.config): | ||
print(classname) | ||
class_config = self.config[classname] | ||
if not class_config: | ||
continue | ||
for traitname in sorted(class_config): | ||
value = class_config[traitname] | ||
sio = io.StringIO() | ||
pprint.pprint(value, stream=sio) | ||
vs = sio.getvalue() | ||
sys.stdout.write(' .%s = ' % traitname) | ||
if '\n' in vs.strip(): | ||
sys.stdout.write('\n') | ||
vs = indent(vs, 4) | ||
sys.stdout.write(vs) | ||
|
||
def print_alias_help(self): | ||
"""Print the alias part of the help.""" | ||
if not self.aliases: | ||
|
@@ -615,10 +674,10 @@ def _load_config_files(cls, basefilename, path=None, log=None, raise_config_file | |
if log: | ||
log.debug("Looking for %s in %s", basefilename, path or os.getcwd()) | ||
jsonloader = cls.json_config_loader_class(basefilename+'.json', path=path, log=log) | ||
config = None | ||
loaded = [] | ||
filenames = [] | ||
for loader in [pyloader, jsonloader]: | ||
config = None | ||
try: | ||
config = loader.load_config() | ||
except ConfigFileNotFound: | ||
|
@@ -644,7 +703,7 @@ def _load_config_files(cls, basefilename, path=None, log=None, raise_config_file | |
" {1} has higher priority: {2}".format( | ||
filename, loader.full_filename, json.dumps(collisions, indent=2), | ||
)) | ||
yield config | ||
yield (config, loader.full_filename) | ||
loaded.append(config) | ||
filenames.append(loader.full_filename) | ||
|
||
|
@@ -653,10 +712,11 @@ def load_config_file(self, filename, path=None): | |
"""Load config files by filename and path.""" | ||
filename, ext = os.path.splitext(filename) | ||
new_config = Config() | ||
for config in self._load_config_files(filename, path=path, log=self.log, | ||
for (config, filename) in self._load_config_files(filename, path=path, log=self.log, | ||
raise_config_file_errors=self.raise_config_file_errors, | ||
): | ||
new_config.merge(config) | ||
self._loaded_config_files.append(filename) | ||
# add self.cli_config to preserve CLI config priority | ||
new_config.merge(self.cli_config) | ||
self.update_config(new_config) | ||
|
@@ -727,6 +787,9 @@ def launch_instance(cls, argv=None, **kwargs): | |
# utility functions, for convenience | ||
#----------------------------------------------------------------------------- | ||
|
||
default_aliases = Application.aliases | ||
default_flags = Application.flags | ||
|
||
def boolean_flag(name, configurable, set_help='', unset_help=''): | ||
"""Helper for building basic --trait, --no-trait flags. | ||
|
@@ -769,3 +832,7 @@ def get_config(): | |
return Application.instance().config | ||
else: | ||
return Config() | ||
|
||
|
||
if __name__ == '__main__': | ||
Application.launch_instance() |
@minrk Is there a reason to replace start in order to print configs,
instead of simply putting an
if then
inside defaultstart()
?The way it is currently implemented makes problematic to override
Application.start()
in subclasses.