Skip to content

Commit

Permalink
refactor: move resolve_exe to utils.flopy_io, various fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
wpbonelli committed Mar 3, 2023
1 parent f934db9 commit dfc6829
Show file tree
Hide file tree
Showing 15 changed files with 104 additions and 89 deletions.
13 changes: 8 additions & 5 deletions autotest/test_modflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,20 +814,23 @@ def test_bcs_check(function_tmpdir):
assert np.array_equal(chk.summary_array["j"], np.array([0, 1, 1, 1, 1]))


def test_path_arguments(function_tmpdir, module_tmpdir):
def test_path_params_and_props(function_tmpdir, module_tmpdir):
# properties should be set to string abspaths regardless of
# pathlib.Path or str arguments

mf = Modflow(
version="mf2005", model_ws=function_tmpdir, external_path=module_tmpdir
)
assert mf.model_ws == function_tmpdir
assert mf.external_path == module_tmpdir
assert mf.model_ws == str(function_tmpdir)
assert mf.external_path == str(module_tmpdir)

mf = Modflow(
version="mf2005",
model_ws=str(function_tmpdir),
external_path=str(module_tmpdir),
)
assert mf.model_ws == function_tmpdir
assert mf.external_path == module_tmpdir
assert mf.model_ws == str(function_tmpdir)
assert mf.external_path == str(module_tmpdir)


def test_properties_check(function_tmpdir):
Expand Down
14 changes: 7 additions & 7 deletions autotest/test_uzf.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,8 +643,7 @@ def test_uzf_negative_iuzfopt(function_tmpdir):

ml.write_input()
success, buff = ml.run_model()
if not success:
raise AssertionError("UZF model with -1 iuzfopt failed to run")
assert success, "UZF model with -1 iuzfopt failed to run"

ml2 = Modflow.load(
"uzf_neg.nam", version="mfnwt", model_ws=function_tmpdir
Expand All @@ -653,8 +652,9 @@ def test_uzf_negative_iuzfopt(function_tmpdir):
pet = ml2.uzf.pet.array
extpd = ml2.uzf.pet.array

if not np.max(pet) == np.min(pet) and np.max(pet) != 0.1:
raise AssertionError("Read error for iuzfopt less than 0")

if not np.max(extpd) == np.min(extpd) and np.max(extpd) != 0.2:
raise AssertionError("Read error for iuzfopt less than 0")
assert (
np.max(pet) == np.min(pet) and np.max(pet) != 0.1
), "Read error for iuzfopt less than 0"
assert (
np.max(extpd) == np.min(extpd) and np.max(extpd) != 0.2
), "Read error for iuzfopt less than 0"
4 changes: 2 additions & 2 deletions flopy/export/shapefile_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ def recarray2shp(
shpname: Union[str, os.PathLike] = "recarray.shp",
mg=None,
epsg=None,
prj: Union[str, os.PathLike] = None,
prj: Optional[Union[str, os.PathLike]] = None,
verbose=False,
**kwargs,
):
Expand All @@ -558,7 +558,7 @@ def recarray2shp(
Path for the output shapefile
epsg : int
EPSG code. See https://www.epsg-registry.org/ or spatialreference.org
prj : str or PathLike, default None
prj : str or PathLike, optional, default None
Existing projection file to be used with new shapefile.
verbose : bool
Whether to print verbose output
Expand Down
68 changes: 33 additions & 35 deletions flopy/mbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,37 @@
iprn = -1


def resolve_exe(exe_name: Union[str, os.PathLike]) -> str:
"""
Resolves the absolute path of the executable.
Parameters
----------
exe_name : str or PathLike
The executable's name or path. If only the name is provided,
the executable must be on the system path.
Returns
-------
str: absolute path to the executable
"""

exe_name = str(exe_name)
exe = which(exe_name)
if exe is None:
if exe_name.lower().endswith(".exe"):
# try removing .exe suffix
exe = which(exe_name[:-4])
if exe is None:
# try tilde-expanded abspath
exe = which(Path(exe_name).expanduser().absolute())
if exe is None:
raise FileNotFoundError(
f"The program {exe_name} does not exist or is not executable."
)
return exe


# external exceptions for users
class PackageLoadException(Exception):
"""
Expand Down Expand Up @@ -336,7 +367,7 @@ def __init__(
self._namefile = self.__name + "." + self.namefile_ext
self._packagelist = []
self.heading = ""
self.exe_name = resolve_exe(exe_name)
self.exe_name = resolve_exe(exe_name) if exe_name else "mf2005"
self._verbose = verbose
self.external_path = None
self.external_extension = "ref"
Expand Down Expand Up @@ -1364,7 +1395,7 @@ def run_model(
pause=False,
report=False,
normal_msg="normal termination",
):
) -> Tuple[bool, List[str]]:
"""
This method will run the model using subprocess.Popen.
Expand All @@ -1383,7 +1414,6 @@ def run_model(
Returns
-------
(success, buff)
success : boolean
buff : list of lines of stdout
Expand Down Expand Up @@ -1656,37 +1686,6 @@ def to_shapefile(
self.export(filename, package_names=package_names)


def resolve_exe(exe_name: Union[str, os.PathLike]) -> str:
"""
Resolves the absolute path of the executable.
Parameters
----------
exe_name : str or PathLike
The executable's name or path. If only the name is provided,
the executable must be on the system path.
Returns
-------
str: absolute path to the executable
"""

exe_name = str(exe_name)
exe = which(exe_name)
if exe is None:
if exe_name.lower().endswith(".exe"):
# try removing .exe suffix
exe = which(exe_name[:-4])
if exe is None:
# try tilde-expanded abspath
exe = which(Path(exe_name).expanduser().absolute())
if exe is None:
raise FileNotFoundError(
f"The program {exe_name} does not exist or is not executable."
)
return exe


def run_model(
exe_name: Union[str, os.PathLike],
namefile: Optional[str],
Expand Down Expand Up @@ -1734,7 +1733,6 @@ def run_model(
(Default is None)
Returns
-------
(success, buff)
success : boolean
buff : list of lines of stdout (empty if report is False)
Expand Down
11 changes: 5 additions & 6 deletions flopy/mf6/mfmodel.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import inspect
import os
import sys
from typing import Union

import numpy as np

Expand Down Expand Up @@ -691,9 +692,9 @@ def load_base(
model_nam_file="modflowtest.nam",
mtype="gwf",
version="mf6",
exe_name="mf6",
exe_name: Union[str, os.PathLike] = "mf6",
strict=True,
model_rel_path=".",
model_rel_path=os.curdir,
load_only=None,
):
"""
Expand All @@ -713,10 +714,8 @@ def load_base(
relative path to the model name file from model working folder
version : str
version of modflow
exe_name : str
model executable name
model_ws : str
model working folder relative to simulation working folder
exe_name : str or PathLike
model executable name or path
strict : bool
strict mode when loading files
model_rel_path : str
Expand Down
7 changes: 5 additions & 2 deletions flopy/mf6/modflow/mfgwf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# DO NOT MODIFY THIS FILE DIRECTLY. THIS FILE MUST BE CREATED BY
# mf6/utils/createpackages.py
# FILE created on January 27, 2023 18:36:16 UTC
import os
from typing import Union

from .. import mfmodel
from ..data.mfdatautil import ArrayTemplateGenerator, ListTemplateGenerator

Expand Down Expand Up @@ -119,9 +122,9 @@ def load(
modelname="NewModel",
model_nam_file="modflowtest.nam",
version="mf6",
exe_name="mf6",
exe_name: Union[str, os.PathLike] = "mf6",
strict=True,
model_rel_path=".",
model_rel_path=os.curdir,
load_only=None,
):
return mfmodel.MFModel.load_base(
Expand Down
12 changes: 6 additions & 6 deletions flopy/mfusg/mfusg.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ def __repr__(self):
@classmethod
def load(
cls,
f,
f: str,
version="mfusg",
exe_name="mfusg",
exe_name: Union[str, os.PathLike] = "mfusg",
verbose=False,
model_ws: Union[str, os.PathLike] = os.curdir,
load_only=None,
Expand All @@ -159,23 +159,23 @@ def load(
Parameters
----------
f : str or PathLike
Path to MODFLOW name file to load.
f : str
Name of MODFLOW name file to load.
version : str, default "mfusg"
MODFLOW version. Must be "mfusg".
exe_name : str, default "mfusg"
MODFLOW executable name.
verbose : bool, default False
Show messages that can be useful for debugging.
model_ws : str, default "."
model_ws : str or PathLike, default "."
Model workspace path. Default is the current directory.
load_only : list, str or None
List of case insensitive packages to load, e.g. ["bas6", "lpf"].
One package can also be specified, e.g. "rch". Default is None,
which attempts to load all files. An empty list [] will not load
any additional packages than is necessary. At a minimum, "dis" or
"disu" is always loaded.
forgive : bool, optional
forgive : bool, optional, default False
Option to raise exceptions on package load failure, which can be
useful for debugging. Default False.
check : boolean, optional
Expand Down
18 changes: 10 additions & 8 deletions flopy/modflow/mf.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ class Modflow(BaseModel):
version : str, default "mf2005"
MODFLOW version. Choose one of: "mf2k", "mf2005" (default),
"mfnwt", or "mfusg".
exe_name : str, default "mf2005"
The name of the executable to use.
exe_name : str or PathLike, default "mf2005"
The name or path of the executable to use.
structured : bool, default True
Specify if model grid is structured (default) or unstructured.
listunit : int, default 2
Expand Down Expand Up @@ -162,7 +162,9 @@ def __init__(
print(f"Note: external_path {external_path} already exists")
else:
os.makedirs(os.path.join(model_ws, external_path))
self.external_path = str(external_path)
self.external_path = str(external_path)
else:
self.external_path = None
self.verbose = verbose
self.mfpar = ModflowPar()

Expand Down Expand Up @@ -649,9 +651,9 @@ def load_results(self, **kwargs):
@classmethod
def load(
cls,
f: Union[str, os.PathLike],
f: str,
version="mf2005",
exe_name="mf2005",
exe_name: Union[str, os.PathLike] = "mf2005",
verbose=False,
model_ws: Union[str, os.PathLike] = os.curdir,
load_only=None,
Expand All @@ -663,14 +665,14 @@ def load(
Parameters
----------
f : str or PathLike
f : str
Path to MODFLOW name file to load.
version : str, default "mf2005"
MODFLOW version. Choose one of: "mf2k", "mf2005" (default),
or "mfnwt". Note that this can be modified on loading
packages unique to different MODFLOW versions.
exe_name : str, default "mf2005"
MODFLOW executable name.
exe_name : str or PathLike, default "mf2005"
MODFLOW executable name or path.
verbose : bool, default False
Show messages that can be useful for debugging.
model_ws : str or PathLike, default "."
Expand Down
9 changes: 8 additions & 1 deletion flopy/pakbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import abc
import os
import webbrowser as wb
from typing import Union

import numpy as np
from numpy.lib.recfunctions import stack_arrays
Expand Down Expand Up @@ -881,7 +882,13 @@ def write_file(self, f=None, check=False):
return

@staticmethod
def load(f, model, pak_type, ext_unit_dict=None, **kwargs):
def load(
f: Union[str, bytes, os.PathLike],
model,
pak_type,
ext_unit_dict=None,
**kwargs,
):
"""
Default load method for standard boundary packages.
Expand Down
13 changes: 7 additions & 6 deletions flopy/seawat/swt.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
from typing import Union

from ..discretization.modeltime import ModelTime
from ..discretization.structuredgrid import StructuredGrid
Expand Down Expand Up @@ -425,11 +426,11 @@ def write_name_file(self):
@classmethod
def load(
cls,
f,
f: str,
version="seawat",
exe_name="swtv4",
exe_name: Union[str, os.PathLike] = "swtv4",
verbose=False,
model_ws=".",
model_ws: Union[str, os.PathLike] = os.curdir,
load_only=None,
):
"""
Expand All @@ -438,15 +439,15 @@ def load(
Parameters
----------
f : str
Path to SEAWAT name file to load.
Name of SEAWAT name file to load.
version : str, default "seawat"
Version of SEAWAT to use. Valid versions are "seawat" (default).
exe_name : str, default "swtv4"
The name of the executable to use.
verbose : bool, default False
Print additional information to the screen.
model_ws : str, default "."
Model workspace. Directory name to create model data sets.
model_ws : str or PathLike, default "."
Model workspace. Directory to create model data sets.
Default is the present working directory.
load_only : list of str, optional
Packages to load (e.g. ["lpf", "adv"]). Default None
Expand Down
1 change: 0 additions & 1 deletion flopy/utils/binaryfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,6 @@ def _build_index(self):
self.recordarray = np.array(self.recordarray, dtype=self.header_dtype)
self.iposarray = np.array(self.iposarray)
self.nlay = np.max(self.recordarray["ilay"])
return

def get_databytes(self, header):
"""
Expand Down
Loading

0 comments on commit dfc6829

Please sign in to comment.