Skip to content

Commit

Permalink
omnibus-2024-07-09 (#526)
Browse files Browse the repository at this point in the history
  • Loading branch information
maddenp-noaa authored Jul 12, 2024
1 parent 1835fe6 commit 7dd754d
Show file tree
Hide file tree
Showing 17 changed files with 130 additions and 153 deletions.
4 changes: 2 additions & 2 deletions docs/environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ name: readthedocs
channels:
- conda-forge
dependencies:
- sphinx_rtd_theme=1.3.0
- sphinxcontrib-bibtex=2.6.1
- sphinx_rtd_theme=2.0.*
- sphinxcontrib-bibtex=2.6.*
- tree
13 changes: 6 additions & 7 deletions docs/sections/contributor_guide/documentation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ The ``make docs`` command will build the docs under ``docs/build/html``, after w
file://<filesystem-path-to-your-clone>/docs/build/html/index.html
Re-run ``make docs`` and refresh your browser after making and saving changes. Note that some documentation content is dynamically generated: Timestamps shown in e.g. log messages are expected and are ok to commit.
After making and saving changes, re-run ``make docs`` and refresh your browser. Note that some documentation content is dynamically generated: Timestamps shown in e.g. log messages are expected and are ok to commit.

If, at some point, you remove and recreate the conda development environment underlying your development shell, you will need to rerun the ``source install-deps`` command in the new environment/shell. Until then, the installed doc packages will persist and support docs generation.
If, at some point, you remove and recreate the conda development environment underlying your development shell, you will need to re-run the ``source install-deps`` command in the new environment/shell. Until then, the installed doc packages will persist and support docs generation.

Viewing Online Documentation
----------------------------

Online documentation generation and hosting for ``uwtools`` is provided by :rtd:`Read the Docs<>`. The green *View Docs* button near the upper right of that page links to the official docs for the project. When viewing the documentation, the version selector at the bottom of the navigation column on the left can be used to switch between the latest development code (``main``), the latest released version (``stable``), and any previously released version.

Docs are also built and temporarily published when Pull Requests (PRs) targeting the ``main`` branch are opened. Visit the :rtd:`Builds page<builds>` to see recent builds, including those made for PRs. Click a PR-related build marked *Passed*, then the small *View docs* link (**not** the large green *View Docs* button) to see the docs built specifically for that PR. If your PR includes documentation updates, it may be helpful to include the URL of this build in your PR's description so that reviewers can see the rendered HTML docs and not just the modified ``.rst`` files. Note that if commits are pushed to the PR's source branch, Read the Docs will rebuild the PR docs. See the checks section near the bottom of a PR for current status, and for another link to the PR docs via the *Details* link.
Docs are also built and temporarily published when Pull Requests (PRs) targeting the ``main`` branch are opened. Visit the :rtd:`Builds page<builds>` to see recent builds, including those made for PRs. Click a PR-related build marked *Passed*, then the small *View docs* link (**not** the large green *View Docs* button) to see the docs built specifically for that PR. See the ``docs/readthedocs.org:uwtools`` item in the checks section near the bottom of the PR for current status of the PR docs build, and click the *Details* link to its right to preview the docs when they are available. Note that if commits are pushed to the PR's source branch, Read the Docs will rebuild the PR docs.

Documentation Guidelines
------------------------
Expand All @@ -37,14 +37,13 @@ Please follow these guidelines when contributing to the documentation:
* If the link-check portion of ``make docs`` reports that a URL is ``permanently`` redirected, update the link in the docs to use the new URL. Non-permanent redirects can be left as-is.
* Do not manually wrap lines in the ``.rst`` files. Insert newlines only as needed to achieve correctly formatted HTML, and let HTML wrap long lines and/or provide a scrollbar.
* Use one blank line between documentation elements (headers, paragraphs, code blocks, etc.) unless additional lines are necessary to achieve correctly formatted HTML.
* Remove all trailing whitespace.
* Remove all trailing whitespace, except where inserted by dynamic content generation -- don't fight the tooling.
* In general, avoid pronouns like "we" and "you". (Using "we" may be appropriate when synonymous with "The UW Team", "The UFS Community", etc., when the context is clear.) Prefer direct, factual statements about what the code does, requires, etc.
* Use the `Oxford Comma <https://en.wikipedia.org/wiki/Serial_comma>`_.
* The synopsis information printed by ``uw [mode [action]] --help`` is automatically wrapped and indented based on current terminal size. For visual consistency, please set your terminal width to 100 columns when running such commands to produce output to copy into the docs.
* Follow the :rst:`RST Sections<basics.html#sections>` guidelines, underlining section headings with = characters, subsections with - characters, and subsubsections with ^ characters. If a further level of refinement is needed, use " to underline paragraph headers.
* Follow the :rst:`RST Sections<basics.html#sections>` guidelines, underlining section headings with ``=`` characters, subsections with ``-`` characters, and subsubsections with ``^`` characters. If a further level of refinement is needed, indented and/or bulleted lists, as subsections marked with ``"`` are nearly indistinguishable from those marked with ``^``.
* In [[sub]sub]section titles, capitalize all "principal" words. In practice this usually means all words but articles (a, an, the), logicals (and, etc.), and prepositions (for, of, etc.). Always fully capitalize acronyms (e.g., YAML).
* Never capitalize proper names when their owners do not (e.g., write `"pandas" <https://pandas.pydata.org/>`_, not "Pandas", even at the start of a sentence) or when referring to a software artifact (e.g., write ``numpy`` when referring to the library, and "NumPy" when referring to the project).
* When referring to YAML constructs, `block` refers to an entry whose values is a nested collection of key/value pairs, while `entry` is a single key/value pair.
* When referring to YAML constructs, `block` refers to an entry whose value is a nested collection of key/value pairs, while `entry` refers to a single key/value pair.
* When using the ``.. code-block::`` directive, align the actual code with the word ``code``. Also, when ``.. code-block::`` directives appear in bulleted or numberd lists, align them with the text following the space to the right of the bullet/number. For example:

.. code-block:: text
Expand Down
6 changes: 3 additions & 3 deletions recipe/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@
"isort =5.13.*",
"jinja2 =3.1.*",
"jq =1.7.*",
"jsonschema =4.22.*",
"jsonschema =4.23.*",
"lxml =5.2.*",
"make >=3.8",
"mypy =1.10.*",
"pip",
"pylint =3.2.*",
"pytest =8.2.*",
"pytest-cov =5.0.*",
"pytest-xdist =3.5.*",
"pytest-xdist =3.6.*",
"python >=3.9,<3.13",
"pyyaml =6.0.*"
],
"run": [
"f90nml =1.4.*",
"iotaa =0.8.*",
"jinja2 =3.1.*",
"jsonschema =4.22.*",
"jsonschema =4.23.*",
"lxml =5.2.*",
"python >=3.9,<3.13",
"pyyaml =6.0.*"
Expand Down
4 changes: 2 additions & 2 deletions recipe/meta.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ requirements:
- f90nml 1.4.*
- iotaa 0.8.*
- jinja2 3.1.*
- jsonschema 4.22.*
- jsonschema 4.23.*
- lxml 5.2.*
- python >=3.9,<3.13
- pyyaml 6.0.*
Expand All @@ -31,6 +31,6 @@ test:
- pylint 3.2.*
- pytest 8.2.*
- pytest-cov 5.0.*
- pytest-xdist 3.5.*
- pytest-xdist 3.6.*
about:
license: LGPL
4 changes: 2 additions & 2 deletions src/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
"version": meta["version"],
}

# Define dependency packages for non-conda installs.
# Define dependency packages for non-devshell installs.

if not os.environ.get("CONDA_PREFIX"):
if not os.environ.get("CONDEV_SHELL"):
kwargs["install_requires"] = [
pkg.replace(" =", "==")
for pkg in meta["packages"]["run"]
Expand Down
4 changes: 2 additions & 2 deletions src/uwtools/api/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
_CLASSNAMES = [
"Assets",
"AssetsCycleBased",
"AssetsCycleAndLeadtimeBased",
"AssetsCycleLeadtimeBased",
"AssetsTimeInvariant",
"Driver",
"DriverCycleBased",
"DriverCycleAndLeadtimeBased",
"DriverCycleLeadtimeBased",
"DriverTimeInvariant",
]

Expand Down
8 changes: 3 additions & 5 deletions src/uwtools/config/formats/ini.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ def _dict_to_str(cls, cfg: dict) -> str:

config_check_depths_dump(config_obj=cfg, target_format=FORMAT.ini)
parser = configparser.ConfigParser()
sio = StringIO()
parser.read_dict(cfg)
parser.write(sio)
s = sio.getvalue().strip()
sio.close()
return s
with StringIO() as sio:
parser.write(sio)
return sio.getvalue().strip()

def _load(self, config_file: Optional[Path]) -> dict:
"""
Expand Down
8 changes: 3 additions & 5 deletions src/uwtools/config/formats/nml.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ def to_od(d):

config_check_depths_dump(config_obj=cfg, target_format=FORMAT.nml)
nml: Namelist = Namelist(to_od(cfg)) if not isinstance(cfg, Namelist) else cfg
sio = StringIO()
nml.write(sio, sort=False)
s = sio.getvalue()
sio.close()
return s.strip()
with StringIO() as sio:
nml.write(sio, sort=False)
return sio.getvalue().strip()

def _load(self, config_file: Optional[Path]) -> dict:
"""
Expand Down
116 changes: 43 additions & 73 deletions src/uwtools/drivers/driver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
An abstract class for component drivers.
Abstract classes for component drivers.
"""

import json
Expand All @@ -24,6 +24,8 @@
from uwtools.scheduler import JobScheduler
from uwtools.utils.processing import execute

# NB: Class docstrings are programmatically defined.


class Assets(ABC):
"""
Expand All @@ -38,15 +40,6 @@ def __init__(
dry_run: bool = False,
key_path: Optional[list[str]] = None,
) -> None:
"""
A component driver.
:param cycle: The cycle.
:param leadtime: The leadtime.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
"""
self._config = YAMLConfig(config=config)
self._config.dereference(
context={
Expand Down Expand Up @@ -226,19 +219,11 @@ def __init__(
dry_run: bool = False,
key_path: Optional[list[str]] = None,
):
"""
The driver.
:param cycle: The cycle.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
"""
super().__init__(cycle=cycle, config=config, dry_run=dry_run, key_path=key_path)
self._cycle = cycle


class AssetsCycleAndLeadtimeBased(Assets):
class AssetsCycleLeadtimeBased(Assets):
"""
An abstract class to provision assets for cycle-and-leadtime-based components.
"""
Expand All @@ -251,15 +236,6 @@ def __init__(
dry_run: bool = False,
key_path: Optional[list[str]] = None,
):
"""
The driver.
:param cycle: The cycle.
:param leadtime: The leadtime.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
"""
super().__init__(
cycle=cycle, leadtime=leadtime, config=config, dry_run=dry_run, key_path=key_path
)
Expand All @@ -278,13 +254,6 @@ def __init__(
dry_run: bool = False,
key_path: Optional[list[str]] = None,
):
"""
The driver.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
"""
super().__init__(config=config, dry_run=dry_run, key_path=key_path)


Expand All @@ -302,16 +271,6 @@ def __init__(
key_path: Optional[list[str]] = None,
batch: bool = False,
):
"""
The driver.
:param cycle: The cycle.
:param leadtime: The leadtime.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
:param batch: Run component via the batch system?
"""
super().__init__(
cycle=cycle, leadtime=leadtime, config=config, dry_run=dry_run, key_path=key_path
)
Expand Down Expand Up @@ -490,22 +449,13 @@ def __init__(
key_path: Optional[list[str]] = None,
batch: bool = False,
):
"""
The driver.
:param cycle: The cycle.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
:param batch: Run component via the batch system?
"""
super().__init__(
cycle=cycle, config=config, dry_run=dry_run, key_path=key_path, batch=batch
)
self._cycle = cycle


class DriverCycleAndLeadtimeBased(Driver):
class DriverCycleLeadtimeBased(Driver):
"""
An abstract class for standalone cycle-and-leadtime-based component drivers.
"""
Expand All @@ -519,16 +469,6 @@ def __init__(
key_path: Optional[list[str]] = None,
batch: bool = False,
):
"""
The driver.
:param cycle: The cycle.
:param leadtime: The leadtime.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
:param batch: Run component via the batch system?
"""
super().__init__(
cycle=cycle,
leadtime=leadtime,
Expand All @@ -553,15 +493,45 @@ def __init__(
key_path: Optional[list[str]] = None,
batch: bool = False,
):
"""
The driver.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
:param batch: Run component via the batch system?
"""
super().__init__(config=config, dry_run=dry_run, key_path=key_path, batch=batch)


DriverT = Union[type[Assets], type[Driver]]


def _add_docstring(class_: type, omit: Optional[list[str]] = None) -> None:
"""
Dynamically add docstring to a driver class.
:param class_: The class to add the docstring to.
:param omit: Parameters to omit from the docstring.
"""
base = """
The driver.
:param cycle: The cycle.
:param leadtime: The leadtime.
:param config: Path to config file (read stdin if missing or None).
:param dry_run: Run in dry-run mode?
:param key_path: Keys leading through the config to the driver's configuration block.
:param batch: Run component via the batch system?
"""
setattr(
class_,
"__doc__",
"\n".join(
line
for line in dedent(base).strip().split("\n")
if not any(line.startswith(f":param {o}:") for o in omit or [])
),
)


_add_docstring(Assets, omit=["batch"])
_add_docstring(AssetsCycleBased, omit=["batch", "leadtime"])
_add_docstring(AssetsCycleLeadtimeBased, omit=["batch"])
_add_docstring(AssetsTimeInvariant, omit=["batch", "cycle", "leadtime"])
_add_docstring(Driver)
_add_docstring(DriverCycleBased, omit=["leadtime"])
_add_docstring(DriverCycleLeadtimeBased)
_add_docstring(DriverTimeInvariant, omit=["cycle", "leadtime"])
4 changes: 2 additions & 2 deletions src/uwtools/drivers/upp.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
from iotaa import asset, task, tasks

from uwtools.config.formats.nml import NMLConfig
from uwtools.drivers.driver import DriverCycleAndLeadtimeBased
from uwtools.drivers.driver import DriverCycleLeadtimeBased
from uwtools.strings import STR
from uwtools.utils.tasks import file, filecopy, symlink


class UPP(DriverCycleAndLeadtimeBased):
class UPP(DriverCycleLeadtimeBased):
"""
A driver for UPP.
"""
Expand Down
9 changes: 5 additions & 4 deletions src/uwtools/tests/config/formats/test_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def test_yaml_constructor_error_not_dict_from_file(tmp_path):

def test_yaml_constructor_error_not_dict_from_stdin():
# Test that a useful exception is raised if the YAML stdin input is a non-dict value.
with patch.object(sys, "stdin", new=StringIO("a string")):
with StringIO("a string") as sio, patch.object(sys, "stdin", new=sio):
with raises(exceptions.UWConfigError) as e:
YAMLConfig()
assert "Parsed a str value from stdin, expected a dict" in str(e.value)
Expand Down Expand Up @@ -167,9 +167,10 @@ def test_yaml_stdin_plus_relpath_failure(caplog):
log.setLevel(logging.INFO)
_stdinproxy.cache_clear()
relpath = "../bar/baz.yaml"
with patch.object(sys, "stdin", new=StringIO(f"foo: {support.INCLUDE_TAG} [{relpath}]")):
with raises(UWConfigError) as e:
YAMLConfig()
with StringIO(f"foo: {support.INCLUDE_TAG} [{relpath}]") as sio:
with patch.object(sys, "stdin", new=sio):
with raises(UWConfigError) as e:
YAMLConfig()
msg = f"Reading from stdin, a relative path was encountered: {relpath}"
assert msg in str(e.value)
assert logged(caplog, msg)
Expand Down
Loading

0 comments on commit 7dd754d

Please sign in to comment.