From ab72ccd919cc3a698df3ea0c3a3c0a18e578e3bf Mon Sep 17 00:00:00 2001 From: Tim Mitchell Date: Tue, 19 Oct 2021 13:35:41 +1300 Subject: [PATCH 1/2] refactor(mf6): Make flopy buildable with pyinstaller Use __init_subclass__ to register packages, removing dependency on dfn files when installed. Rename longnames.json and unitsformat.json to .py so they are automatically included. --- MANIFEST.in | 2 - autotest/t600_pyinstaller_test.py | 26 +++++++++ flopy/export/longnames.json | 78 ------------------------- flopy/export/longnames.py | 85 ++++++++++++++++++++++++++++ flopy/export/netcdf.py | 17 ++---- flopy/export/unitsformat.json | 74 ------------------------ flopy/export/unitsformat.py | 76 +++++++++++++++++++++++++ flopy/export/utils.py | 11 +--- flopy/mf6/data/mfstructure.py | 2 +- flopy/mf6/mfbase.py | 94 +++++++++---------------------- flopy/mf6/mfmodel.py | 6 ++ flopy/mf6/mfpackage.py | 12 ++++ 12 files changed, 242 insertions(+), 241 deletions(-) create mode 100644 autotest/t600_pyinstaller_test.py delete mode 100644 flopy/export/longnames.json create mode 100644 flopy/export/longnames.py delete mode 100644 flopy/export/unitsformat.json create mode 100644 flopy/export/unitsformat.py diff --git a/MANIFEST.in b/MANIFEST.in index 458446c077..cb0ebf7e40 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,2 @@ -include flopy/export/longnames.json -include flopy/export/unitsformat.json include flopy/mf6/data/dfn/*.dfn include flopy/plot/mplstyle/*.mplstyle \ No newline at end of file diff --git a/autotest/t600_pyinstaller_test.py b/autotest/t600_pyinstaller_test.py new file mode 100644 index 0000000000..2630051dc9 --- /dev/null +++ b/autotest/t600_pyinstaller_test.py @@ -0,0 +1,26 @@ +import os +import pathlib + +import flopy + +root_folder = pathlib.Path(__file__).parent.parent +flopy_folder = pathlib.Path(flopy.__file__).parent +dfn_path = flopy_folder / "mf6" / "data" / "dfn" +rename_path = flopy_folder / "mf6" / "data" / "no-dfn" + + +def test_flopy_runs_without_dfn_folder(): + """ Test to ensure that flopy can load a modflow 6 simulation without dfn files being present. """ + exists = dfn_path.exists() + if exists: + if rename_path.exists(): + os.rmdir(rename_path) + os.rename(dfn_path, rename_path) + try: + # run built executable + sim_path = root_folder / 'examples' / 'data' / 'mf6' / 'test006_gwf3' + + flopy.mf6.MFSimulation.load(sim_ws=str(sim_path)) + finally: + if exists and rename_path.exists(): + os.rename(rename_path, dfn_path) diff --git a/flopy/export/longnames.json b/flopy/export/longnames.json deleted file mode 100644 index ac0f596f37..0000000000 --- a/flopy/export/longnames.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "botm": "Model layer bottom elevations", - "crs": "Coordinate reference system", - "delc": "Model grid cell spacing along a column", - "delr": "Model grid cell spacing along a row", - "drn_cond": "Drain package conductance", - "drn_elev": "Drain package elevation", - "elevation": "Elevation", - "ghb_bhead": "General head boundary package head", - "ghb_cond": "General head boundary package conductance", - "hani": "Horizontal hydraulic conductivity anisotropy", - "hk": "Horizontal hydraulic conductivity", - "ibound": "Flow model active area array", - "icbund": "Transport model active array", - "latitude": "Latitude", - "layer": "Model layer", - "longitude": "Longitude", - "mnw2_B": "MultiNode well package B coefficient", - "mnw2_C": "MultiNode well package C coefficient", - "mnw2_P": "MultiNode well package P coefficient", - "mnw2_capmult": "MultiNode well package head capacity relation multiplier", - "mnw2_cprime": "MultiNode well package injected fluid concentration", - "mnw2_cwc": "MultiNode well package cell to well conductance", - "mnw2_hlift": "MultiNode well package reference head for well discharge point", - "mnw2_hlim": "MultiNode well package limiting head for well", - "mnw2_hwtol": "MultiNode well package water level solution tolerance", - "mnw2_kskin": "MultiNode well package well skin hydraulic conductivity", - "mnw2_liftn": "MultiNode well package known value of lift at discharge n", - "mnw2_liftq0": "MultiNode well package maximum lift of pump", - "mnw2_liftqmax": "MultiNode well package lift at maximum pumping rate", - "mnw2_pp": "MultiNode well package fraction of partial penetration", - "mnw2_ppflag": "MultiNode well package partial penetration adjustment flag", - "mnw2_pumpcap": "MultiNode well package pump lift adjustment flag", - "mnw2_pumpcol": "MultiNode well package pump intake column", - "mnw2_pumplay": "MultiNode well package pump intake layer", - "mnw2_pumploc": "MultiNode well package pump location flag", - "mnw2_pumprow": "MultiNode well package pump intake row", - "mnw2_qcut": "MultiNode well package pump limits flag", - "mnw2_qdes": "MultiNode well package desired volumetric pumping rate", - "mnw2_qfrcmn": "MultiNode well package minimum fraction of original pumping rate for well to remain active", - "mnw2_qfrcmx": "MultiNode well package minimum fraction of original pumping rate for well to reactivate", - "mnw2_qlimit": "MultiNode well package pumping constraint flag", - "mnw2_qn": "MultiNode well package known value of discharge n", - "mnw2_rskin": "MultiNode well package radius of well skin outer edge", - "mnw2_rw": "MultiNode well package radius of well", - "mnw2_zbotm": "MultiNode well package botm of well open interval", - "mnw2_zpump": "MultiNode well package pump elevation", - "mnw2_ztop": "MultiNode well package top of open interval", - "model_top": "Model top", - "prsity": "Porosity", - "rech": "Simulated groundwater recharge rates", - "riv_cond": "River package bed conductance", - "riv_rbot": "River package bottom elevation", - "riv_stage": "River package stage", - "sconc1": "Starting concentration", - "sfr_eps": "Streamflow Routing Package Brooks Corey exponent", - "sfr_ireach": "Streamflow Routing Package reach number", - "sfr_iseg": "Streamflow Routing Package segment number", - "sfr_j": "Streamflow Routing Package reach column", - "sfr_outreach": "Streamflow Routing Package downstream reach", - "sfr_rchlen": "Streamflow Routing Package reach length", - "sfr_reachID": "Streamflow Routing Package reach ID", - "sfr_slope": "Streamflow Routing Package streambed slope", - "sfr_strhc1": "Streamflow Routing Package streambed hydraulic conductivity", - "sfr_strthick": "Streamflow Routing Package streambed thickness", - "sfr_strtop": "Streamflow Routing Package streambed top", - "sfr_thti": "Streamflow Routing Package unsaturated zone initial volumetric water content", - "sfr_thts": "Streamflow Routing Package unsaturated zone saturated volumetric water content", - "sfr_uhc": "Streamflow Routing Package unsaturated zone saturated vertical hydraulic conductivity", - "ss": "Specific storage", - "strt": "Starting heads", - "sy": "Specific yield", - "thickness": "Layer thickness", - "time": "time", - "vka": "Vertical hydraulic conductivity or vertical anisotropy", - "vkcb": "Vertical hydraulic conductivity of quasi3d confining bed", - "wel_flux": "Well package flux" -} \ No newline at end of file diff --git a/flopy/export/longnames.py b/flopy/export/longnames.py new file mode 100644 index 0000000000..fe4df3fa72 --- /dev/null +++ b/flopy/export/longnames.py @@ -0,0 +1,85 @@ +""" Human readable long names for netCDF variables. """ + +NC_LONG_NAMES = { + "botm": "Model layer bottom elevations", + "crs": "Coordinate reference system", + "delc": "Model grid cell spacing along a column", + "delr": "Model grid cell spacing along a row", + "drn_cond": "Drain package conductance", + "drn_elev": "Drain package elevation", + "elevation": "Elevation", + "ghb_bhead": "General head boundary package head", + "ghb_cond": "General head boundary package conductance", + "hani": "Horizontal hydraulic conductivity anisotropy", + "hk": "Horizontal hydraulic conductivity", + "ibound": "Flow model active area array", + "icbund": "Transport model active array", + "latitude": "Latitude", + "layer": "Model layer", + "longitude": "Longitude", + "mnw2_B": "MultiNode well package B coefficient", + "mnw2_C": "MultiNode well package C coefficient", + "mnw2_P": "MultiNode well package P coefficient", + "mnw2_capmult": "MultiNode well package head capacity relation multiplier", + "mnw2_cprime": "MultiNode well package injected fluid concentration", + "mnw2_cwc": "MultiNode well package cell to well conductance", + "mnw2_hlift": "MultiNode well package reference head for well discharge point", + "mnw2_hlim": "MultiNode well package limiting head for well", + "mnw2_hwtol": "MultiNode well package water level solution tolerance", + "mnw2_kskin": "MultiNode well package well skin hydraulic conductivity", + "mnw2_liftn": "MultiNode well package known value of lift at discharge n", + "mnw2_liftq0": "MultiNode well package maximum lift of pump", + "mnw2_liftqmax": "MultiNode well package lift at maximum pumping rate", + "mnw2_pp": "MultiNode well package fraction of partial penetration", + "mnw2_ppflag": "MultiNode well package partial penetration adjustment flag", + "mnw2_pumpcap": "MultiNode well package pump lift adjustment flag", + "mnw2_pumpcol": "MultiNode well package pump intake column", + "mnw2_pumplay": "MultiNode well package pump intake layer", + "mnw2_pumploc": "MultiNode well package pump location flag", + "mnw2_pumprow": "MultiNode well package pump intake row", + "mnw2_qcut": "MultiNode well package pump limits flag", + "mnw2_qdes": "MultiNode well package desired volumetric pumping rate", + "mnw2_qfrcmn": "MultiNode well package minimum fraction of " + "original pumping rate for well to remain active", + "mnw2_qfrcmx": "MultiNode well package minimum fraction of " + "original pumping rate for well to reactivate", + "mnw2_qlimit": "MultiNode well package pumping constraint flag", + "mnw2_qn": "MultiNode well package known value of discharge n", + "mnw2_rskin": "MultiNode well package radius of well skin outer edge", + "mnw2_rw": "MultiNode well package radius of well", + "mnw2_zbotm": "MultiNode well package botm of well open interval", + "mnw2_zpump": "MultiNode well package pump elevation", + "mnw2_ztop": "MultiNode well package top of open interval", + "model_top": "Model top", + "prsity": "Porosity", + "rech": "Simulated groundwater recharge rates", + "riv_cond": "River package bed conductance", + "riv_rbot": "River package bottom elevation", + "riv_stage": "River package stage", + "sconc1": "Starting concentration", + "sfr_eps": "Streamflow Routing Package Brooks Corey exponent", + "sfr_ireach": "Streamflow Routing Package reach number", + "sfr_iseg": "Streamflow Routing Package segment number", + "sfr_j": "Streamflow Routing Package reach column", + "sfr_outreach": "Streamflow Routing Package downstream reach", + "sfr_rchlen": "Streamflow Routing Package reach length", + "sfr_reachID": "Streamflow Routing Package reach ID", + "sfr_slope": "Streamflow Routing Package streambed slope", + "sfr_strhc1": "Streamflow Routing Package streambed hydraulic conductivity", + "sfr_strthick": "Streamflow Routing Package streambed thickness", + "sfr_strtop": "Streamflow Routing Package streambed top", + "sfr_thti": "Streamflow Routing Package unsaturated zone " + "initial volumetric water content", + "sfr_thts": "Streamflow Routing Package unsaturated zone " + "saturated volumetric water content", + "sfr_uhc": "Streamflow Routing Package unsaturated zone " + "saturated vertical hydraulic conductivity", + "ss": "Specific storage", + "strt": "Starting heads", + "sy": "Specific yield", + "thickness": "Layer thickness", + "time": "time", + "vka": "Vertical hydraulic conductivity or vertical anisotropy", + "vkcb": "Vertical hydraulic conductivity of quasi3d confining bed", + "wel_flux": "Well package flux", +} diff --git a/flopy/export/netcdf.py b/flopy/export/netcdf.py index 11d40112f0..06eb8a29ee 100644 --- a/flopy/export/netcdf.py +++ b/flopy/export/netcdf.py @@ -9,6 +9,7 @@ from .metadata import acdd from ..utils import import_optional_dependency +from .longnames import NC_LONG_NAMES # globals FILLVALUE = -99999.9 @@ -24,10 +25,6 @@ STANDARD_VARS = ["longitude", "latitude", "layer", "elevation", "time"] -path = os.path.split(__file__)[0] -with open(path + "/longnames.json") as f: - NC_LONG_NAMES = json.load(f) - class Logger: """ @@ -1388,7 +1385,7 @@ def _check_vs_sciencebase(self, md): assert md.geospatial_vertical_min - self.vbounds[0] < tol assert md.geospatial_vertical_max - self.vbounds[1] < tol - def get_longnames_from_docstrings(self, outfile="longnames.json"): + def get_longnames_from_docstrings(self, outfile="longnames.py"): """ This is experimental. @@ -1440,7 +1437,7 @@ def get_entries(ds): attr = [v.split("_")[-1] for v in self.nc.variables] # parse docstrings to get long names - longnames = {} + longnames = dict.fromkeys(attr, "") for pkg in packages: # parse the docstring obj = pkg[-1] @@ -1453,10 +1450,8 @@ def get_entries(ds): if k in attr: longnames[k] = v.split(". ")[0] - # add in any variables that weren't found - for var in attr: - if var not in longnames.keys(): - longnames[var] = "" + longnames_dict = json.dumps(longnames, sort_keys=True, indent=4) with open(outfile, "w") as output: - json.dump(longnames, output, sort_keys=True, indent=2) + output.write("NC_LONG_NAMES = ") + output.write(longnames_dict) return longnames diff --git a/flopy/export/unitsformat.json b/flopy/export/unitsformat.json deleted file mode 100644 index cb73159497..0000000000 --- a/flopy/export/unitsformat.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "2D_cumulative_well_flux": "{0}^3/{1}", - "3D_cumulative_well_flux": "{0}^3/{1}", - "al": "{0}/{0}", - "botm": "{0}", - "cell_by_cell_flow": "{0}^3/{1}", - "chd_ehead": "{0}", - "chd_shead": "{0}", - "delc": "{0}", - "delr": "{0}", - "drawdown": "{0}", - "drn_cond": "{0}^2/{1}", - "drn_elev": "{0}", - "dz": "{0}", - "elevation": "{0}", - "ghb_bhead": "{0}", - "ghb_cond": "{0}^2/{1}", - "hani": "{0}/{0}", - "head": "{0}", - "hk": "{0}/{1}", - "horizontal_hydraulic_conductivity": "{0}/{1}", - "mnw2_B": "{1}/{0}^2", - "mnw2_C": "{1}^P/{0}^(3P-1)", - "mnw2_P": "dimensionless", - "mnw2_capmult": "dimensionless", - "mnw2_cprime": "concentration units", - "mnw2_cwc": "{0}^2/{1}", - "mnw2_hlift": "{0}", - "mnw2_hlim": "{0}", - "mnw2_hwtol": "{0}", - "mnw2_kskin": "{0}/{1}", - "mnw2_liftn": "{0}", - "mnw2_liftq0": "{0}", - "mnw2_liftqmax": "{0}", - "mnw2_pp": "{0}/{0}", - "mnw2_qcut": "{0}^3/{1}", - "mnw2_qdes": "{0}^3/{1}", - "mnw2_qfrcmn": "fraction", - "mnw2_qfrcmx": "fraction", - "mnw2_qn": "{0}^3/{1}", - "mnw2_rskin": "{0}", - "mnw2_rw": "{0}", - "mnw2_zbotm": "{0}", - "mnw2_zpump": "{0}", - "mnw2_ztop": "{0}", - "model_top": "{0}", - "primary_storage_coefficient": "{0}/{0}", - "prsity": "{0}/{0}", - "rech": "{0}/{1}", - "riv_cond": "{0}^2/{1}", - "riv_rbot": "{0}", - "riv_stage": "{0}", - "sconc1": "concentration units", - "sfr_rchlen": "{0}", - "sfr_slope": "{0}/{0}", - "sfr_strhc1": "{0}/{1}", - "sfr_strthick": "{0}", - "sfr_strtop": "{0}", - "sfr_thti": "{0}/{0}", - "sfr_thts": "{0}/{0}", - "sfr_uhc": "{0}/{1}", - "ss": "1/{0}", - "strt": "{0}", - "subsidence": "{0}", - "sy": "{0}/{0}", - "thickness": "{0}", - "time": "{1}", - "top": "{0}", - "transmissivity": "{0}^2/{1}", - "vertical_conductance": "{0}^2/{1}", - "vka": "{0}/{1} or fraction", - "vkcb": "{0}/{1}", - "wel_flux": "{0}^3/{1}" -} \ No newline at end of file diff --git a/flopy/export/unitsformat.py b/flopy/export/unitsformat.py new file mode 100644 index 0000000000..ba208d5c03 --- /dev/null +++ b/flopy/export/unitsformat.py @@ -0,0 +1,76 @@ +""" unit format strings for netCDF variables. """ + +NC_UNITS_FORMAT = { + "2D_cumulative_well_flux": "{0}^3/{1}", + "3D_cumulative_well_flux": "{0}^3/{1}", + "al": "{0}/{0}", + "botm": "{0}", + "cell_by_cell_flow": "{0}^3/{1}", + "chd_ehead": "{0}", + "chd_shead": "{0}", + "delc": "{0}", + "delr": "{0}", + "drawdown": "{0}", + "drn_cond": "{0}^2/{1}", + "drn_elev": "{0}", + "dz": "{0}", + "elevation": "{0}", + "ghb_bhead": "{0}", + "ghb_cond": "{0}^2/{1}", + "hani": "{0}/{0}", + "head": "{0}", + "hk": "{0}/{1}", + "horizontal_hydraulic_conductivity": "{0}/{1}", + "mnw2_B": "{1}/{0}^2", + "mnw2_C": "{1}^P/{0}^(3P-1)", + "mnw2_P": "dimensionless", + "mnw2_capmult": "dimensionless", + "mnw2_cprime": "concentration units", + "mnw2_cwc": "{0}^2/{1}", + "mnw2_hlift": "{0}", + "mnw2_hlim": "{0}", + "mnw2_hwtol": "{0}", + "mnw2_kskin": "{0}/{1}", + "mnw2_liftn": "{0}", + "mnw2_liftq0": "{0}", + "mnw2_liftqmax": "{0}", + "mnw2_pp": "{0}/{0}", + "mnw2_qcut": "{0}^3/{1}", + "mnw2_qdes": "{0}^3/{1}", + "mnw2_qfrcmn": "fraction", + "mnw2_qfrcmx": "fraction", + "mnw2_qn": "{0}^3/{1}", + "mnw2_rskin": "{0}", + "mnw2_rw": "{0}", + "mnw2_zbotm": "{0}", + "mnw2_zpump": "{0}", + "mnw2_ztop": "{0}", + "model_top": "{0}", + "primary_storage_coefficient": "{0}/{0}", + "prsity": "{0}/{0}", + "rech": "{0}/{1}", + "riv_cond": "{0}^2/{1}", + "riv_rbot": "{0}", + "riv_stage": "{0}", + "sconc1": "concentration units", + "sfr_rchlen": "{0}", + "sfr_slope": "{0}/{0}", + "sfr_strhc1": "{0}/{1}", + "sfr_strthick": "{0}", + "sfr_strtop": "{0}", + "sfr_thti": "{0}/{0}", + "sfr_thts": "{0}/{0}", + "sfr_uhc": "{0}/{1}", + "ss": "1/{0}", + "strt": "{0}", + "subsidence": "{0}", + "sy": "{0}/{0}", + "thickness": "{0}", + "time": "{1}", + "top": "{0}", + "transmissivity": "{0}^2/{1}", + "vertical_conductance": "{0}^2/{1}", + "vka": "{0}/{1} or fraction", + "vkcb": "{0}/{1}", + "wel_flux": "{0}^3/{1}", +} diff --git a/flopy/export/utils.py b/flopy/export/utils.py index 9761de2775..799aab09de 100644 --- a/flopy/export/utils.py +++ b/flopy/export/utils.py @@ -1,5 +1,3 @@ -import json -import os import numpy as np from ..utils import ( HeadFile, @@ -15,7 +13,8 @@ from . import shapefile_utils from . import vtk from ..utils import import_optional_dependency - +from .longnames import NC_LONG_NAMES +from .unitsformat import NC_UNITS_FORMAT NC_PRECISION_TYPE = { np.float64: "f8", @@ -25,12 +24,6 @@ np.int32: "i4", } -path = os.path.split(netcdf.__file__)[0] -with open(f"{path}/longnames.json") as f: - NC_LONG_NAMES = json.load(f) -with open(f"{path}/unitsformat.json") as f: - NC_UNITS_FORMAT = json.load(f) - def ensemble_helper( inputs_filename, outputs_filename, models, add_reals=True, **kwargs diff --git a/flopy/mf6/data/mfstructure.py b/flopy/mf6/data/mfstructure.py index 3b1b58c1b5..8101c59197 100644 --- a/flopy/mf6/data/mfstructure.py +++ b/flopy/mf6/data/mfstructure.py @@ -2455,7 +2455,7 @@ def __load_structure(self): self.sim_struct.process_dfn(DfnFile(file)) self.sim_struct.tag_read_as_arrays() else: - package_list = PackageContainer.package_factory(None, None) + package_list = PackageContainer.package_list() for package in package_list: self.sim_struct.process_dfn(DfnPackage(package)) self.sim_struct.tag_read_as_arrays() diff --git a/flopy/mf6/mfbase.py b/flopy/mf6/mfbase.py index ddc6291ae8..9a5759e1f3 100644 --- a/flopy/mf6/mfbase.py +++ b/flopy/mf6/mfbase.py @@ -1,5 +1,4 @@ -import glob -import importlib +""" Base classes for Modflow 6 """ import inspect, sys, traceback import os, copy from collections.abc import Iterable @@ -459,6 +458,11 @@ class PackageContainer: """ + modflow_packages = [] + packages_by_abbr = {} + modflow_models = [] + models_by_type = {} + def __init__(self, simulation_data, name): self.type = "PackageContainer" self.simulation_data = simulation_data @@ -469,7 +473,22 @@ def __init__(self, simulation_data, name): self.package_key_dict = {} @staticmethod - def package_factory(package_type, model_type): + def package_list(): + """Static method that returns the list of available packages. + For internal FloPy use only, not intended for end users. + + Returns a list of MFPackage subclasses + """ + # all packages except "group" classes + package_list = [] + for abbr, package in sorted(PackageContainer.packages_by_abbr.items()): + # don't store packages "group" classes + if not abbr.endswith("packages"): + package_list.append(package) + return package_list + + @staticmethod + def package_factory(package_type: str, model_type: str): """Static method that returns the appropriate package type object based on the package_type and model_type strings. For internal FloPy use only, not intended for end users. @@ -487,35 +506,11 @@ def package_factory(package_type, model_type): """ package_abbr = f"{model_type}{package_type}" - package_utl_abbr = f"utl{package_type}" - package_list = [] - # iterate through python files - package_file_paths = PackageContainer.get_package_file_paths() - for package_file_path in package_file_paths: - module = PackageContainer.get_module(package_file_path) - if module is not None: - # iterate imported items - for item in dir(module): - value = PackageContainer.get_module_val( - module, item, "package_abbr" - ) - if value is not None: - abbr = value.package_abbr - if package_type is None: - # don't store packages "group" classes - if len(abbr) <= 8 or abbr[-8:] != "packages": - package_list.append(value) - else: - # check package type - if ( - value.package_abbr == package_abbr - or value.package_abbr == package_utl_abbr - ): - return value - if package_type is None: - return package_list - else: - return None + factory = PackageContainer.packages_by_abbr.get(package_abbr) + if factory is None: + package_utl_abbr = "utl{}".format(package_type) + factory = PackageContainer.packages_by_abbr.get(package_utl_abbr) + return factory @staticmethod def model_factory(model_type): @@ -533,18 +528,7 @@ def model_factory(model_type): model : MFModel subclass """ - package_file_paths = PackageContainer.get_package_file_paths() - for package_file_path in package_file_paths: - module = PackageContainer.get_module(package_file_path) - if module is not None: - # iterate imported items - for item in dir(module): - value = PackageContainer.get_module_val( - module, item, "model_type" - ) - if value is not None and value.model_type == model_type: - return value - return None + return PackageContainer.models_by_type.get(model_type) @staticmethod def get_module_val(module, item, attrb): @@ -560,28 +544,6 @@ def get_module_val(module, item, attrb): return None return value - @staticmethod - def get_module(package_file_path): - """Static method that returns the python module library. For - internal FloPy use only, not intended for end users.""" - package_file_name = os.path.basename(package_file_path) - module_path = os.path.splitext(package_file_name)[0] - module_name = f"Modflow{module_path[2].upper()}{module_path[3:]}" - if module_name.startswith("__"): - return None - - # import - return importlib.import_module(f"flopy.mf6.modflow.{module_path}") - - @staticmethod - def get_package_file_paths(): - """Static method that gets the paths of all the FloPy python package - files. For internal FloPy use only, not intended for end users. - """ - base_path = os.path.split(os.path.realpath(__file__))[0] - package_path = os.path.join(base_path, "modflow") - return glob.glob(os.path.join(package_path, "*.py")) - @property def package_dict(self): """Returns a copy of the package name dictionary.""" diff --git a/flopy/mf6/mfmodel.py b/flopy/mf6/mfmodel.py index 17a14ec0ea..32b25bfda7 100644 --- a/flopy/mf6/mfmodel.py +++ b/flopy/mf6/mfmodel.py @@ -143,6 +143,12 @@ def __init__( self, filename=self.model_nam_file, pname=self.name ) + def __init_subclass__(cls): + """Register model type""" + super().__init_subclass__() + PackageContainer.modflow_models.append(cls) + PackageContainer.models_by_type[cls.model_type] = cls + def __getattr__(self, item): """ __getattr__ - used to allow for getting packages as if they are diff --git a/flopy/mf6/mfpackage.py b/flopy/mf6/mfpackage.py index 4eeeb6ca07..c5b33f9925 100644 --- a/flopy/mf6/mfpackage.py +++ b/flopy/mf6/mfpackage.py @@ -1598,6 +1598,12 @@ def __init__( self.__inattr = False self._child_package_groups = {} + def __init_subclass__(cls): + """Register package type""" + super().__init_subclass__() + PackageContainer.modflow_packages.append(cls) + PackageContainer.packages_by_abbr[cls.package_abbr] = cls + def __setattr__(self, name, value): if hasattr(self, name) and getattr(self, name) is not None: attribute = object.__getattribute__(self, name) @@ -2634,6 +2640,12 @@ def __init__( self._pkg_type = pkg_type self._package_class = package_class + def __init_subclass__(cls): + """Register package""" + super().__init_subclass__() + PackageContainer.modflow_packages.append(cls) + PackageContainer.packages_by_abbr[cls.package_abbr] = cls + def __getattr__(self, attr): if ( "_packages" in self.__dict__ From be264b162ecd3b3da0206a08b4a38e9056567267 Mon Sep 17 00:00:00 2001 From: Tim Mitchell Date: Tue, 19 Oct 2021 13:41:15 +1300 Subject: [PATCH 2/2] refactor(mf6): Make flopy buildable with pyinstaller restore os import accidentally removed. --- flopy/export/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/flopy/export/utils.py b/flopy/export/utils.py index 799aab09de..109b5745ec 100644 --- a/flopy/export/utils.py +++ b/flopy/export/utils.py @@ -1,3 +1,4 @@ +import os import numpy as np from ..utils import ( HeadFile,