Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b4c6fc0
feat(dfns): specify and reimplement v2 dfn schema
wpbonelli May 6, 2026
dc06561
ruff
wpbonelli May 11, 2026
1e8d3f9
spelling
wpbonelli May 11, 2026
3228ecc
mypy + fixes
wpbonelli May 11, 2026
e6e52c8
revisions
wpbonelli May 13, 2026
05c55ad
clean v1/v1.1/v2 split
wpbonelli May 14, 2026
b4ccbb5
ruff
wpbonelli May 14, 2026
b0a72f4
ruff ruff
wpbonelli May 14, 2026
ebc5a1c
less is more
wpbonelli May 14, 2026
96f62b1
mypy
wpbonelli May 14, 2026
a8c7c9b
big cleanup
wpbonelli May 20, 2026
427b2f1
revert models/programs api changes
wpbonelli May 21, 2026
591d0f9
more fixes, fix tests
wpbonelli May 21, 2026
1c92ed8
fixes
wpbonelli May 22, 2026
6d0ec17
update spec
wpbonelli May 22, 2026
d9d72d3
fixes
wpbonelli May 22, 2026
c73d3e7
cleanup
wpbonelli May 22, 2026
ee01ed5
appease mypy, drop official release from dfns.toml (only nightly buil…
wpbonelli May 22, 2026
ff348cc
drop python 3.10
wpbonelli May 22, 2026
ab67123
ruff
wpbonelli May 22, 2026
715a765
fix test paths, fix uv venv path, add intro language to dfn spec
wpbonelli May 22, 2026
f10c7b0
tweak language
wpbonelli May 22, 2026
caea422
wip
wpbonelli May 22, 2026
911c77d
various fixes
wpbonelli May 22, 2026
efb0cd5
support yaml and json
wpbonelli May 22, 2026
1de7a20
fixes
wpbonelli May 22, 2026
84b7a8b
more fixes
wpbonelli May 22, 2026
916f605
shape fixes, etc
wpbonelli May 23, 2026
117bdf8
describe traditional vs advanced stress package maxbound conventions
wpbonelli May 23, 2026
8831580
schema.json
wpbonelli May 23, 2026
ad2b970
fix
wpbonelli May 23, 2026
435e779
tagged fix
wpbonelli May 23, 2026
ce59670
spec fixes
wpbonelli May 23, 2026
748e029
cleanup, better comments
wpbonelli May 23, 2026
3f69707
drop FieldBase.from_dict, add script to generate schema.json
wpbonelli May 23, 2026
b232735
export scalar types
wpbonelli May 23, 2026
77a6a7d
fix v1.1 mapper bugs
wpbonelli May 23, 2026
f1520c8
clean up unnecessary stuff
wpbonelli May 23, 2026
cb305cf
clean up
wpbonelli May 23, 2026
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
18 changes: 10 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ jobs:
steps:

- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: "**/pyproject.toml"

Expand All @@ -80,9 +80,10 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-22.04, macos-14, windows-2022 ]
python: [ "3.10", "3.11", "3.12", "3.13" ]
python: [ "3.11", "3.12", "3.13", "3.14" ]
env:
GCC_V: 11
UV_PROJECT_ENVIRONMENT: ${{ github.workspace }}/.venv
steps:

- name: Checkout repo
Expand All @@ -97,10 +98,11 @@ jobs:
path: modflow6

- name: Setup uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@v7
with:
cache-dependency-glob: "**/pyproject.toml"
python-version: ${{ matrix.python }}
working-directory: modflow-devtools

- name: Setup Fortran
if: runner.os != 'Windows'
Expand All @@ -124,16 +126,16 @@ jobs:
working-directory: modflow-devtools/autotest
env:
REPOS_PATH: ${{ github.workspace }}
DFNS_PATH: ${{ github.workspace }}/modflow6/doc/mf6io/mf6ivar/dfn
MODFLOW_DEVTOOLS_AUTO_SYNC: 0
TEST_DFN_PATH: ${{ github.workspace }}/modflow6/doc/mf6io/mf6ivar/dfn
# use --dist loadfile to so tests requiring pytest-virtualenv run on the same worker
run: uv run pytest -v -n auto --dist loadfile --durations 0 --ignore test_download.py --ignore test_models.py --ignore test_dfns_registry.py
run: uv run pytest -v -n auto --dist loadfile --durations 0 --ignore test_download.py --ignore test_models.py --ignore dfns/test_dfns_registry.py

- name: Run network-dependent tests
# only invoke the GH API on one OS and Python version
# to avoid rate limits (1000 rqs / hour / repository)
# https://docs.github.com/en/actions/learn-github-actions/usage-limits-billing-and-administration#usage-limits
if: runner.os == 'Linux' && matrix.python == '3.10'
if: runner.os == 'Linux' && matrix.python == '3.11'
working-directory: modflow-devtools/autotest
env:
REPOS_PATH: ${{ github.workspace }}
Expand All @@ -151,7 +153,7 @@ jobs:
TEST_PROGRAMS_REPO: MODFLOW-ORG/modflow6
TEST_PROGRAMS_REF: develop
TEST_PROGRAMS_SOURCE: modflow6
run: uv run pytest -v -n auto --dist loadgroup --durations 0 test_download.py test_models.py test_dfns_registry.py
run: uv run pytest -v -n auto --dist loadgroup --durations 0 test_download.py test_models.py dfns/test_dfns_registry.py

rtd:
name: Docs
Expand Down
2 changes: 1 addition & 1 deletion DEVELOPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This document provides guidance to set up a development environment and discusse

## Requirements

Python3.10+ is currently required. This project has historically aimed to support several recent versions of Python, loosely following [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html#implementation). In current and future development this window may narrow to follow [SPEC 0](https://scientific-python.org/specs/spec-0000/#support-window) instead.
Python3.11+. This project has historically aimed to support several recent versions of Python, loosely following [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html#implementation). In current and future development this window may narrow to follow [SPEC 0](https://scientific-python.org/specs/spec-0000/#support-window) instead.

## Installation

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Python development tools for MODFLOW 6 and related projects.

## Requirements

Python3.10+, dependency-free by default.
Python3.11+, dependency-free by default.

Two main dependency groups are available, oriented around specific use cases:

Expand Down
Empty file added autotest/dfn/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions autotest/dfn/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import pytest

from modflow_devtools.dfn import fetch_dfns

MF6_OWNER = "MODFLOW-ORG"
MF6_REPO = "modflow6"
MF6_REF = "develop"


@pytest.fixture(scope="module")
def dfn_dir(module_tmpdir):
pytest.importorskip("boltons")
path = module_tmpdir / "dfn"
path.mkdir()
fetch_dfns(MF6_OWNER, MF6_REPO, MF6_REF, path, verbose=True)
return path
23 changes: 23 additions & 0 deletions autotest/dfn/test_dfn.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from modflow_devtools.dfn import Dfn
from modflow_devtools.markers import requires_pkg


@requires_pkg("boltons")
def test_load_v1(dfn_dir):
common = {}
common_path = dfn_dir / "common.dfn"
if common_path.exists():
with common_path.open() as f:
common, _ = Dfn._load_v1_flat(f)
names = [p.stem for p in dfn_dir.glob("*.dfn") if p.stem not in ("common", "flopy")]
assert names
for name in names:
with (dfn_dir / f"{name}.dfn").open() as f:
dfn = Dfn.load(f, name=name, common=common)
assert any(dfn)


@requires_pkg("boltons")
def test_load_all(dfn_dir):
dfns = Dfn.load_all(dfn_dir)
assert any(dfns)
Empty file added autotest/dfns/__init__.py
Empty file.
34 changes: 34 additions & 0 deletions autotest/dfns/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import os
from pathlib import Path

import pytest

from modflow_devtools.dfns import fetch_dfns

PROJ_ROOT = Path(__file__).parents[1]

DFNS_REPO = os.getenv("TEST_DFNS_REPO", "MODFLOW-ORG/modflow6")
DFNS_REF = os.getenv("TEST_DFNS_REF", "develop")
DFNS_SOURCE = os.getenv("TEST_DFNS_SOURCE", "modflow6")
DFNS_VERSION = os.getenv("TEST_DFNS_VERSION", "6.6.0")


@pytest.fixture(scope="module")
def dfn_dir(module_tmpdir):
"""
Path to DFN files: $DFNS_PATH if set, otherwise fetched from develop branch
to a temp dir (for LocalDfnRegistry tests).
"""
env_var = "DFNS_PATH"
if dfns_path := os.getenv(env_var):
dfn_path = Path(dfns_path).expanduser().resolve()
assert dfn_path.exists(), f"{env_var}={dfns_path} does not exist"
assert any(dfn_path.glob("*.dfn")), f"{env_var}={dfns_path} empty"
return dfn_path

dfns_path = module_tmpdir / "dfns"
dfns_path.mkdir()
owner = DFNS_REPO.split("/")[0]
repo = DFNS_REPO.split("/")[1]
fetch_dfns(owner, repo, DFNS_REF, dfns_path, verbose=True)
return dfns_path
56 changes: 56 additions & 0 deletions autotest/dfns/test_dfns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from modflow_devtools.dfns import Dfns
from modflow_devtools.markers import requires_pkg


def test_load(dfn_dir):
spec = Dfns.load(dfn_dir)
assert spec.schema_version == "2"
assert spec.root is not None
assert spec.root.name == "sim-nam"
assert len(spec.components) > 100
assert "sim-nam" in spec.components
assert "gwf-nam" in spec.components
assert "gwf-chd" in spec.components
assert "gwf-wel" in spec.components.keys()
assert "garbage" not in spec.components

gwf_chd = spec.components["gwf-chd"]
assert gwf_chd.name == "gwf-chd"
assert gwf_chd.parent == "gwf-nam"

sim_children = spec.children("sim-nam")
assert "gwf-nam" in sim_children

gwf_children = spec.children("gwf-nam")
assert "gwf-chd" in gwf_children


def test_load_empty_directory(function_tmpdir):
spec = Dfns.load(function_tmpdir)
assert len(spec.components) == 0


# =============================================================================
# CLI
# =============================================================================


@requires_pkg("pydantic")
class TestCLI:
def test_main_help(self):
from modflow_devtools.dfns.__main__ import main

result = main([])
assert result == 0

def test_info_command(self):
from modflow_devtools.dfns.__main__ import main

result = main(["info"])
assert result == 0

def test_clean_command(self):
from modflow_devtools.dfns.__main__ import main

result = main(["clean"])
assert result == 0
Loading
Loading