modflowpy / flopy

A Python package to create, run, and post-process MODFLOW-based models.
https://flopy.readthedocs.io
Other
521 stars 314 forks source link

feature: Adding Python type hints for input specifications #2298

Open dannbuckley opened 2 months ago

dannbuckley commented 2 months ago

Is your feature request related to a problem? Please describe. The documentation for the "type recarray" entries in the dfn specifications is sometimes hard to understand. These parameters might be a little easier to understand if there were type annotations in the __init__ definitions. This is sort of already done in the package docstring, but the docstring is written in MODFLOW descriptive types.

Describe the solution you'd like Add an annotation line to the dfn specification to store Python type information, and modify the createpackages.py utility to add Python type annotations to the package __init__ definition.

Example dfn change (sim-tdis.dfn):

block perioddata
name perioddata
type recarray perlen nstp tsmult
+ annotation = tuple[tuple[float, int, float], ...]
reader urword
optional false
longname stress period time information
description
default_value ((1.0, 1, 1.0),)

Example __init__ change after updating packages: (mftdis.py):

def __init__(
    self,
    simulation,
    ...,
-   perioddata=((1.0, 1, 1.0),),
+   perioddata: tuple[tuple[float, int, float], ...] = ((1.0, 1, 1.0),),
    ...,
):
    ...

Additional context Some examples:

wpbonelli commented 2 months ago

@dannbuckley

Thanks for this. Agreed that the mapping between the MF6 input spec and the Python/FloPy equivalent is not always clear. Your timing is excellent, we have just begun to think on this for the next major version.

Embedding Python type annotations in the DFN would be one approach, but I think we want to avoid coupling MF6 or any other program's input specification to Python. It's not MF6's concern how flopy represents input parameters, nor is it flopy's concern how MF6 does so — notwithstanding the fact that users must currently concern themselves with such, since flopy reproduces a lot of MF6 implementation details. But IMO we want to get away from that.

We could aim instead for a pythonic specification with a sound type-theoretic basis, which is translated under the hood into a form suitable for MF6 or whatever program FloPy is driving. I think there are a few parts to this, which could form the foundation of a generic plugin framework anyone could implement to bind flopy to a model code:

This would also allow consistent APIs for MF6 and older MODFLOW programs, which is a major friction point as it stands.

dannbuckley commented 2 months ago

@wpbonelli

I'll throw a couple of other options out here too. The dataclasses module was added to the standard library in 3.7. I think it was meant as a replacement for named tuples, but is still somewhat limited. There's also attrs, which I think has better support for inheritance/subclassing.

wpbonelli commented 2 months ago

@dannbuckley we are working on an attrs-based prototype right this moment, in fact!

wpbonelli commented 2 months ago

do you mind editing the issue title? maybe "type hints for input specifications" or something reflecting the more general utility of typing annotations

wpbonelli commented 1 month ago

@dannbuckley I had an initial look at how we might generate named tuples alongside the components they appear in and substitute them into docstrings and typehints, I think your suggestion to add type hints is achievable in the near term (pre v4). More to come soon