def test_prune_keys(self): for scalar in (None, True, 1, float(1), 'abc', {1, 2}): eq_(prune_keys(scalar, 'comment'), scalar) with open(info.home / 'config.prune_keys.yaml', encoding='utf-8') as handle: tests = yaml.load(handle, Loader=yaml.SafeLoader) for test in tests: eq_(prune_keys(test['source'], 'comment'), test['target'])
def init(force_reload=False, **kwargs): ''' Update Gramex configurations and start / restart the instance. ``gramex.init()`` can be called any time to refresh configuration files. ``gramex.init(key=val)`` adds ``val`` as a configuration layer named ``key``. If ``val`` is a Path, it is converted into a PathConfig. (If it is Path directory, use ``gramex.yaml``.) Services are re-initialised if their configurations have changed. Service callbacks are always re-run (even if the configuration hasn't changed.) ''' try: setup_secrets(paths['base'] / '.secrets.yaml') except Exception as e: app_log.exception(e) # Reset variables variables.clear() variables.update(setup_variables()) # Initialise configuration layers with provided configurations # AttrDicts are updated as-is. Paths are converted to PathConfig paths.update(kwargs) for key, val in paths.items(): if isinstance(val, Path): if val.is_dir(): val = val / 'gramex.yaml' val = PathConfig(val) config_layers[key] = val # Locate all config files config_files = set() for path_config in config_layers.values(): if hasattr(path_config, '__info__'): for pathinfo in path_config.__info__.imports: config_files.add(pathinfo.path) config_files = list(config_files) # Add config file folders to sys.path sys.path[:] = _sys_path + [ str(path.absolute().parent) for path in config_files ] from . import services globals( )['service'] = services.info # gramex.service = gramex.services.info # Override final configurations appconfig.clear() appconfig.update(+config_layers) # --settings.debug => log.root.level = True if appconfig.app.get('settings', {}).get('debug', False): appconfig.log.root.level = logging.DEBUG # Set up a watch on config files (including imported files) if appconfig.app.get('watch', True): from services import watcher watcher.watch('gramex-reconfig', paths=config_files, on_modified=lambda event: init()) # Run all valid services. (The "+" before config_chain merges the chain) # Services may return callbacks to be run at the end for key, val in appconfig.items(): if key not in conf or conf[key] != val or force_reload: if hasattr(services, key): app_log.debug('Loading service: %s', key) conf[key] = prune_keys(val, {'comment'}) callback = getattr(services, key)(conf[key]) if callable(callback): callbacks[key] = callback else: app_log.error('No service named %s', key) # Run the callbacks. Specifically, the app service starts the Tornado ioloop for key in (+config_layers).keys(): if key in callbacks: app_log.debug('Running callback: %s', key) callbacks[key]()