115 lines
3.9 KiB
Python
115 lines
3.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
The reader module is used to read the config data. This will read in cli
|
|
arguments and merge them with config fie arguments.
|
|
"""
|
|
# Import python libs
|
|
import warnings
|
|
|
|
# Priority order: cli, config, cli_defaults
|
|
|
|
__virtualname__ = "reader"
|
|
__contracts__ = [__virtualname__]
|
|
|
|
|
|
def _merge_dicts(opts, updates, os_opts, explicit_cli_args):
|
|
"""
|
|
recursively merge updates into opts
|
|
"""
|
|
for key, val in os_opts.items():
|
|
if not val:
|
|
# Don't use empty os vals
|
|
continue
|
|
if key in opts:
|
|
opts[key] = val
|
|
for key, val in updates.items():
|
|
if isinstance(val, dict) and isinstance(opts.get(key), dict):
|
|
_merge_dicts(opts.get(key, {}), val, os_opts, explicit_cli_args)
|
|
elif val is not None:
|
|
if key not in opts:
|
|
# The key is not in opts(from config file), let's add it
|
|
opts[key] = val
|
|
continue
|
|
|
|
# We already have a value for the key in opts
|
|
if opts[key] == val:
|
|
# The value is the same, carry on
|
|
continue
|
|
|
|
if key in explicit_cli_args:
|
|
# We have a value for the key in opts(from config file) but
|
|
# this option was explicitly passed on the CLI, ie, it's not
|
|
# a default value.
|
|
# Overwrite what's in opts
|
|
opts[key] = val
|
|
continue
|
|
return opts
|
|
|
|
|
|
def read(
|
|
hub,
|
|
defaults,
|
|
subs=None,
|
|
loader="json",
|
|
process_cli=True,
|
|
process_cli_known_args_only=False,
|
|
args=None,
|
|
namespace=None,
|
|
):
|
|
"""
|
|
Pass in the default options dict to use
|
|
:param opts:
|
|
:param process_cli: Process the passed args or sys.argv
|
|
:param process_cli_known_args_only: Tells the ArgumentParser to only process known arguments
|
|
:param args: Arguments to pass to ArgumentParser
|
|
:param namespace: argparse.Namespace to pass to ArgumentParser
|
|
:return: options
|
|
"""
|
|
msg = "Pop-config is the new means to load configs in pop, reader.read will be removed in pop 13"
|
|
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
|
hub.conf._loader = loader
|
|
if subs:
|
|
hub.conf.args.subs(subs)
|
|
opts = hub.conf.args.setup(defaults)["return"]
|
|
os_opts = hub.conf.os.gather(defaults)
|
|
if process_cli is True:
|
|
cli_opts = hub.conf.args.parse(args, namespace, process_cli_known_args_only)[
|
|
"return"
|
|
]
|
|
else:
|
|
cli_opts = {}
|
|
explicit_cli_args = cli_opts.pop("_explicit_cli_args_", set())
|
|
cli_opts = hub.conf.args.render(defaults, cli_opts, explicit_cli_args)
|
|
kwargs = {}
|
|
# Due to the order of priorities and the representation of defaults in the
|
|
# Argparser we need to manually check if the config option values are from
|
|
# the cli or from defaults
|
|
f_func = False
|
|
if "config_dir" in cli_opts:
|
|
if cli_opts["config_dir"]:
|
|
kwargs["confdir"] = cli_opts["config_dir"]
|
|
else:
|
|
kwargs["confdir"] = opts["config_dir"]
|
|
if "config_recurse" in cli_opts:
|
|
if cli_opts["config_recurse"]:
|
|
kwargs["recurse"] = cli_opts["config_recurse"]
|
|
else:
|
|
kwargs["recurse"] = opts["config_recurse"]
|
|
# If the config_dir configuration dictionary provides a configuration
|
|
# file pattern to read, pass it along
|
|
kwargs["pattern"] = defaults["config_dir"].get("pattern")
|
|
f_func = hub.conf.file.load_dir
|
|
elif "config" in cli_opts:
|
|
if cli_opts["config"]:
|
|
kwargs["paths"] = cli_opts["config"]
|
|
else:
|
|
kwargs["paths"] = opts["config"]
|
|
f_func = hub.conf.file.load_file
|
|
# Render args before config parsing
|
|
if f_func:
|
|
f_opts = f_func(**kwargs)
|
|
opts.update(f_opts)
|
|
return _merge_dicts(opts, cli_opts, os_opts, explicit_cli_args)
|
|
else:
|
|
return _merge_dicts(opts, cli_opts, os_opts, explicit_cli_args)
|