Skip to content

Commit

Permalink
omnibus-2024-05-23 (ufs-community#497)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddenp-noaa authored May 28, 2024
1 parent d8588e8 commit 96785cd
Show file tree
Hide file tree
Showing 14 changed files with 58 additions and 88 deletions.
1 change: 0 additions & 1 deletion docs/sections/user_guide/cli/drivers/chgres_cube.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ Its contents are described in depth in section :ref:`chgres_cube_yaml`. Each of
$ uw chgres_cube run --config-file config.yaml --cycle 2023-12-15T18 --batch --dry-run
.. include:: ../../../../shared/key_path.rst

* The ``run`` task depends on the other available tasks and executes them as prerequisites. It is possible to execute any task directly, which entails execution of any of *its* dependencies. For example, to create a ``chgres_cube`` run directory provisioned with all the files, directories, symlinks, etc. required per the configuration file:
Expand Down
2 changes: 1 addition & 1 deletion docs/sections/user_guide/cli/tools/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ and YAML file ``update.yaml`` with contents:
.. literalinclude:: config/realize-extension-stdin-fix.out
:language: text

* This example demonstrates: 1. Reading a config from ``stdin``, 2. Extracting a specific subsection with the ``--output-block`` option, and 3. Writing the output in a different format:
* This example demonstrates: 1. Reading a config from ``stdin``, 2. Extracting a specific subsection with the ``--key-path`` option, and 3. Writing the output in a different format:

.. literalinclude:: config/realize-combo.cmd
:language: text
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
cat config.yaml | uw config realize --input-format yaml --update-file update.yaml --output-block values --output-format sh
cat config.yaml | uw config realize --input-format yaml --update-file update.yaml --key-path values --output-format sh
6 changes: 3 additions & 3 deletions docs/sections/user_guide/cli/tools/config/realize-help.out
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ usage: uw config realize [-h] [--version] [--input-file PATH]
[--update-format {ini,nml,sh,yaml}]
[--output-file PATH]
[--output-format {ini,nml,sh,yaml}]
[--output-block KEY[.KEY[.KEY]...]] [--values-needed]
[--total] [--dry-run] [--quiet] [--verbose]
[--key-path KEY[.KEY...]] [--values-needed] [--total]
[--dry-run] [--quiet] [--verbose]

Realize config

Expand All @@ -26,7 +26,7 @@ Optional arguments:
Path to output file (defaults to stdout)
--output-format {ini,nml,sh,yaml}
Output format
--output-block KEY[.KEY[.KEY]...]
--key-path KEY[.KEY...]
Dot-separated path of keys to the block to be output
--values-needed
Print report of values needed to render template
Expand Down
22 changes: 10 additions & 12 deletions docs/sections/user_guide/cli/tools/config/realize-values-needed.out
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
[2024-05-23T19:39:17] INFO Keys that are complete:
[2024-05-23T19:39:17] INFO values
[2024-05-23T19:39:17] INFO values.greeting
[2024-05-23T19:39:17] INFO values.message
[2024-05-23T19:39:17] INFO values.recipient
[2024-05-23T19:39:17] INFO values.repeat
[2024-05-23T19:39:17] INFO
[2024-05-23T19:39:17] INFO Keys with unrendered Jinja2 variables/expressions:
[2024-05-23T19:39:17] INFO values.date: {{ yyyymmdd }}
[2024-05-23T19:39:17] INFO
[2024-05-23T19:39:17] INFO Keys that are set to empty:
[2024-05-23T19:39:17] INFO values.empty
[2024-05-28T16:43:43] INFO Keys that are complete:
[2024-05-28T16:43:43] INFO values
[2024-05-28T16:43:43] INFO values.empty
[2024-05-28T16:43:43] INFO values.greeting
[2024-05-28T16:43:43] INFO values.message
[2024-05-28T16:43:43] INFO values.recipient
[2024-05-28T16:43:43] INFO values.repeat
[2024-05-28T16:43:43] INFO
[2024-05-28T16:43:43] INFO Keys with unrendered Jinja2 variables/expressions:
[2024-05-28T16:43:43] INFO values.date: {{ yyyymmdd }}
6 changes: 3 additions & 3 deletions src/uwtools/api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def realize(
update_format: Optional[str] = None,
output_file: Optional[Union[Path, str]] = None,
output_format: Optional[str] = None,
output_block: Optional[List[Union[str, int]]] = None,
key_path: Optional[List[Union[str, int]]] = None,
values_needed: bool = False,
total: bool = False,
dry_run: bool = False,
Expand All @@ -138,7 +138,7 @@ def realize(
update_format=update_format,
output_file=_str2path(output_file),
output_format=output_format,
output_block=output_block,
key_path=key_path,
values_needed=values_needed,
total=total,
dry_run=dry_run,
Expand Down Expand Up @@ -235,7 +235,7 @@ def validate(
:param update_format: Format of the update config (optional if file's extension is recognized)
:param output_file: Output config file (``None`` or unspecified => write to ``stdout``)
:param output_format: Format of the output config (optional if file's extension is recognized)
:param output_block: Path through keys to the desired output block
:param key_path: Path through keys to the desired output block
:param values_needed: Report complete, missing, and template values
:param total: Require rendering of all Jinja2 variables/expressions
:param dry_run: Log output instead of writing to output
Expand Down
25 changes: 9 additions & 16 deletions src/uwtools/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def _add_subparser_config_realize(subparsers: Subparsers) -> ActionChecks:
_add_arg_update_format(optional, choices=FORMATS)
_add_arg_output_file(optional)
_add_arg_output_format(optional, choices=FORMATS)
_add_arg_output_block(optional)
_add_arg_key_path(optional, helpmsg="Dot-separated path of keys to the block to be output")
_add_arg_values_needed(optional)
_add_arg_total(optional)
_add_arg_dry_run(optional)
Expand Down Expand Up @@ -217,7 +217,7 @@ def _dispatch_config_realize(args: Args) -> bool:
update_format=args[STR.updatefmt],
output_file=args[STR.outfile],
output_format=args[STR.outfmt],
output_block=args[STR.outblock],
key_path=args[STR.keypath],
values_needed=args[STR.valsneeded],
total=args[STR.total],
dry_run=args[STR.dryrun],
Expand Down Expand Up @@ -641,11 +641,10 @@ def _add_arg_key_eq_val_pairs(group: Group) -> None:
)


def _add_arg_key_path(group: Group) -> None:
def _add_arg_key_path(group: Group, helpmsg: str) -> None:
group.add_argument(
_switch(STR.keypath),
help="Dot-separated path of keys leading through the config "
"to the driver's configuration block",
help=helpmsg,
metavar="KEY[.KEY...]",
required=False,
type=lambda s: s.split("."),
Expand All @@ -670,16 +669,6 @@ def _add_arg_leadtime(group: Group) -> None:
)


def _add_arg_output_block(group: Group):
group.add_argument(
_switch(STR.outblock),
help="Dot-separated path of keys to the block to be output",
metavar="KEY[.KEY[.KEY]...]",
required=False,
type=lambda s: s.split("."),
)


def _add_arg_output_file(group: Group, required: bool = False) -> None:
group.add_argument(
_switch(STR.outfile),
Expand Down Expand Up @@ -899,7 +888,11 @@ def _add_subparser_for_driver_task(
_add_arg_batch(optional)
_add_arg_dry_run(optional)
_add_arg_graph_file(optional)
_add_arg_key_path(optional)
_add_arg_key_path(
optional,
helpmsg="Dot-separated path of keys leading through the config "
"to the driver's configuration block",
)
checks = _add_args_verbosity(optional)
return checks

Expand Down
19 changes: 8 additions & 11 deletions src/uwtools/config/formats/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,38 +83,35 @@ def _load_paths(self, config_files: List[Path]) -> dict:

# Public methods

def characterize_values(self, values: dict, parent: str) -> Tuple[list, list, list]:
def characterize_values(self, values: dict, parent: str) -> Tuple[list, list]:
"""
Characterize values as complete, empty, or template placeholders.
Characterize values as complete or as template placeholders.
:param values: The dictionary to examine.
:param parent: Parent key.
:return: Lists of of complete, empty, and template-placeholder values.
:return: Lists of of complete and template-placeholder values.
"""
complete: List[str] = []
empty: List[str] = []
template: List[str] = []
for key, val in values.items():
if isinstance(val, dict):
complete.append(f"{INDENT}{parent}{key}")
c, e, t = self.characterize_values(val, f"{parent}{key}.")
complete, empty, template = complete + c, empty + e, template + t
c, t = self.characterize_values(val, f"{parent}{key}.")
complete, template = complete + c, template + t
elif isinstance(val, list):
for item in val:
if isinstance(item, dict):
c, e, t = self.characterize_values(item, parent)
complete, empty, template = complete + c, empty + e, template + t
c, t = self.characterize_values(item, parent)
complete, template = complete + c, template + t
complete.append(f"{INDENT}{parent}{key}")
elif "{{" in str(val) or "{%" in str(val):
template.append(f"{INDENT}{parent}{key}: {val}")
break
elif "{{" in str(val) or "{%" in str(val):
template.append(f"{INDENT}{parent}{key}: {val}")
elif val == "" or val is None:
empty.append(f"{INDENT}{parent}{key}")
else:
complete.append(f"{INDENT}{parent}{key}")
return complete, empty, template
return complete, template

def compare_config(self, dict1: dict, dict2: Optional[dict] = None) -> bool:
"""
Expand Down
27 changes: 9 additions & 18 deletions src/uwtools/config/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def realize_config(
update_format: Optional[str] = None,
output_file: Optional[Path] = None,
output_format: Optional[str] = None,
output_block: Optional[List[Union[str, int]]] = None,
key_path: Optional[List[Union[str, int]]] = None,
values_needed: bool = False,
total: bool = False,
dry_run: bool = False,
Expand All @@ -94,7 +94,7 @@ def realize_config(
input_obj = _realize_config_update(input_obj, update_config, update_format)
input_obj.dereference()
output_data, output_format = _realize_config_output_setup(
input_obj, output_file, output_format, output_block
input_obj, output_file, output_format, key_path
)
if dry_run:
for line in str(input_obj).strip().split("\n"):
Expand Down Expand Up @@ -185,23 +185,23 @@ def _realize_config_output_setup(
input_obj: Config,
output_file: Optional[Path] = None,
output_format: Optional[str] = None,
output_block: Optional[List[Union[str, int]]] = None,
key_path: Optional[List[Union[str, int]]] = None,
) -> Tuple[dict, str]:
"""
Set up config-realize output.
:param input_obj: The input Config object.
:param output_file: Output config destination (None => write to stdout).
:param output_format: Format of the output config.
:param output_block: Path through keys to the desired output block.
:param key_path: Path through keys to the desired output block.
:return: The unrealized data to output and the output format name.
"""
output_format = _ensure_format("output", output_format, output_file)
log.debug("Writing output to %s" % (output_file or "stdout"))
_validate_format("output", output_format, input_obj.get_format())
output_data = input_obj.data
if output_block is not None:
for key in output_block:
if key_path is not None:
for key in key_path:
output_data = output_data[key]
config_check_depths_realize(output_data, output_format)
return output_data, output_format
Expand Down Expand Up @@ -238,14 +238,13 @@ def _realize_config_update(
return input_obj


def _realize_config_values_needed(input_obj: Config) -> bool:
def _realize_config_values_needed(input_obj: Config) -> None:
"""
Print a report characterizing input values as complete, empty, or template placeholders.
:param input_obj: The config to update.
:return: True
"""
complete, empty, template = input_obj.characterize_values(input_obj.data, parent="")
complete, template = input_obj.characterize_values(input_obj.data, parent="")
if complete:
log.info("Keys that are complete:")
for var in complete:
Expand All @@ -259,14 +258,6 @@ def _realize_config_values_needed(input_obj: Config) -> bool:
log.info(var)
else:
log.info("No keys have unrendered Jinja2 variables/expressions.")
log.info("")
if empty:
log.info("Keys that are set to empty:")
for var in empty:
log.info(var)
else:
log.info("No keys are set to empty.")
return True


def _validate_depth(
Expand Down Expand Up @@ -335,7 +326,7 @@ def _validate_format(other_fmt_desc: str, other_fmt: str, input_fmt: str) -> Non
:param update_format: Format of the update config.
:param output_file: Output config destination (None => write to ``stdout``).
:param output_format: Format of the output config.
:param output_block: Path through keys to the desired output block.
:param key_path: Path through keys to the desired output block.
:param values_needed: Report complete, missing, and template values.
:param total: Require rendering of all Jinja2 variables/expressions.
:param dry_run: Log output instead of writing to output.
Expand Down
1 change: 0 additions & 1 deletion src/uwtools/strings.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class STR:
model: str = "model"
mpas: str = "mpas"
mpasinit: str = "mpas_init"
outblock: str = "output_block"
outfile: str = "output_file"
outfmt: str = "output_format"
quiet: str = "quiet"
Expand Down
2 changes: 1 addition & 1 deletion src/uwtools/tests/api/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def test_realize():
"update_format": "fmt2",
"output_file": "path3",
"output_format": "fmt3",
"output_block": None,
"key_path": None,
"values_needed": True,
"total": True,
"dry_run": False,
Expand Down
5 changes: 2 additions & 3 deletions src/uwtools/tests/config/formats/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,8 @@ def test__load_paths(config, tmp_path):

def test_characterize_values(config):
values = {1: "", 2: None, 3: "{{ n }}", 4: {"a": 88}, 5: [{"b": 99}], 6: "string"}
complete, empty, template = config.characterize_values(values=values, parent="p")
assert complete == [" p4", " p4.a", " pb", " p5", " p6"]
assert empty == [" p1", " p2"]
complete, template = config.characterize_values(values=values, parent="p")
assert complete == [" p1", " p2", " p4", " p4.a", " pb", " p5", " p6"]
assert template == [" p3: {{ n }}"]


Expand Down
Loading

0 comments on commit 96785cd

Please sign in to comment.