diff --git a/traitlets/config/application.py b/traitlets/config/application.py index 91a6f121d..67dd0af81 100644 --- a/traitlets/config/application.py +++ b/traitlets/config/application.py @@ -6,13 +6,15 @@ from __future__ import print_function +from collections import defaultdict, OrderedDict from copy import deepcopy +import io import json import logging import os +import pprint import re import sys -from collections import defaultdict, OrderedDict from decorator import decorator @@ -229,13 +231,29 @@ def _log_default(self): return log # the alias map for configurables - 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() + flags = { + 'debug': { + 'Application': { + 'log_level': logging.DEBUG, + }, + }, + 'show-config': { + 'Application': { + 'show_config': True, + }, + }, + 'show-config-json': { + 'Application': { + 'show_config_json': True, + }, + }, + } @observe('flags') @observe_compat def _flags_changed(self, change): @@ -267,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 + self.start = self.start_show_config def __init__(self, **kwargs): SingletonConfigurable.__init__(self, **kwargs) @@ -304,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: @@ -589,10 +655,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: @@ -618,7 +684,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) @@ -629,10 +695,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) @@ -696,6 +763,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.