Skip to content

Commit

Permalink
merge: merge pull request #87 from cryotools/fix-wrfxcspy-config-path
Browse files Browse the repository at this point in the history
fix: fix wrfxcspy default pathing

Fixes #86
  • Loading branch information
gampnico authored Nov 29, 2024
2 parents 15e5211 + 59a17f0 commit 20a80d4
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 11 deletions.
44 changes: 35 additions & 9 deletions cosipy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
"""

import argparse
import os
import pathlib
import sys
from importlib.metadata import entry_points

Expand All @@ -12,20 +14,44 @@
import tomli as tomllib # backwards compatibility


def get_cosipy_path_from_env(name: str = "COSIPY_DIR") -> pathlib.Path:
"""Get path to COSIPY directory.
When using WRFxCSPY, the coupler will default to searching for
config files in the current working directory, which may contain the
COSIPY source code. This function instead loads an environment
variable.
Args:
name: Name of environment variable pointing to the COSIPY
directory.
Returns:
Path to the COSIPY directory.
Raises:
NotADirectoryError: Invalid path.
"""
cosipy_path = pathlib.Path(os.environ.get(name, os.getcwd()))
if not cosipy_path.is_dir():
raise NotADirectoryError(f"Invalid path at: {cosipy_path}")

return cosipy_path


def set_parser() -> argparse.ArgumentParser:
"""Set argument parser for COSIPY."""
tagline = (
"Coupled snowpack and ice surface energy and mass balance model in Python."
)
tagline = "Coupled snowpack and ice surface energy and mass balance model in Python."
parser = argparse.ArgumentParser(prog="COSIPY", description=tagline)
cosipy_path = get_cosipy_path_from_env()

# Optional arguments
parser.add_argument(
"-c",
"--config",
default="./config.toml",
default=cosipy_path / "config.toml",
dest="config_path",
type=str,
type=pathlib.Path,
metavar="<path>",
required=False,
help="relative path to configuration file",
Expand All @@ -34,9 +60,9 @@ def set_parser() -> argparse.ArgumentParser:
parser.add_argument(
"-x",
"--constants",
default="./constants.toml",
default=cosipy_path / "constants.toml",
dest="constants_path",
type=str,
type=pathlib.Path,
metavar="<path>",
required=False,
help="relative path to constants file",
Expand All @@ -45,9 +71,9 @@ def set_parser() -> argparse.ArgumentParser:
parser.add_argument(
"-s",
"--slurm",
default="./slurm_config.toml",
default=cosipy_path / "slurm_config.toml",
dest="slurm_path",
type=str,
type=pathlib.Path,
metavar="<path>",
required=False,
help="relative path to Slurm configuration file",
Expand Down
9 changes: 9 additions & 0 deletions cosipy/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ def conftest_mock_check_file_exists():
mock_exists.return_value = True


@pytest.fixture(scope="function", autouse=False)
def conftest_mock_check_directory_exists():
"""Override checks when mocking directories."""

patcher = patch("pathlib.Path.is_dir")
mock_exists = patcher.start()
mock_exists.return_value = True


@pytest.fixture(scope="function", autouse=False)
def conftest_disable_jit():
# numba.config.DISABLE_JIT = True
Expand Down
55 changes: 55 additions & 0 deletions cosipy/tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import argparse
import os
import pathlib
from unittest.mock import patch

import pytest

import cosipy.config
from cosipy.config import Config
Expand All @@ -25,6 +30,56 @@ def test_set_parser(self):
for name in ["help", "config", "constants", "slurm"]:
assert name in actions

@pytest.mark.dependency(name="TestConfigParser::test_set_parser")
@pytest.mark.parametrize("arg_type", (str, pathlib.Path))
def test_user_arguments(self, arg_type):
test_parser = cosipy.config.set_parser()
test_path = "./some/path/config.toml"
assert isinstance(test_path, str)

test_args = [
"--config",
test_path,
"--constants",
test_path,
"--slurm",
test_path,
]
arguments, unknown = test_parser.parse_known_args(test_args)
assert isinstance(arguments, argparse.Namespace)

for user_path in [
arguments.config_path,
arguments.constants_path,
arguments.slurm_path,
]:
assert isinstance(user_path, pathlib.Path)
assert user_path == pathlib.Path(test_path)

@patch.dict(os.environ, {"COSIPY_DIR": "./path/to/wrong/cosipy/"})
def test_check_directory_exists(self):
"""Raise error if directory not found."""
wrong_path = "./path/to/wrong/cosipy/"
error_message = f"Invalid path at: {pathlib.Path(wrong_path)}"
with pytest.raises(NotADirectoryError, match=error_message):
cosipy.config.get_cosipy_path_from_env(name="COSIPY_DIR")

@pytest.mark.parametrize(
"arg_env", ((True, "COSIPY_DIR"), (True, "XFAIL"), (False, ""))
)
@patch.dict(os.environ, {"COSIPY_DIR": "./path/to/cosipy/"})
def test_get_cosipy_path(
self, arg_env, conftest_mock_check_directory_exists
):
_ = conftest_mock_check_directory_exists
test_name = arg_env[1]
compare_path = cosipy.config.get_cosipy_path_from_env(name=test_name)

if arg_env[1] == "COSIPY_DIR":
assert compare_path == pathlib.Path("./path/to/cosipy/")
else:
assert compare_path == pathlib.Path.cwd()


class TestConfig:
"""Test rtoml support."""
Expand Down
5 changes: 3 additions & 2 deletions cosipy/utilities/config_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"""

import argparse
import pathlib
import sys
from collections import namedtuple

Expand Down Expand Up @@ -73,9 +74,9 @@ def set_arg_parser(cls) -> argparse.ArgumentParser:
parser.add_argument(
"-u",
"--utilities",
default="./utilities_config.toml",
default=pathlib.Path("./utilities_config.toml"),
dest="utilities_path",
type=str,
type=pathlib.Path,
metavar="<path>",
required=False,
help="relative path to utilities' configuration file",
Expand Down

0 comments on commit 20a80d4

Please sign in to comment.