Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 2 additions & 6 deletions flopy4/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ def _resolve_release_id(release_id: str | None, verbose: bool = False) -> str:
or the latest release if no release_id is given.
"""
if release_id is not None:
if "@" not in release_id:
return f"MODFLOW-ORG/modflow6@{release_id}"
return release_id

# Try to read the version from a binary on PATH.
Expand Down Expand Up @@ -142,7 +144,6 @@ def _write_contract(outdir: Path, mf6_version: str) -> None:
outdir=_MF6_ROOT,
existing_only=not args.all_packages,
makedirs=args.all_packages,
fmt=not args.no_format,
)
_write_contract(_MF6_ROOT, effective_version)

Expand Down Expand Up @@ -211,11 +212,6 @@ def main() -> None:
help="Generate all packages, including ones not yet on disk. "
"By default sync only updates already-generated files.",
)
sync_p.add_argument(
"--no-format",
action="store_true",
help="Skip ruff formatting of generated files.",
)
sync_p.add_argument("--force", action="store_true", help="Force binary reinstallation.")
sync_p.add_argument("--verbose", action="store_true")
sync_p.set_defaults(func=_cmd_sync)
Expand Down
12 changes: 7 additions & 5 deletions flopy4/mf6/_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,15 @@ def check_mf6_compatibility(exe: str | None = None) -> None:
Path to an MF6 executable. If None, searches PATH for ``mf6``
or ``mf6.exe``. Does nothing if no binary is found.
"""
try:
from flopy4.mf6._contract import MF6_VERSION
except ImportError:
return
from flopy4.mf6._contract import MF6_VERSION

# Skip if version is unknown or a branch name rather than a semver tag.
if not MF6_VERSION or not MF6_VERSION[0].isdigit():
if not MF6_VERSION or MF6_VERSION == "unknown":
warnings.warn(
"flopy4.mf6 is synced to an unknown MF6 version. Run `flopy4 mf6 sync` to re-sync.",
UserWarning,
stacklevel=3,
)
return

if exe is None:
Expand Down
2 changes: 1 addition & 1 deletion flopy4/mf6/_contract.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# autogenerated file, do not modify
MF6_VERSION = "unknown"
MF6_VERSION = "develop"
DFN_SCHEMA_VERSION = "2.0.0.dev1"
8 changes: 0 additions & 8 deletions flopy4/mf6/utils/codegen/dfn2py.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ def make(
dfndir: str | PathLike,
outdir: str | PathLike = _MF6_ROOT,
developmode: bool = False,
fmt: bool = True,
makedirs: bool = False,
existing_only: bool = False,
):
Expand All @@ -57,7 +56,6 @@ def make(
dfns=dfns,
outdir=outdir,
developmode=developmode,
fmt=fmt,
skip=_SKIP,
makedirs=makedirs,
existing_only=existing_only,
Expand Down Expand Up @@ -93,11 +91,6 @@ def cli_main() -> None:
action="store_true",
help="Include developmode fields.",
)
parser.add_argument(
"--no-format",
action="store_true",
help="Skip ruff formatting.",
)
parser.add_argument(
"--makedirs",
action="store_true",
Expand All @@ -116,7 +109,6 @@ def cli_main() -> None:
dfndir=args.dfndir,
outdir=args.outdir,
developmode=args.developmode,
fmt=not args.no_format,
makedirs=args.makedirs,
existing_only=args.existing_only,
)
Expand Down
51 changes: 9 additions & 42 deletions flopy4/mf6/utils/codegen/make.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
Jinja templates stay thin and logic is easy to test and debug.
"""

import logging
import subprocess
import sys
from dataclasses import dataclass
from dataclasses import field as dc_field
from os import PathLike
Expand All @@ -28,11 +25,6 @@
replace_list_fields,
)

logger = logging.getLogger(__name__)

_RUFF_CONFIG = Path(__file__).parents[4] / "pyproject.toml"


# Pre-computed context dataclasses


Expand Down Expand Up @@ -912,39 +904,13 @@ def _get_env() -> jinja2.Environment:
)


# File generation


def _format(path: Path) -> None:
config = ["--config", str(_RUFF_CONFIG)] if _RUFF_CONFIG.exists() else []
subprocess.run(
[sys.executable, "-m", "ruff", "format", *config, str(path)],
check=True,
capture_output=True,
)
subprocess.run(
[sys.executable, "-m", "ruff", "check", "--fix", *config, str(path)],
check=True,
capture_output=True,
)


def make_module(
spec: ComponentSpec,
env: jinja2.Environment,
*,
fmt: bool = True,
) -> None:
def make_module(spec: ComponentSpec, env: jinja2.Environment, verbose: bool = False) -> None:
"""Generate a single component module."""
template = env.get_template(spec.template)
rendered = template.render(spec=spec)
spec.outpath.write_text(rendered, newline="\n")
logger.info(f"Wrote {spec.outpath}")
if fmt:
try:
_format(spec.outpath)
except subprocess.CalledProcessError as e:
logger.warning(f"Failed to format {spec.outpath}: {e.stderr.decode().strip()}")
if verbose:
print(f"Wrote {spec.outpath}")


def make_modules(
Expand All @@ -953,10 +919,10 @@ def make_modules(
dfndir: PathLike | None = None,
outdir: PathLike,
developmode: bool = False,
fmt: bool = True,
skip: set[str] | None = None,
makedirs: bool = False,
existing_only: bool = False,
verbose: bool = False,
) -> list[ComponentSpec]:
"""Generate Python modules for all components.

Expand All @@ -971,14 +937,14 @@ def make_modules(
Root output directory for generated Python files.
developmode :
If True, include developmode fields.
fmt :
If True, run ruff format/check on generated files.
skip :
Set of DFN names to skip.
makedirs :
If True, create output subdirectories as needed.
existing_only :
If True, only (re)generate files that already exist on disk.
verbose :
Whether to show verbose output

Returns
-------
Expand All @@ -998,10 +964,11 @@ def make_modules(
continue
spec = build_component_spec(dfn, root=outdir, developmode=developmode, v1_dfn=dfn)
if existing_only and not spec.outpath.exists():
logger.info(f"{spec.outpath} does not exist — skipping {name} (existing_only)")
if verbose:
print(f"{spec.outpath} does not exist — skipping {name} (existing_only)")
continue
if makedirs:
spec.outpath.parent.mkdir(parents=True, exist_ok=True)
make_module(spec, env, fmt=fmt)
make_module(spec, env)
specs.append(spec)
return specs
12 changes: 6 additions & 6 deletions test/test_mf6_codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ def test_simple_tier_generates_importable_files(dfn_path, tmp_path, all_dfns):
(tmp_path / "gwf").mkdir()

skip = {n for n in all_dfns if n not in SIMPLE_TIER}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, skip=skip)

generated = {s.dfn_name: s for s in specs}

Expand Down Expand Up @@ -638,7 +638,7 @@ def test_solution_tier_generates_importable_files(dfn_path, tmp_path, all_dfns):
from flopy4.mf6.solution import Solution

skip = {n for n in all_dfns if n not in SOLUTION_TIER}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, skip=skip)

generated = {s.dfn_name: s for s in specs}

Expand Down Expand Up @@ -697,7 +697,7 @@ def test_transport_tier_generates_importable_files(dfn_path, tmp_path, all_dfns)

target = {n for n in TRANSPORT_TIER if n in all_dfns}
skip = {n for n in all_dfns if n not in target}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, skip=skip)
generated = {s.dfn_name: s for s in specs}

from flopy4.mf6.package import Package
Expand All @@ -719,7 +719,7 @@ def test_oc_tier_generates_importable_files(dfn_path, tmp_path, all_dfns):

target = {n for n in OC_TIER if n in all_dfns}
skip = {n for n in all_dfns if n not in target}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, skip=skip)
generated = {s.dfn_name: s for s in specs}

from flopy4.mf6.package import Package
Expand All @@ -743,7 +743,7 @@ def test_utl_tier_generates_importable_files(dfn_path, tmp_path, all_dfns):

target = {n for n in UTL_TIER if n in all_dfns}
skip = {n for n in all_dfns if n not in target}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, makedirs=True, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, makedirs=True, skip=skip)
generated = {s.dfn_name: s for s in specs}

from flopy4.mf6.package import Package
Expand All @@ -764,7 +764,7 @@ def test_exg_tier_generates_importable_files(dfn_path, tmp_path, all_dfns):

target = {n for n in EXG_TIER if n in all_dfns}
skip = {n for n in all_dfns if n not in target}
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, fmt=False, makedirs=True, skip=skip)
specs = make_modules(dfndir=dfn_path, outdir=tmp_path, makedirs=True, skip=skip)
generated = {s.dfn_name: s for s in specs}

from flopy4.mf6.package import Package
Expand Down
Loading