From a2fddbc932e56d349b4c5420bd2fa0ba25196071 Mon Sep 17 00:00:00 2001 From: Bonelli Date: Tue, 3 Mar 2026 19:41:43 -0500 Subject: [PATCH 1/5] fix(dfn): restore old dfn2toml logic --- modflow_devtools/dfn2toml.py | 108 ++++--------------------- modflow_devtools/dfns/dfn2toml.py | 126 ++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 94 deletions(-) create mode 100644 modflow_devtools/dfns/dfn2toml.py diff --git a/modflow_devtools/dfn2toml.py b/modflow_devtools/dfn2toml.py index 7ec012d8..96a68661 100644 --- a/modflow_devtools/dfn2toml.py +++ b/modflow_devtools/dfn2toml.py @@ -1,126 +1,46 @@ """Convert DFNs to TOML.""" import argparse -import sys -import textwrap -from dataclasses import asdict from os import PathLike from pathlib import Path import tomli_w as tomli from boltons.iterutils import remap -from modflow_devtools.dfns import Dfn, is_valid, load, load_flat, map, to_flat, to_tree -from modflow_devtools.dfns.schema.block import block_sort_key -from modflow_devtools.misc import drop_none_or_empty +from modflow_devtools.dfn import Dfn # mypy: ignore-errors -def convert(inpath: PathLike, outdir: PathLike, schema_version: str = "2") -> None: - """ - Convert DFN files in `inpath` to TOML files in `outdir`. - By default, convert the definitions to schema version 2. - """ - inpath = Path(inpath).expanduser().absolute() +def convert(indir: PathLike, outdir: PathLike): + indir = Path(indir).expanduser().absolute() outdir = Path(outdir).expanduser().absolute() outdir.mkdir(exist_ok=True, parents=True) + for dfn in Dfn.load_all(indir).values(): + with Path.open(outdir / f"{dfn['name']}.toml", "wb") as f: - if inpath.is_file(): - if inpath.name == "common.dfn": - raise ValueError("Cannot convert common.dfn as a standalone file") + def drop_none_or_empty(path, key, value): + if value is None or value == "" or value == [] or value == {}: + return False + return True - common_path = inpath.parent / "common.dfn" - if common_path.exists(): - with common_path.open() as f: - from modflow_devtools.dfn import parse_dfn - - common, _ = parse_dfn(f) - else: - common = {} - - with inpath.open() as f: - dfn = load(f, name=inpath.stem, common=common, format="dfn") - - dfn = map(dfn, schema_version=schema_version) - _convert(dfn, outdir / f"{inpath.stem}.toml") - else: - dfns = { - name: map(dfn, schema_version=schema_version) for name, dfn in load_flat(inpath).items() - } - tree = to_tree(dfns) - flat = to_flat(tree) - for dfn_name, dfn in flat.items(): - _convert(dfn, outdir / f"{dfn_name}.toml") - - -def _convert(dfn: Dfn, outpath: Path) -> None: - with Path.open(outpath, "wb") as f: - # TODO if we start using c/attrs, swap out - # all this for a custom unstructuring hook - dfn_dict = asdict(dfn) - dfn_dict["schema_version"] = str(dfn_dict["schema_version"]) - if blocks := dfn_dict.pop("blocks", None): - for block_name, block_fields in blocks.items(): - if block_name not in dfn_dict: - dfn_dict[block_name] = {} - for field_name, field_data in block_fields.items(): - dfn_dict[block_name][field_name] = field_data - - tomli.dump( - dict( - sorted( - remap(dfn_dict, visit=drop_none_or_empty).items(), - key=block_sort_key, - ) - ), - f, - ) + tomli.dump(remap(dfn, visit=drop_none_or_empty), f) if __name__ == "__main__": - """ - Convert DFN files in the original format and schema version 1 - to TOML files, by default also converting to schema version 2. - """ + """Convert DFN files to TOML.""" - parser = argparse.ArgumentParser( - description="Convert DFN files to TOML.", - epilog=textwrap.dedent( - """\ -Convert DFN files in the original format and schema version 1 -to TOML files, by default also converting to schema version 2. -""" - ), - ) + parser = argparse.ArgumentParser(description="Convert DFN files to TOML.") parser.add_argument( "--indir", "-i", type=str, - help="Directory containing DFN files, or a single DFN file.", + help="Directory containing DFN files.", ) parser.add_argument( "--outdir", "-o", help="Output directory.", ) - parser.add_argument( - "--schema-version", - "-s", - type=str, - default="2", - help="Schema version to convert to.", - ) - parser.add_argument( - "--validate", - "-v", - action="store_true", - help="Validate DFN files without converting them.", - ) args = parser.parse_args() - - if args.validate: - if not is_valid(args.indir): - sys.exit(1) - else: - convert(args.indir, args.outdir, args.schema_version) + convert(args.indir, args.outdir) diff --git a/modflow_devtools/dfns/dfn2toml.py b/modflow_devtools/dfns/dfn2toml.py new file mode 100644 index 00000000..7ec012d8 --- /dev/null +++ b/modflow_devtools/dfns/dfn2toml.py @@ -0,0 +1,126 @@ +"""Convert DFNs to TOML.""" + +import argparse +import sys +import textwrap +from dataclasses import asdict +from os import PathLike +from pathlib import Path + +import tomli_w as tomli +from boltons.iterutils import remap + +from modflow_devtools.dfns import Dfn, is_valid, load, load_flat, map, to_flat, to_tree +from modflow_devtools.dfns.schema.block import block_sort_key +from modflow_devtools.misc import drop_none_or_empty + +# mypy: ignore-errors + + +def convert(inpath: PathLike, outdir: PathLike, schema_version: str = "2") -> None: + """ + Convert DFN files in `inpath` to TOML files in `outdir`. + By default, convert the definitions to schema version 2. + """ + inpath = Path(inpath).expanduser().absolute() + outdir = Path(outdir).expanduser().absolute() + outdir.mkdir(exist_ok=True, parents=True) + + if inpath.is_file(): + if inpath.name == "common.dfn": + raise ValueError("Cannot convert common.dfn as a standalone file") + + common_path = inpath.parent / "common.dfn" + if common_path.exists(): + with common_path.open() as f: + from modflow_devtools.dfn import parse_dfn + + common, _ = parse_dfn(f) + else: + common = {} + + with inpath.open() as f: + dfn = load(f, name=inpath.stem, common=common, format="dfn") + + dfn = map(dfn, schema_version=schema_version) + _convert(dfn, outdir / f"{inpath.stem}.toml") + else: + dfns = { + name: map(dfn, schema_version=schema_version) for name, dfn in load_flat(inpath).items() + } + tree = to_tree(dfns) + flat = to_flat(tree) + for dfn_name, dfn in flat.items(): + _convert(dfn, outdir / f"{dfn_name}.toml") + + +def _convert(dfn: Dfn, outpath: Path) -> None: + with Path.open(outpath, "wb") as f: + # TODO if we start using c/attrs, swap out + # all this for a custom unstructuring hook + dfn_dict = asdict(dfn) + dfn_dict["schema_version"] = str(dfn_dict["schema_version"]) + if blocks := dfn_dict.pop("blocks", None): + for block_name, block_fields in blocks.items(): + if block_name not in dfn_dict: + dfn_dict[block_name] = {} + for field_name, field_data in block_fields.items(): + dfn_dict[block_name][field_name] = field_data + + tomli.dump( + dict( + sorted( + remap(dfn_dict, visit=drop_none_or_empty).items(), + key=block_sort_key, + ) + ), + f, + ) + + +if __name__ == "__main__": + """ + Convert DFN files in the original format and schema version 1 + to TOML files, by default also converting to schema version 2. + """ + + parser = argparse.ArgumentParser( + description="Convert DFN files to TOML.", + epilog=textwrap.dedent( + """\ +Convert DFN files in the original format and schema version 1 +to TOML files, by default also converting to schema version 2. +""" + ), + ) + parser.add_argument( + "--indir", + "-i", + type=str, + help="Directory containing DFN files, or a single DFN file.", + ) + parser.add_argument( + "--outdir", + "-o", + help="Output directory.", + ) + parser.add_argument( + "--schema-version", + "-s", + type=str, + default="2", + help="Schema version to convert to.", + ) + parser.add_argument( + "--validate", + "-v", + action="store_true", + help="Validate DFN files without converting them.", + ) + args = parser.parse_args() + + if args.validate: + if not is_valid(args.indir): + sys.exit(1) + else: + convert(args.indir, args.outdir, args.schema_version) From 2780b5807fb789bb2f33b9920f99897816f1b982 Mon Sep 17 00:00:00 2001 From: Bonelli Date: Tue, 3 Mar 2026 19:50:00 -0500 Subject: [PATCH 2/5] fix import --- autotest/test_dfns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autotest/test_dfns.py b/autotest/test_dfns.py index 52b02170..92571969 100644 --- a/autotest/test_dfns.py +++ b/autotest/test_dfns.py @@ -4,7 +4,7 @@ import pytest from packaging.version import Version -from modflow_devtools.dfn2toml import convert, is_valid +from modflow_devtools.dfns.dfn2toml import convert, is_valid from modflow_devtools.dfns import Dfn, _load_common, load, load_flat from modflow_devtools.dfns.fetch import fetch_dfns from modflow_devtools.dfns.schema.v1 import FieldV1 From 75b82f7821ec7d0c0d8a36fb6a6595e6bf1096ec Mon Sep 17 00:00:00 2001 From: Bonelli Date: Tue, 3 Mar 2026 19:50:48 -0500 Subject: [PATCH 3/5] ruff --- autotest/test_dfns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autotest/test_dfns.py b/autotest/test_dfns.py index 92571969..d4f6eff4 100644 --- a/autotest/test_dfns.py +++ b/autotest/test_dfns.py @@ -4,8 +4,8 @@ import pytest from packaging.version import Version -from modflow_devtools.dfns.dfn2toml import convert, is_valid from modflow_devtools.dfns import Dfn, _load_common, load, load_flat +from modflow_devtools.dfns.dfn2toml import convert, is_valid from modflow_devtools.dfns.fetch import fetch_dfns from modflow_devtools.dfns.schema.v1 import FieldV1 from modflow_devtools.dfns.schema.v2 import FieldV2 From 8c8fed3123399eafaff99dbe97f3de64ee2934c9 Mon Sep 17 00:00:00 2001 From: Bonelli Date: Wed, 4 Mar 2026 06:54:44 -0500 Subject: [PATCH 4/5] import fix --- modflow_devtools/dfns/dfn2toml.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modflow_devtools/dfns/dfn2toml.py b/modflow_devtools/dfns/dfn2toml.py index 7ec012d8..33760280 100644 --- a/modflow_devtools/dfns/dfn2toml.py +++ b/modflow_devtools/dfns/dfn2toml.py @@ -11,6 +11,7 @@ from boltons.iterutils import remap from modflow_devtools.dfns import Dfn, is_valid, load, load_flat, map, to_flat, to_tree +from modflow_devtools.dfns.parse import parse_dfn from modflow_devtools.dfns.schema.block import block_sort_key from modflow_devtools.misc import drop_none_or_empty @@ -33,8 +34,6 @@ def convert(inpath: PathLike, outdir: PathLike, schema_version: str = "2") -> No common_path = inpath.parent / "common.dfn" if common_path.exists(): with common_path.open() as f: - from modflow_devtools.dfn import parse_dfn - common, _ = parse_dfn(f) else: common = {} From 2e7fdb234de9dfab9d247792b7ab38e44d4616cc Mon Sep 17 00:00:00 2001 From: Bonelli Date: Wed, 4 Mar 2026 07:11:48 -0500 Subject: [PATCH 5/5] fix tempdir --- autotest/test_dfns.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autotest/test_dfns.py b/autotest/test_dfns.py index d4f6eff4..ab5c281a 100644 --- a/autotest/test_dfns.py +++ b/autotest/test_dfns.py @@ -12,7 +12,7 @@ from modflow_devtools.markers import requires_pkg PROJ_ROOT = Path(__file__).parents[1] -DFN_DIR = PROJ_ROOT / "autotest" / "temp" / "dfn" +DFN_DIR = PROJ_ROOT / "autotest" / "temp" / "dfns" TOML_DIR = DFN_DIR / "toml" SPEC_DIRS = {1: DFN_DIR, 2: TOML_DIR} MF6_OWNER = "MODFLOW-ORG"