Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
maddenp-noaa authored Feb 7, 2024
1 parent b7c65d8 commit bd64cb0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 42 deletions.
6 changes: 3 additions & 3 deletions docs/sections/user_guide/cli/mode_template.rst
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ The examples in this section use atparse-formatted template file ``atparse.txt``
.. code-block:: text
$ uw template translate --input-file atparse.txt
{{greeting}}, {{recipient}}!
{{ greeting }}, {{ recipient }}!
Shell redirection via ``|``, ``>``, et al. may also be used to stream output to a file, another process, etc.

Expand All @@ -287,11 +287,11 @@ The examples in this section use atparse-formatted template file ``atparse.txt``

.. code-block:: jinja
{{greeting}}, {{recipient}}!
{{ greeting }}, {{ recipient }}!
* With the ``--dry-run`` flag specified, nothing is written to ``stdout`` (or to a file if ``--output-file`` is specified), but a report of what would have been written is logged to ``stderr``:

.. code-block:: text
$ uw template translate --input-file atparse.txt --dry-run
[2024-01-03T16:41:13] INFO {{greeting}}, {{recipient}}!
[2024-02-06T21:53:43] INFO {{ greeting }}, {{ recipient }}!
19 changes: 6 additions & 13 deletions src/uwtools/config/atparse_to_jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"""

import re
from typing import IO, Any, Generator

from uwtools.logging import log
from uwtools.utils.file import OptionalPath, readable, writable
Expand All @@ -23,21 +22,15 @@ def convert(
:param dry_run: Run in dry-run mode?
"""

def lines() -> Generator[str, Any, Any]:
with readable(input_file) as f_in:
for line in f_in.read().strip().split("\n"):
yield _replace(line.strip())

def write(f_out: IO) -> None:
for line in lines():
print(_replace(line.strip()), file=f_out)

with readable(input_file) as f:
lines = f.readlines()
jinja2 = "".join(_replace(line) for line in lines)
if dry_run:
for line in lines():
for line in jinja2.removesuffix("\n").split("\n"):
log.info(line)
else:
with writable(output_file) as f:
write(f)
f.write(jinja2)


def _replace(atline: str) -> str:
Expand All @@ -54,5 +47,5 @@ def _replace(atline: str) -> str:
# Set maxsplits to 1 so only first ] is captured, which should be the
# bracket closing @[.
after_atparse = atline.split("@[", 1)[1].split("]", 1)[1]
atline = "".join([before_atparse, "{{", within_atparse, "}}", after_atparse])
atline = "".join([before_atparse, "{{ ", within_atparse, " }}", after_atparse])
return atline
87 changes: 61 additions & 26 deletions src/uwtools/tests/config/test_atparse_to_jinja2.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,83 +18,118 @@


@fixture
def atparselines():
return ["@[greeting] to the @[subject]", "@[flowers] are @[color]"]
def txt_atparse():
return """
@[greeting] to the @[subject]
@[flowers] are @[color]
""".strip()


@fixture
def atparsefile(atparselines, tmp_path):
path = tmp_path / "atparse.txt"
with open(path, "w", encoding="utf-8") as f:
for line in atparselines:
print(line, file=f)
return path
def txt_jinja2():
return """
{{ greeting }} to the {{ subject }}
{{ flowers }} are {{ color }}
""".strip()


@fixture
def jinja2txt():
return "{{greeting}} to the {{subject}}\n{{flowers}} are {{color}}\n"
def atparsefile(txt_atparse, tmp_path):
path = tmp_path / "atparse.txt"
with open(path, "w", encoding="utf-8") as f:
print(txt_atparse, file=f)
return path


# Test functions


def test_convert_input_file_to_output_file(atparsefile, capsys, jinja2txt, tmp_path):
def test_convert_input_file_to_output_file(atparsefile, capsys, txt_jinja2, tmp_path):
outfile = tmp_path / "outfile"
atparse_to_jinja2.convert(input_file=atparsefile, output_file=outfile)
with open(outfile, "r", encoding="utf-8") as f:
assert f.read() == jinja2txt
assert f.read().strip() == txt_jinja2
streams = capsys.readouterr()
assert not streams.err
assert not streams.out


def test_convert_input_file_to_logging(atparsefile, caplog, capsys, jinja2txt, tmp_path):
def test_convert_input_file_to_logging(atparsefile, caplog, capsys, txt_jinja2, tmp_path):
log.setLevel(logging.INFO)
outfile = tmp_path / "outfile"
atparse_to_jinja2.convert(input_file=atparsefile, dry_run=True)
streams = capsys.readouterr()
assert "\n".join(record.message for record in caplog.records) == jinja2txt.strip()
assert "\n".join(record.message for record in caplog.records).strip() == txt_jinja2
assert not streams.out
assert not outfile.is_file()


def test_convert_input_file_to_stdout(atparsefile, capsys, jinja2txt):
def test_convert_input_file_to_stdout(atparsefile, capsys, txt_jinja2):
atparse_to_jinja2.convert(input_file=atparsefile)
streams = capsys.readouterr()
assert not streams.err
assert streams.out == jinja2txt
assert streams.out.strip() == txt_jinja2


def test_convert_preserve_whitespace(tmp_path):
atparse = """
@[first_entry]
@[second_entry]
@[third_entry]
@[fourth_entry]
@[fifth_entry] @[sixth_entry]
"""
infile = tmp_path / "atparse"
with open(infile, "w", encoding="utf-8") as f:
f.write(atparse)
outfile = tmp_path / "jinja2"
atparse_to_jinja2.convert(input_file=infile, output_file=outfile)
expected = """
{{ first_entry }}
{{ second_entry }}
{{ third_entry }}
{{ fourth_entry }}
{{ fifth_entry }} {{ sixth_entry }}
"""
with open(outfile, "r", encoding="utf-8") as f:
assert f.read() == expected


def test_convert_stdin_to_file(atparselines, capsys, jinja2txt, tmp_path):
def test_convert_stdin_to_file(txt_atparse, capsys, txt_jinja2, tmp_path):
outfile = tmp_path / "outfile"
_stdinproxy.cache_clear()
with patch.object(sys, "stdin", new=StringIO("\n".join(atparselines))):
with patch.object(sys, "stdin", new=StringIO(txt_atparse)):
atparse_to_jinja2.convert(output_file=outfile)
with open(outfile, "r", encoding="utf-8") as f:
assert f.read() == jinja2txt
assert f.read().strip() == txt_jinja2
streams = capsys.readouterr()
assert not streams.err
assert not streams.out


def test_convert_stdin_to_logging(atparselines, caplog, jinja2txt, tmp_path):
def test_convert_stdin_to_logging(txt_atparse, caplog, txt_jinja2, tmp_path):
log.setLevel(logging.INFO)
outfile = tmp_path / "outfile"
_stdinproxy.cache_clear()
with patch.object(sys, "stdin", new=StringIO("\n".join(atparselines))):
with patch.object(sys, "stdin", new=StringIO(txt_atparse)):
atparse_to_jinja2.convert(output_file=outfile, dry_run=True)
assert "\n".join(record.message for record in caplog.records) == jinja2txt.strip()
assert "\n".join(record.message for record in caplog.records) == txt_jinja2
assert not outfile.is_file()


def test_convert_stdin_to_stdout(atparselines, capsys, jinja2txt):
def test_convert_stdin_to_stdout(txt_atparse, capsys, txt_jinja2):
_stdinproxy.cache_clear()
with patch.object(sys, "stdin", new=StringIO("\n".join(atparselines))):
with patch.object(sys, "stdin", new=StringIO(txt_atparse)):
atparse_to_jinja2.convert()
streams = capsys.readouterr()
assert not streams.err
assert streams.out == jinja2txt
assert streams.out.strip() == txt_jinja2


def test__replace():
Expand All @@ -103,4 +138,4 @@ def test__replace():
assert atparse_to_jinja2._replace(line_without) == line_without
# A line with atparse syntax should be returned updated to Jinja2 syntax:
line_with = "@[greeting] to the @[subject]"
assert atparse_to_jinja2._replace(line_with) == "{{greeting}} to the {{subject}}"
assert atparse_to_jinja2._replace(line_with) == "{{ greeting }} to the {{ subject }}"

0 comments on commit bd64cb0

Please sign in to comment.