Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(createpackages): use jinja for mf6 module code generation #2333

Open
wants to merge 73 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
7b5ceac
refactor(createpackages): use jinja for mf6 module code generation
wpbonelli Sep 20, 2024
cff9b2a
add templates to package-data, misc
wpbonelli Oct 10, 2024
2cbc3fc
shim fixes
wpbonelli Oct 10, 2024
6c952a3
cleanup
wpbonelli Oct 11, 2024
028ffc3
appease codacy
wpbonelli Oct 11, 2024
394092a
remove unneeded imports from context template
wpbonelli Oct 11, 2024
fc3997c
remove unneeded conditional from init template
wpbonelli Oct 11, 2024
1da40a5
cleanup
wpbonelli Oct 11, 2024
8f05049
fix codegen tests
wpbonelli Oct 11, 2024
2670545
fix job name in rtd.yml
wpbonelli Oct 11, 2024
675d8d6
import Union
wpbonelli Oct 11, 2024
5fffef5
cleanup
wpbonelli Oct 11, 2024
e840520
correction
wpbonelli Oct 11, 2024
80b54fc
shim fixes
wpbonelli Oct 11, 2024
1d6786e
hacky shim fix
wpbonelli Oct 11, 2024
fa24af3
ruff
wpbonelli Oct 11, 2024
2c545c2
restructuring, passing more tests
wpbonelli Oct 14, 2024
edcca13
ruff
wpbonelli Oct 15, 2024
b6644ac
cleanup
wpbonelli Oct 15, 2024
3ffbc5d
docstring fixes
wpbonelli Oct 15, 2024
e06ce4a
restore test_generate_classes.py
wpbonelli Oct 15, 2024
f459746
3.9 syntax?
wpbonelli Oct 15, 2024
baabcd8
cleanup
wpbonelli Oct 15, 2024
ff96c7f
cleanup
wpbonelli Oct 15, 2024
00a227f
docs/comments
wpbonelli Oct 15, 2024
3adedda
backcompat fix?
wpbonelli Oct 15, 2024
214823d
remove unused statement, fix mermaid diagrams in mf6_dev_guide, add b…
wpbonelli Oct 16, 2024
2d97e4f
bound boltons >= 1
wpbonelli Oct 16, 2024
128b0c2
hints
wpbonelli Oct 16, 2024
9526902
Moving code from shim to jinja
deltamarnix Oct 16, 2024
11338d2
move more from shim to jinja
wpbonelli Oct 27, 2024
277c2d7
codacy fixes
wpbonelli Oct 28, 2024
39867c5
boltons and jinja as dev dependencies, cleanup
wpbonelli Oct 29, 2024
d41de76
gen -> codegen dep group
wpbonelli Oct 29, 2024
18dd3d6
mention deps in generate_classes docs
wpbonelli Oct 29, 2024
6441ed6
handle missing jinja
wpbonelli Oct 29, 2024
05f24b9
fixes
wpbonelli Oct 29, 2024
10ea654
fixes after review
wpbonelli Oct 30, 2024
94a535d
docstring indentation fix
wpbonelli Oct 30, 2024
f9ddc23
formatting fixes
wpbonelli Oct 30, 2024
7148e88
fmt
wpbonelli Oct 30, 2024
5f2e2d9
install dev dep group in mf6.yml
wpbonelli Oct 31, 2024
e5b091b
remove description from context, just use name.description
wpbonelli Oct 31, 2024
4ef51f5
replace latex quotes in descriptions
wpbonelli Oct 31, 2024
fffed48
consolidate ref param replacement in shim, remove children, fix descr…
wpbonelli Oct 31, 2024
8063906
trim shim
wpbonelli Oct 31, 2024
216e8fe
add Dfn.load_all()
wpbonelli Oct 31, 2024
b83644c
dataclasses -> typeddicts
wpbonelli Oct 31, 2024
c668403
remove unneeded imports
wpbonelli Oct 31, 2024
3b3f194
add params macro
wpbonelli Oct 31, 2024
e003eac
initial toml support
wpbonelli Oct 31, 2024
2fa53f8
Revert "add params macro"
wpbonelli Oct 31, 2024
41dd1a5
fix renderable
wpbonelli Oct 31, 2024
2b2f507
support var type directly (as str for now)
wpbonelli Oct 31, 2024
ee8ff8c
revisions
wpbonelli Nov 4, 2024
0b7e3a0
ruff
wpbonelli Nov 4, 2024
3891f35
remove shim and renderable, much cleanup
wpbonelli Nov 5, 2024
d509e20
cleanup
wpbonelli Nov 5, 2024
a128cbe
update dev guide
wpbonelli Nov 5, 2024
3d20c74
file record squashing as a filter
wpbonelli Nov 5, 2024
9c6c009
prep for version support
wpbonelli Nov 5, 2024
dde9b6e
cleaner subpkg ref passing
wpbonelli Nov 5, 2024
3955ded
add new deps to environment.yml
wpbonelli Nov 6, 2024
bdac389
fix filein/fileout in toml conversion
wpbonelli Nov 7, 2024
623c8c3
switch dfn dataclass -> typeddict, owns-a (not is-a) var dict, cleare…
wpbonelli Nov 7, 2024
57def41
order
wpbonelli Nov 7, 2024
b2dbe5c
improve docstrings, misc cleanup
wpbonelli Nov 10, 2024
a47b772
improve dev guide
wpbonelli Nov 10, 2024
53188ca
revisions
wpbonelli Nov 13, 2024
d9f596b
whitespace mgmt
wpbonelli Nov 14, 2024
96fc8c5
better composite variable docstring format
wpbonelli Nov 14, 2024
3878326
rebase and ruff
wpbonelli Nov 14, 2024
32ff250
indentation
wpbonelli Nov 14, 2024
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
4 changes: 1 addition & 3 deletions autotest/test_codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
MF6_PATH = PROJ_ROOT / "flopy" / "mf6"
DFN_PATH = MF6_PATH / "data" / "dfn"
DFN_NAMES = [
dfn.stem
for dfn in DFN_PATH.glob("*.dfn")
if dfn.stem not in ["common", "flopy"]
dfn.stem for dfn in DFN_PATH.glob("*.dfn") if dfn.stem not in ["common", "flopy"]
]


Expand Down
12 changes: 8 additions & 4 deletions flopy/mf6/utils/codegen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ def _get_template_env():
# expect optional deps at module init time
jinja = import_optional_dependency("jinja2")
loader = jinja.PackageLoader("flopy", "mf6/utils/codegen/templates/")
env = jinja.Environment(loader=loader)
env = jinja.Environment(
loader=loader,
trim_blocks=True,
lstrip_blocks=True,
line_statement_prefix="_",
keep_trailing_newline=True,
)

from flopy.mf6.utils.codegen.filters import Filters

Expand Down Expand Up @@ -47,9 +53,7 @@ def make_init(dfns: dict, outdir: PathLike, verbose: bool = False):
from flopy.mf6.utils.codegen.context import Context

contexts = list(
chain(
*[[ctx for ctx in Context.from_dfn(dfn)] for dfn in dfns.values()]
)
chain.from_iterable(Context.from_dfn(dfn) for dfn in dfns.values())
)
target_name = "__init__.py"
target_path = outdir / target_name
Expand Down
4 changes: 2 additions & 2 deletions flopy/mf6/utils/codegen/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ def from_dfn(dfn: Dfn) -> List["Context.Name"]:
name: Name
vars: Vars

@classmethod
def from_dfn(cls, dfn: Dfn) -> Iterator["Context"]:
@staticmethod
def from_dfn(dfn: Dfn) -> Iterator["Context"]:
"""
Extract context class descriptor(s) from an input definition.
These are structured representations of input context classes.
Expand Down
2 changes: 1 addition & 1 deletion flopy/mf6/utils/codegen/dfn.py
wpbonelli marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ def _fields() -> Vars:
block=block,
children=None,
description=(
f"* Contains data for the {ref['abbr']} package. Data can be "
f"Contains data for the {ref['abbr']} package. Data can be "
f"stored in a dictionary containing data for the {ref['abbr']} "
"package with variable names as keys and package data as "
f"values. Data just for the {ref['val']} variable is also "
Expand Down
26 changes: 7 additions & 19 deletions flopy/mf6/utils/codegen/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ def parent(ctx, ctx_name) -> str:
or ctx_name.l in ["sim", "exg", "sln"]
):
return "simulation"
elif subpkg:
if ctx_name.l == "utl" and ctx_name.r == "hpc":
return "simulation"
return "package"
return "model"

@pass_context
Expand All @@ -101,13 +97,7 @@ def skip_init(ctx, ctx_name) -> List[str]:
"solutiongroup",
]
elif base == "MFModel":
skip = ["packages", "export_netcdf", "nc_filerecord"]
refs = ctx.get("foreign_keys", dict())
if any(refs) and ctx["name"] != (None, "nam"):
for k in refs.keys():
if ctx["vars"].get(k, None):
skip.append(k)
return skip
return ["packages", "export_netcdf", "nc_filerecord"]
else:
if ctx_name.r == "nam":
return ["export_netcdf", "nc_filerecord"]
Expand Down Expand Up @@ -156,17 +146,17 @@ def type(var: dict) -> str:
"""
Get a readable representation of the variable's type.
TODO: eventually replace this with a proper `type` in
the variable spec when we add type hints. For now try
to match the existing format, with a few tweaks; e.g.
distinguishing lists from records by square and round
brackets, respectively, and separating each choice in
a keystring by '|'.
the variable spec when we add type hints
"""
_type = var["type"]
shape = var.get("shape", None)
children = var.get("children", None)
if children:
if _type == "list":
if len(children) == 1:
first = list(children.values())[0]
if first["type"] in ["record", "union"]:
return f"[{Filters.Var.type(first)}]"
children = ", ".join(
[v["name"] for v in children.values()]
)
Expand Down Expand Up @@ -295,9 +285,7 @@ def _var(var: dict) -> List[str]:

attrs = list(filter(None, [_attr(v) for v in variables.values()]))

if base == "MFModel":
attrs.append(f"model_type = {name.l}")
elif base == "MFPackage":
if base == "MFPackage":
attrs.extend(
[
f"package_abbr = '{name.r}'"
Expand Down
10 changes: 5 additions & 5 deletions flopy/mf6/utils/codegen/templates/exchange.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ class Modflow{{ title }}(MFPackage):

Parameters
----------
{{ macros.vars_docs(vars, indent=4) }}
{{ macros.vars_docs(vars, indent=4) }}
"""

{% for attr in vars|attrs %}
{{ attr }}
{%- endfor %}
{% endfor %}

def __init__(
self,
Expand All @@ -27,7 +27,7 @@ class Modflow{{ title }}(MFPackage):
exgtype="{{ name.r[:3].upper() }}6-{{ name.r[3:].upper() }}6",
exgmnamea=None,
exgmnameb=None,
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
filename=None,
pname=None,
**kwargs,
Expand Down Expand Up @@ -64,7 +64,7 @@ class Modflow{{ title }}(MFPackage):
GWE Model with the name exgmnameb must correspond to the GWF Model
with the name gwfmodelname2.

{{ macros.vars_docs(vars, indent=8) }}
{{ macros.vars_docs(vars, indent=8) }}
"""

super().__init__(
Expand All @@ -83,6 +83,6 @@ class Modflow{{ title }}(MFPackage):

{% for statement in vars|init %}
{{ statement }}
{%- endfor %}
{% endfor %}

self._init_complete = True
34 changes: 19 additions & 15 deletions flopy/mf6/utils/codegen/templates/macros.jinja
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
{% macro init_vars(vars, alias=false, indent=0, skip=none) %}
{%- for name, var in vars.items() if name not in skip %}
{% set v = var|untag -%}
{% set n = (name if alias else v.name)|safe_name -%}
{{ ""|indent(indent, first=true) }}{{ n }}{%- if v.default is defined %}={{ v.default|value }}{%- endif -%},
{%- endfor %}
{% for name, var in vars.items() if name not in skip %}
{% set v = var|untag %}
{% set n = (name if alias else v.name)|safe_name %}
{{ ""|indent(indent, first=true) }}{{ n }}{% if v.default is defined %}={{ v.default|value }}{% endif %},
{% endfor %}
{% endmacro %}

{% macro vars_docs(vars, indent=0) %}
{%- for var in vars.values() recursive %}
{% set v = var|untag -%}
{% set n = v.name|safe_name|escape_trailing_underscore -%}
{% macro vars_docs(vars, indent=0, recurse=true) %}
{% for var in vars.values() recursive %}
{% set v = var|untag %}
{% set n = v.name|safe_name|escape_trailing_underscore %}
{{ ""|indent(indent, first=true) }}{% if loop.depth > 1 %}* {% endif %}{{ n }} : {{ v|type }}
{%- if v.description is defined and v.description is not none %}
{% if v.description is defined and v.description is not none %}
{{ v.description|wordwrap|indent(indent + (loop.depth * 4), first=true) }}
{%- endif %}
{%- if v.children is defined and v.children is not none -%}
{% endif %}
{% if recurse and v.children is defined and v.children is not none %}
{% if v.type == "list" and v.children|length == 1 and (v.children.values()|first).type == "record" %}
{{ loop((v.children.values()|first).children.values())|indent(indent, first=true) }}
{% else %}
{{ loop(v.children.values())|indent(indent, first=true) }}
{%- endif %}
{% endfor -%}
{% endmacro %}
{% endif %}
{% endif %}
{% endfor %}
{% endmacro %}
8 changes: 4 additions & 4 deletions flopy/mf6/utils/codegen/templates/model.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Modflow{{ title }}(MFModel):

Parameters
----------
{{ macros.vars_docs(vars, indent=4) }}
{{ macros.vars_docs(vars, indent=4) }}

Methods
-------
Expand All @@ -34,7 +34,7 @@ class Modflow{{ title }}(MFModel):
version="mf6",
exe_name="mf6",
model_rel_path=".",
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
**kwargs,
):
"""
Expand All @@ -61,7 +61,7 @@ class Modflow{{ title }}(MFModel):
Simulation that this model is a part of. Model is automatically
added to simulation when it is initialized.

{{ macros.vars_docs(vars, indent=8) }}
{{ macros.vars_docs(vars, indent=8) }}
"""

super().__init__(
Expand All @@ -77,7 +77,7 @@ class Modflow{{ title }}(MFModel):

{% for statement in vars|init %}
{{ statement }}
{%- endfor %}
{% endfor %}

@classmethod
def load(
Expand Down
22 changes: 11 additions & 11 deletions flopy/mf6/utils/codegen/templates/package.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ class Modflow{{ title }}(MFPackage):

Parameters
----------
{{ macros.vars_docs(vars, indent=4) }}
{{ macros.vars_docs(vars, indent=4) }}
"""

{% for attr in vars|attrs %}
{{ attr }}
{%- endfor %}
{% endfor %}

def __init__(
self,
{{ name|parent }},
loading_package=False,
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
wpbonelli marked this conversation as resolved.
Show resolved Hide resolved
filename=None,
pname=None,
**kwargs,
Expand All @@ -43,7 +43,7 @@ class Modflow{{ title }}(MFPackage):
Do not set this parameter. It is intended for debugging and internal
processing purposes only.

{{ macros.vars_docs(vars, indent=8) }}
{{ macros.vars_docs(vars, indent=8) }}

filename : str
File name for this package.
Expand All @@ -68,7 +68,7 @@ class Modflow{{ title }}(MFPackage):

{% for statement in vars|init %}
{{ statement }}
{%- endfor %}
{% endfor %}

self._init_complete = True

Expand All @@ -94,15 +94,15 @@ class {{ title }}Packages(MFChildPackages):

def initialize(
self,
{{ macros.init_vars(vars, alias=true, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, alias=true, indent=8, skip=name|skip_init) }}
filename=None,
pname=None,
):
new_package = Modflow{{ title }}(
self._cpparent,
{%- for n, var in vars.items() if n not in name|skip_init %}
{% for n, var in vars.items() if n not in name|skip_init %}
{{ n|safe_name }}={{ n|safe_name }},
{%- endfor %}
{% endfor %}
filename=filename,
pname=pname,
child_builder_call=True,
Expand All @@ -112,15 +112,15 @@ class {{ title }}Packages(MFChildPackages):
{% if name.r != "obs" %}
def append_package(
self,
{{ macros.init_vars(vars, alias=true, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, alias=true, indent=8, skip=name|skip_init) }}
filename=None,
pname=None,
):
new_package = Modflow{{ title }}(
self._cpparent,
{%- for n, var in vars.items() if n not in name|skip_init %}
{% for n, var in vars.items() if n not in name|skip_init %}
{{ n|safe_name }}={{ n|safe_name }},
{%- endfor %}
{% endfor %}
filename=filename,
pname=pname,
child_builder_call=True,
Expand Down
8 changes: 4 additions & 4 deletions flopy/mf6/utils/codegen/templates/simulation.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class MF{{ title }}(MFSimulationBase):

Parameters
----------
{{ macros.vars_docs(vars, indent=4) }}
{{ macros.vars_docs(vars, indent=4) }}

Methods
-------
Expand All @@ -35,7 +35,7 @@ class MF{{ title }}(MFSimulationBase):
write_headers: bool = True,
use_pandas: bool = True,
lazy_io: bool = False,
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
{{ macros.init_vars(vars, indent=8, skip=name|skip_init) }}
):
"""
{{ name|description }}
Expand Down Expand Up @@ -66,7 +66,7 @@ class MF{{ title }}(MFSimulationBase):
lazy_io
Whether to use lazy IO

{{ macros.vars_docs(vars, indent=8) }}
{{ macros.vars_docs(vars, indent=8) }}
"""

super().__init__(
Expand All @@ -82,7 +82,7 @@ class MF{{ title }}(MFSimulationBase):

{% for statement in vars|init %}
{{ statement }}
{%- endfor %}
{% endfor %}

@classmethod
def load(
Expand Down
Loading