From 6361d7d8546b6e3d2415ca52860f8ad88a418ca4 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 11:07:23 -0600 Subject: [PATCH 01/12] Update Python version requirement and add linting workflow --- .github/workflows/lint.yml | 33 +++++++++++++++++++++++++++++++++ pyproject.toml | 30 ++++++++++++++---------------- 2 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..b389f82 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,33 @@ +name: Tools repository + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + lint: + name: Lint python files + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + strategy: + fail-fast: false + env: + HATCH_VERBOSE: 1 + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version-file: "pyproject.toml" + - name: Install uv + uses: astral-sh/setup-uv@v3 + - name: Install hatch + run: uv tool install hatch + - name: Lint Python files + run: hatch run lintformat:lint diff --git a/pyproject.toml b/pyproject.toml index a9643d8..dcc49ad 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,29 +45,27 @@ license = { file = "LICENSE.txt" } maintainers = [{ name = "Bas des Tombe", email = "bas.des.tombe@pwn.nl" }] name = "nhflotools" readme = "README.md" -requires-python = ">=3.9, <3.12" +requires-python = "3.11" [project.optional-dependencies] dev = ["hatch", "pytest", "ruff"] +lintformat = [ + "hatch", + "ruff==0.6.8", +] [tool.hatch.envs.default] -features = ["dev"] - -[tool.hatch.envs.default.scripts] -fast-test = ["pytest ./tests/ -m \"not slow\""] -format = ["ruff check --fix .", "ruff format ."] -lint = ["ruff check ."] -test = ["pytest ./src/ ./tests/"] # --doctest-modules - -[tool.hatch.envs.matrix_test] -features = ["dev"] +installer = "uv" +python = "3.11" -[[tool.hatch.envs.matrix_test.matrix]] -python = ["3.10", "3.11", "3.9"] +[tool.hatch.envs.lintformat] +detached = true +features = ["lintformat"] -[tool.hatch.envs.matrix_test.scripts] -test = ["pytest ./tests/"] # --doctest-modules +[tool.hatch.envs.lintformat.scripts] +format = ["ruff check --fix --unsafe-fixes src/nhflodata/*.py tests", "ruff format src/nhflodata/*.py tests"] +lint = ["ruff check src/nhflodata/*.py tests", "mypy src/nhflodata/*.py"] +lintminimal = ["ruff check src/nhflodata/*.py tests --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] [tool.pytest.ini_options] -markers = ["slow: marks tests as slow (deselect with '-m \"not slow\"')"] testpaths = ["tests"] From 3f5bf33fd05d1e24697b63bc1ca7ccdfee9eab97 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 11:36:39 -0600 Subject: [PATCH 02/12] Specify exact Python version requirement in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index dcc49ad..0b27704 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,7 +45,7 @@ license = { file = "LICENSE.txt" } maintainers = [{ name = "Bas des Tombe", email = "bas.des.tombe@pwn.nl" }] name = "nhflotools" readme = "README.md" -requires-python = "3.11" +requires-python = "==3.11" [project.optional-dependencies] dev = ["hatch", "pytest", "ruff"] From f2095997e44f506a2b866af80db1af4e229d5cab Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 14:32:36 -0600 Subject: [PATCH 03/12] Update ruff configuration to specify target Python version and extend linting rules --- ruff.toml | 19 ++++++++++++++++--- ruff_defaults.toml | 45 ++++++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/ruff.toml b/ruff.toml index ab693ae..2f11877 100644 --- a/ruff.toml +++ b/ruff.toml @@ -28,14 +28,27 @@ exclude = [".git", ".mypy_cache", ".ruff_cache", ".venv", ".direnv", "venv", ] -extend-include = ["*.ipynb"] +target-version = "py311" [format] preview = true [lint] preview = true -extend-select = ["D"] + +# Documentation and ensure that the defaults are included +extend-select = ["D", "E4", "E7", "E9", "F", "C901"] [lint.pydocstyle] -convention = "numpy" \ No newline at end of file +convention = "numpy" + +[lint.per-file-ignores] +'modelscripts/**/*.py' = [ + 'INP001', # Missing return type annotation for public function +] +"tests/**/test_*.py" = [ + "S101", # asserts allowed in tests +] +"**/*.ipynb" = [ + "B018", # allow notebooks printing out variables in the mid cell with variable names only +] \ No newline at end of file diff --git a/ruff_defaults.toml b/ruff_defaults.toml index ae12cd7..856559d 100644 --- a/ruff_defaults.toml +++ b/ruff_defaults.toml @@ -10,13 +10,12 @@ select = [ "A002", "A003", "ARG001", + "ARG001", "ARG002", "ARG003", "ARG004", "ARG005", "ASYNC100", - "ASYNC101", - "ASYNC102", "B002", "B003", "B004", @@ -52,6 +51,7 @@ select = [ "B035", "B904", "B905", + "B909", "BLE001", "C400", "C401", @@ -114,7 +114,7 @@ select = [ "E275", "E401", "E402", - "E501", + "E502", "E701", "E702", "E703", @@ -129,7 +129,6 @@ select = [ "E742", "E743", "E902", - "E999", "EM101", "EM102", "EM103", @@ -187,17 +186,23 @@ select = [ "FBT002", "FLY002", "FURB105", + "FURB110", "FURB113", + "FURB116", "FURB118", "FURB129", "FURB131", "FURB132", "FURB136", + "FURB142", "FURB145", "FURB148", "FURB152", + "FURB157", "FURB161", "FURB163", + "FURB164", + "FURB166", "FURB167", "FURB168", "FURB169", @@ -205,6 +210,8 @@ select = [ "FURB177", "FURB180", "FURB181", + "FURB187", + "FURB192", "G001", "G002", "G003", @@ -272,13 +279,19 @@ select = [ "PLC3002", "PLE0100", "PLE0101", + "PLE0115", "PLE0116", "PLE0117", "PLE0118", "PLE0237", "PLE0241", "PLE0302", + "PLE0303", + "PLE0304", + "PLE0305", "PLE0307", + "PLE0308", + "PLE0309", "PLE0604", "PLE0605", "PLE0643", @@ -293,6 +306,7 @@ select = [ "PLE1310", "PLE1507", "PLE1519", + "PLE1520", "PLE1700", "PLE2502", "PLE2510", @@ -300,35 +314,41 @@ select = [ "PLE2513", "PLE2514", "PLE2515", + "PLE4703", "PLR0124", "PLR0133", "PLR0202", "PLR0203", "PLR0206", "PLR0402", - "PLR1701", "PLR1704", "PLR1711", "PLR1714", "PLR1722", + "PLR1730", "PLR1733", "PLR1736", "PLR2004", "PLR2044", "PLR5501", + "PLR6104", "PLR6201", "PLR6301", "PLW0108", "PLW0120", "PLW0127", + "PLW0128", "PLW0129", "PLW0131", "PLW0133", + "PLW0177", + "PLW0211", "PLW0245", "PLW0406", "PLW0602", "PLW0603", "PLW0604", + "PLW0642", "PLW0711", "PLW1501", "PLW1508", @@ -413,6 +433,8 @@ select = [ "PYI055", "PYI056", "PYI058", + "PYI059", + "PYI062", "RET503", "RET504", "RET505", @@ -441,12 +463,12 @@ select = [ "RUF022", "RUF023", "RUF024", - "RUF025", "RUF026", "RUF027", "RUF028", + "RUF029", "RUF100", - "RUF200", + "RUF101", "S101", "S102", "S103", @@ -511,6 +533,7 @@ select = [ "S607", "S608", "S609", + "S610", "S611", "S612", "S701", @@ -563,11 +586,6 @@ select = [ "TID251", "TID252", "TID253", - "TRIO100", - "TRIO105", - "TRIO109", - "TRIO110", - "TRIO115", "TRY002", "TRY003", "TRY004", @@ -601,7 +619,6 @@ select = [ "UP024", "UP025", "UP026", - "UP027", "UP028", "UP029", "UP030", @@ -616,9 +633,11 @@ select = [ "UP039", "UP040", "UP041", + "UP042", "W291", "W292", "W293", + "W391", "W505", "W605", "YTT101", From 27ae7c7d013f15244270d94b75ae81f9c36c337f Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 14:39:41 -0600 Subject: [PATCH 04/12] Ruff format --- src/nhflotools/bergen_utils.py | 32 ++++++-------- src/nhflotools/hhnk.py | 8 ++-- src/nhflotools/nhflo_utils.py | 71 +++++++++++++++--------------- src/nhflotools/pwnlayers/io.py | 4 +- src/nhflotools/pwnlayers/layers.py | 14 +++--- 5 files changed, 60 insertions(+), 69 deletions(-) diff --git a/src/nhflotools/bergen_utils.py b/src/nhflotools/bergen_utils.py index 8c2a124..e32a388 100644 --- a/src/nhflotools/bergen_utils.py +++ b/src/nhflotools/bergen_utils.py @@ -13,7 +13,7 @@ def get_pwn_layer_model(modelgrid, shpdir, plot=False): - """Reads PWN shapefiles and converts to a layer model Dataset + """Reads PWN shapefiles and converts to a layer model Dataset. Parameters ---------- @@ -71,10 +71,7 @@ def get_pwn_layer_model(modelgrid, shpdir, plot=False): arr = np.full(len(modelgrid.xcellcenters), default) for i, row in poly.iterrows(): - if not row.geometry.is_valid: - geom = row.geometry.buffer(0.0) - else: - geom = row.geometry + geom = row.geometry.buffer(0.0) if not row.geometry.is_valid else row.geometry r = ix.intersect(geom) # set zones with value from polygon @@ -103,12 +100,12 @@ def get_pwn_layer_model(modelgrid, shpdir, plot=False): xpts = np.array(modelgrid.xcellcenters)[r.cellids.astype(int)] ypts = np.array(modelgrid.ycellcenters)[r.cellids.astype(int)] - z, ss = ok.execute("points", xpts, ypts) + z, _ss = ok.execute("points", xpts, ypts) # arr[tuple(zip(*r.cellids))] = z arr[r.cellids.astype(int)] = z else: - print(f"Did not parse {shpfolder}/{shpnam} {i}!") + pass arrays.append(arr) @@ -293,14 +290,13 @@ def get_pwn_layer_model(modelgrid, shpdir, plot=False): # create new dataset new_layer_ds = xr.Dataset(data_vars={"top": t_da, "bot": b_da, "kh": kh, "kv": kv}) - new_layer_ds = new_layer_ds.assign_coords(coords={"layer": [f"hlc_{i}" for i in range(new_layer_ds.dims["layer"])]}) + return new_layer_ds.assign_coords(coords={"layer": [f"hlc_{i}" for i in range(new_layer_ds.dims["layer"])]}) - return new_layer_ds def update_layermodel(layermodel_orig, layermodel_update): """Updates the REGIS Holocene layer with information from a PWN layer - dataset + dataset. Parameters @@ -406,7 +402,7 @@ def update_layermodel(layermodel_orig, layermodel_update): layermodel_update["kv"][lay] = xr.where(mask5, np.nan, layermodel_update["kv"][lay]) if (mask2 * (~mask1)).sum() > 0: - print(f"regis holoceen snijdt door laag {layermodel_update.layer[lay].values}") + pass top_new[: len(layermodel_update.layer), :] = layermodel_update["top"].data top_new[len(layermodel_update.layer) :, :] = layermodel_orig["top"].data[layer_no + 1 :] @@ -435,7 +431,7 @@ def update_layermodel(layermodel_orig, layermodel_update): def get_surface_water_bgt(oppwaterg, fname_bgt, gwf, cachedir="."): - """Read surface water data from a bgt geojson file + """Read surface water data from a bgt geojson file. Parameters ---------- @@ -464,18 +460,17 @@ def get_surface_water_bgt(oppwaterg, fname_bgt, gwf, cachedir="."): # put drains in most bgt-shapes at minimum surface level at watercourses fname_bgtg = os.path.join(cachedir, "bgt_waterdeel_grid.geojson") if os.path.isfile(fname_bgtg): - print("Loading gridded surface water data from cache.") # read bgtg from cache bgtg = gpd.read_file(fname_bgtg).set_index("index") bgtg = bgtg.set_crs(epsg=28992, allow_override=True) else: if os.path.isfile(fname_bgt): # read bgt from cache - print("Loading surface water data from data directory.") bgt = gpd.read_file(fname_bgt).set_index("index") bgt = bgt.set_crs(epsg=28992, allow_override=True) else: - raise FileNotFoundError("No stored surface water data!" f" {fname_bgt}") + msg = "No stored surface water data!" f" {fname_bgt}" + raise FileNotFoundError(msg) # set the index to the unique column of lokaalID bgt = bgt.set_index("lokaalID") @@ -543,7 +538,7 @@ def get_surface_water_bgt(oppwaterg, fname_bgt, gwf, cachedir="."): "W0651.45b659b8d5254f4eb2a4dc440cd464b2", ]) # some ponds near the sea - bgtg = bgtg.drop([ + return bgtg.drop([ "G0373.88944c1bb9e14bdfb35dc46d2c6eff70", "W0651.15d7bba7d7b9462d9585095d7407cd80", "W0651.e74ba578b2c14f349e72f8d301500dde", @@ -553,7 +548,6 @@ def get_surface_water_bgt(oppwaterg, fname_bgt, gwf, cachedir="."): "G0373.ab88b1eb82da4831be36b6a785ff7ec4", ]) - return bgtg def line2hfb(gdf, gwf, prevent_rings=True, plot=False): @@ -673,7 +667,7 @@ def line2hfb(gdf, gwf, prevent_rings=True, plot=False): def plot_hfb(cellids, gwf, ax=None): - """Plots a horizontal flow barrier + """Plots a horizontal flow barrier. Parameters ---------- @@ -694,7 +688,7 @@ def plot_hfb(cellids, gwf, ax=None): """ if ax is None: - fig, ax = plt.subplots() + _fig, ax = plt.subplots() if isinstance(cellids, flopy.mf6.ModflowGwfhfb): spd = cellids.stress_period_data.data[0] diff --git a/src/nhflotools/hhnk.py b/src/nhflotools/hhnk.py index 7cc448d..d7b6102 100644 --- a/src/nhflotools/hhnk.py +++ b/src/nhflotools/hhnk.py @@ -1,5 +1,5 @@ """ -Created on Mon Jun 29 15:18:06 2020 +Created on Mon Jun 29 15:18:06 2020. @author: Artesia """ @@ -39,8 +39,7 @@ def get_locations( raise (Exception(r.text)) # make a GeoDataFrame df = pd.DataFrame(r.json()["locations"]).set_index("locationId") - gdf = result_to_gdf(df) - return gdf + return result_to_gdf(df) def get_timeseries( @@ -90,8 +89,7 @@ def get_timeseries( else: events.append(None) df["events"] = events - gdf = result_to_gdf(df) - return gdf + return result_to_gdf(df) def result_to_gdf(df): diff --git a/src/nhflotools/nhflo_utils.py b/src/nhflotools/nhflo_utils.py index 533d4a4..9344428 100644 --- a/src/nhflotools/nhflo_utils.py +++ b/src/nhflotools/nhflo_utils.py @@ -1,5 +1,5 @@ """ -Created on Wed Sep 12 12:15:42 2018 +Created on Wed Sep 12 12:15:42 2018. @author: Artesia """ @@ -30,7 +30,7 @@ def colorbar_inside(mappable=None, ax=None, width=0.2, height="90%", loc=5, **kw ax = plt.gca() cax = inset_axes(ax, width=width, height=height, loc=loc) cb = plt.colorbar(mappable, cax=cax, ax=ax, **kw) - if loc == 1 or loc == 4 or loc == 5: + if loc in {1, 4, 5}: cax.yaxis.tick_left() cax.yaxis.set_label_position("left") return cb @@ -51,7 +51,7 @@ def title_inside(title, ax=None, x=0.5, y=0.98, **kwargs): def geodataframe2grid(mf, shp_in): - """Cut a geodataframe shp_in by the grid of a modflow model ml""" + """Cut a geodataframe shp_in by the grid of a modflow model ml.""" geom_col_name = shp_in._geometry_column_name # make a polygon for each of the grid-cells @@ -69,7 +69,7 @@ def geodataframe2grid(mf, shp_in): shp_list = [] # cut the lines with the grid - for index, row in shp_in.iterrows(): + for _index, row in shp_in.iterrows(): g = row[geom_col_name] result = s.query(g) for r in result: @@ -89,7 +89,8 @@ def geodataframe2grid2(gdf, mgrid=None, grid_ix=None, keepcols=None, progressbar if grid_ix is None and mgrid is not None: grid_ix = flopy.utils.GridIntersect(mgrid, method="vertex") elif grid_ix is None and mgrid is None: - raise ValueError("Provide either 'mgrid' or 'grid_ix'!") + msg = "Provide either 'mgrid' or 'grid_ix'!" + raise ValueError(msg) reclist = [] @@ -103,7 +104,7 @@ def geodataframe2grid2(gdf, mgrid=None, grid_ix=None, keepcols=None, progressbar if keepcols is not None: dtypes = gdf.dtypes.loc[keepcols].to_list() - val_arrs = [ival * np.ones(r.shape[0], dtype=idtype) for ival, idtype in zip(row.loc[keepcols], dtypes)] + val_arrs = [ival * np.ones(r.shape[0], dtype=idtype) for ival, idtype in zip(row.loc[keepcols], dtypes, strict=False)] r = append_fields(r, keepcols, val_arrs, dtypes, usemask=False, asrecarray=True) if r.shape[0] > 0: reclist.append(r) @@ -115,11 +116,11 @@ def geodataframe2grid2(gdf, mgrid=None, grid_ix=None, keepcols=None, progressbar def _add_shapes_to_list(i, geometryType, geom_col_name, row, shp_list, r): - """Subfunction of geodataframe2grid""" + """Subfunction of geodataframe2grid.""" if geometryType == "LineString": if not i.is_empty: it = i.geometryType() - if it == "GeometryCollection" or it == "MultiLineString": + if it in {"GeometryCollection", "MultiLineString"}: for im in i.geoms: _add_shapes_to_list(im, geometryType, geom_col_name, row, shp_list, r) elif it == "LineString": @@ -139,9 +140,9 @@ def _add_shapes_to_list(i, geometryType, geom_col_name, row, shp_list, r): pass else: raise NotImplementedError("geometryType " + it + " not yet supprted in geodataframe2grid") - elif geometryType == "Polygon" or geometryType == "MultiPolygon": + elif geometryType in {"Polygon", "MultiPolygon"}: it = i.geometryType() - if it == "GeometryCollection" or it == "MultiPolygon": + if it in {"GeometryCollection", "MultiPolygon"}: for im in i.geoms: _add_shapes_to_list(im, geometryType, geom_col_name, row, shp_list, r) elif it == "Polygon": @@ -153,7 +154,7 @@ def _add_shapes_to_list(i, geometryType, geom_col_name, row, shp_list, r): elif it == "Point": # endpoint of the polygon is on the cell-edge pass - elif it == "LineString" or it == "MultiLineString": + elif it in {"LineString", "MultiLineString"}: # one of the edges of the polygon is on a cell-egde pass else: @@ -204,7 +205,7 @@ def change_util3d(pack, parnam, sr_old, xgrid, ygrid): set_util3d(pack, parnam, val_new, val_old.dtype) for pack in packages: - if pack in ["PCG", "OC"]: + if pack in {"PCG", "OC"}: # packages have no spatial component pass @@ -246,7 +247,7 @@ def change_util3d(pack, parnam, sr_old, xgrid, ygrid): def unzip_file(src, dst, force=False, preserve_datetime=False): - """Unzip file + """Unzip file. Parameters ---------- @@ -265,15 +266,13 @@ def unzip_file(src, dst, force=False, preserve_datetime=False): 1 of True """ - if os.path.exists(dst): - if not force: - print("File not unzipped. Destination already exists. " "Use 'force=True' to unzip.") - return + if os.path.exists(dst) and not force: + return if preserve_datetime: zipf = zipfile.ZipFile(src, "r") for f in zipf.infolist(): zipf.extract(f, path=dst) - date_time = time.mktime(f.date_time + (0, 0, -1)) + date_time = time.mktime((*f.date_time, 0, 0, -1)) os.utime(os.path.join(dst, f.filename), (date_time, date_time)) zipf.close() else: @@ -284,7 +283,7 @@ def unzip_file(src, dst, force=False, preserve_datetime=False): def df2gdf(df, xcol="x", ycol="y"): - """Convert DataFrame to a point GeoDataFrame + """Convert DataFrame to a point GeoDataFrame. Parameters ---------- @@ -299,8 +298,7 @@ def df2gdf(df, xcol="x", ycol="y"): ------- gdf : geopandas.GeoDataFrame """ - gdf = gpd.GeoDataFrame(df.copy(), geometry=[Point((s[xcol], s[ycol])) for i, s in df.iterrows()]) - return gdf + return gpd.GeoDataFrame(df.copy(), geometry=[Point((s[xcol], s[ycol])) for i, s in df.iterrows()]) def get_mt3d_results(f, kstpkper=(0, 0), mflay=0, inact=1e30): @@ -339,7 +337,7 @@ def unzip_changed_files(zipname, pathname, check_time=True, check_size=False, de extract = False if os.path.exists(fname): if check_time: - tz = time.mktime(info.date_time + (0, 0, -1)) + tz = time.mktime((*info.date_time, 0, 0, -1)) tf = os.path.getmtime(fname) if tz != tf: extract = True @@ -352,16 +350,16 @@ def unzip_changed_files(zipname, pathname, check_time=True, check_size=False, de extract = True if extract: if debug: - print(f"extracting {info.filename}") + pass zf.extract(info.filename, pathname) # set the correct modification time # (which is the time of extraction by default) - tz = time.mktime(info.date_time + (0, 0, -1)) + tz = time.mktime((*info.date_time, 0, 0, -1)) os.utime(os.path.join(pathname, info.filename), (tz, tz)) def interp_weights(xy, uv, d=2): - """Calculate interpolation weights + """Calculate interpolation weights. Parameters ---------- @@ -424,7 +422,7 @@ def interpolate(values, vtx, wts): def inpolygon(x, y, polygon, engine="matplotlib"): - """Find out which points defined by x and y are within polygon + """Find out which points defined by x and y are within polygon. Parameters ---------- @@ -444,25 +442,27 @@ def inpolygon(x, y, polygon, engine="matplotlib"): """ shape = x.shape - points = list(zip(x.flatten(), y.flatten())) + points = list(zip(x.flatten(), y.flatten(), strict=False)) if engine == "matplotlib": if isinstance(polygon, MultiPolygon): mask = np.full((len(points)), False) for pol2 in polygon: if not isinstance(pol2, Polygon): - raise (Exception(f"{type(pol2)} not supported")) + msg = f"{type(pol2)} not supported" + raise (Exception(msg)) if isinstance(pol2.boundary, MultiLineString): xb, yb = pol2.boundary[0].xy else: xb, yb = pol2.boundary.xy - path = Path(list(zip(xb, yb))) - mask = mask | path.contains_points(points) + path = Path(list(zip(xb, yb, strict=False))) + mask |= path.contains_points(points) elif isinstance(polygon, Polygon): xb, yb = polygon.boundary.xy - path = Path(list(zip(xb, yb))) + path = Path(list(zip(xb, yb, strict=False))) mask = path.contains_points(points) else: - raise (Exception(f"{type(polygon)} not supported")) + msg = f"{type(polygon)} not supported" + raise (Exception(msg)) else: mask = [polygon.contains(Point(x, y)) for x, y in points] mask = np.array(mask) @@ -470,13 +470,12 @@ def inpolygon(x, y, polygon, engine="matplotlib"): def extent2polygon(extent): - """Make a Polygon of the extent of a matplotlib axes""" + """Make a Polygon of the extent of a matplotlib axes.""" nw = (extent[0], extent[2]) no = (extent[1], extent[2]) zo = (extent[1], extent[3]) zw = (extent[0], extent[3]) - polygon = Polygon([nw, no, zo, zw]) - return polygon + return Polygon([nw, no, zo, zw]) def rotate_yticklabels(ax): @@ -485,7 +484,7 @@ def rotate_yticklabels(ax): def rd_ticks(ax, base=1000.0, fmt_base=1000, fmt="{:.0f}"): - """Add ticks every 1000 (base) m, and divide ticklabels by 1000 (fmt_base)""" + """Add ticks every 1000 (base) m, and divide ticklabels by 1000 (fmt_base).""" def fmt_rd_ticks(x, y): return fmt.format(x / fmt_base) diff --git a/src/nhflotools/pwnlayers/io.py b/src/nhflotools/pwnlayers/io.py index 96f5eec..0afa8dd 100644 --- a/src/nhflotools/pwnlayers/io.py +++ b/src/nhflotools/pwnlayers/io.py @@ -244,7 +244,7 @@ def _read_bergen_basis_aquitards( _multipolygon = MultiPolygon( gdf_krieg.geometry.explode("geometry", index_parts=True).values ) # returns Polygon or MultiPolygon - _multipolygonl = [g for g in make_valid(_multipolygon).geoms if isinstance(g, (MultiPolygon, Polygon))] + _multipolygonl = [g for g in make_valid(_multipolygon).geoms if isinstance(g, MultiPolygon | Polygon)] if len(_multipolygonl) != 1: msg = "MultiPolygons in multipolygon" raise ValueError(msg) @@ -391,7 +391,7 @@ def _read_bergen_thickness_aquitards( _multipolygon = MultiPolygon( gdf_krieg.geometry.explode("geometry", index_parts=True).values ) # returns Polygon or MultiPolygon - _multipolygonl = [g for g in make_valid(_multipolygon).geoms if isinstance(g, (MultiPolygon, Polygon))] + _multipolygonl = [g for g in make_valid(_multipolygon).geoms if isinstance(g, MultiPolygon | Polygon)] if len(_multipolygonl) != 1: msg = "MultiPolygons in multipolygon" diff --git a/src/nhflotools/pwnlayers/layers.py b/src/nhflotools/pwnlayers/layers.py index 75f00b6..85f1956 100644 --- a/src/nhflotools/pwnlayers/layers.py +++ b/src/nhflotools/pwnlayers/layers.py @@ -256,14 +256,14 @@ def get_top_from_ahn( points = list( zip( top.y.sel(icell2d=top.notnull()).values, - top.x.sel(icell2d=top.notnull()).values, + top.x.sel(icell2d=top.notnull()).values, strict=False, ) ) values = top.sel(icell2d=top.notnull()).values qpoints = list( zip( top.y.sel(icell2d=top.isnull()).values, - top.x.sel(icell2d=top.isnull()).values, + top.x.sel(icell2d=top.isnull()).values, strict=False, ) ) qvalues = griddata(points=points, values=values, xi=qpoints, method=method_elsewhere) @@ -489,7 +489,7 @@ def combine_two_layer_models( if layer_model_regis.layer.str.contains("_").any(): # TODO: if previously combined layer_model needs to be split for a second time - split_counts_regis_cur = dict(zip(*np.unique(basenames_regis, return_counts=True))) + split_counts_regis_cur = dict(zip(*np.unique(basenames_regis, return_counts=True), strict=False)) assert all( v == split_counts_regis_cur[k] for k, v in split_counts_regis_def.items() ), "Previously combined REGIS layers should be split in the same number of layers as before." @@ -625,14 +625,14 @@ def combine_two_layer_models( griddata_points = list( zip( thick_ratio_other.coords["x"].sel(icell2d=mask).values, - thick_ratio_other.coords["y"].sel(icell2d=mask).values, + thick_ratio_other.coords["y"].sel(icell2d=mask).values, strict=False, ) ) gridpoint_values = thick_ratio_other.sel(layer=layer, icell2d=mask).values qpoints = list( zip( thick_ratio_other.coords["x"].sel(icell2d=~mask).values, - thick_ratio_other.coords["y"].sel(icell2d=~mask).values, + thick_ratio_other.coords["y"].sel(icell2d=~mask).values, strict=False, ) ) qvalues = griddata( @@ -776,14 +776,14 @@ def combine_two_layer_models( griddata_points = list( zip( vari.coords["x"].sel(icell2d=~transi).values, - vari.coords["y"].sel(icell2d=~transi).values, + vari.coords["y"].sel(icell2d=~transi).values, strict=False, ) ) gridpoint_values = vari.sel(icell2d=~transi).values qpoints = list( zip( vari.coords["x"].sel(icell2d=transi).values, - vari.coords["y"].sel(icell2d=transi).values, + vari.coords["y"].sel(icell2d=transi).values, strict=False, ) ) qvalues = griddata( From 48dd09fc71840b7c74e812c1b86d2a35c4e762e9 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 14:45:15 -0600 Subject: [PATCH 05/12] Ruff format --- src/nhflotools/bergen_utils.py | 2 -- src/nhflotools/nhflo_utils.py | 5 ++++- src/nhflotools/polder.py | 3 +-- src/nhflotools/pwnlayers/layers.py | 18 ++++++++++++------ src/nhflotools/well.py | 2 ++ tests/__init__.py | 0 tests/test_hhnk.py | 1 + 7 files changed, 20 insertions(+), 11 deletions(-) create mode 100644 tests/__init__.py diff --git a/src/nhflotools/bergen_utils.py b/src/nhflotools/bergen_utils.py index e32a388..200efb2 100644 --- a/src/nhflotools/bergen_utils.py +++ b/src/nhflotools/bergen_utils.py @@ -293,7 +293,6 @@ def get_pwn_layer_model(modelgrid, shpdir, plot=False): return new_layer_ds.assign_coords(coords={"layer": [f"hlc_{i}" for i in range(new_layer_ds.dims["layer"])]}) - def update_layermodel(layermodel_orig, layermodel_update): """Updates the REGIS Holocene layer with information from a PWN layer dataset. @@ -549,7 +548,6 @@ def get_surface_water_bgt(oppwaterg, fname_bgt, gwf, cachedir="."): ]) - def line2hfb(gdf, gwf, prevent_rings=True, plot=False): """Obtain the cells with a horizontal flow barrier between them from a geodataframe with line elements. diff --git a/src/nhflotools/nhflo_utils.py b/src/nhflotools/nhflo_utils.py index 9344428..e2e7c04 100644 --- a/src/nhflotools/nhflo_utils.py +++ b/src/nhflotools/nhflo_utils.py @@ -104,7 +104,10 @@ def geodataframe2grid2(gdf, mgrid=None, grid_ix=None, keepcols=None, progressbar if keepcols is not None: dtypes = gdf.dtypes.loc[keepcols].to_list() - val_arrs = [ival * np.ones(r.shape[0], dtype=idtype) for ival, idtype in zip(row.loc[keepcols], dtypes, strict=False)] + val_arrs = [ + ival * np.ones(r.shape[0], dtype=idtype) + for ival, idtype in zip(row.loc[keepcols], dtypes, strict=False) + ] r = append_fields(r, keepcols, val_arrs, dtypes, usemask=False, asrecarray=True) if r.shape[0] > 0: reclist.append(r) diff --git a/src/nhflotools/polder.py b/src/nhflotools/polder.py index 5e62fcb..2f1a77c 100644 --- a/src/nhflotools/polder.py +++ b/src/nhflotools/polder.py @@ -41,8 +41,7 @@ def drn_from_waterboard_data(ds, gwf, wb="Hollands Noorderkwartier", cbot=1.0): # Rename duplicate indices counts = Counter(gdf.index) suffix_counter = defaultdict(lambda: itertools.count(1)) - index2 = [elem if counts[elem] == 1 else elem + f'_{next(suffix_counter[elem])}' - for elem in gdf.index] + index2 = [elem if counts[elem] == 1 else elem + f"_{next(suffix_counter[elem])}" for elem in gdf.index] gdf.index = index2 gdf_grid = nlmod.grid.gdf_to_grid(gdf.loc[:, ["summer_stage", "winter_stage", "geometry"]], gwf) diff --git a/src/nhflotools/pwnlayers/layers.py b/src/nhflotools/pwnlayers/layers.py index 85f1956..25e6aae 100644 --- a/src/nhflotools/pwnlayers/layers.py +++ b/src/nhflotools/pwnlayers/layers.py @@ -256,14 +256,16 @@ def get_top_from_ahn( points = list( zip( top.y.sel(icell2d=top.notnull()).values, - top.x.sel(icell2d=top.notnull()).values, strict=False, + top.x.sel(icell2d=top.notnull()).values, + strict=False, ) ) values = top.sel(icell2d=top.notnull()).values qpoints = list( zip( top.y.sel(icell2d=top.isnull()).values, - top.x.sel(icell2d=top.isnull()).values, strict=False, + top.x.sel(icell2d=top.isnull()).values, + strict=False, ) ) qvalues = griddata(points=points, values=values, xi=qpoints, method=method_elsewhere) @@ -625,14 +627,16 @@ def combine_two_layer_models( griddata_points = list( zip( thick_ratio_other.coords["x"].sel(icell2d=mask).values, - thick_ratio_other.coords["y"].sel(icell2d=mask).values, strict=False, + thick_ratio_other.coords["y"].sel(icell2d=mask).values, + strict=False, ) ) gridpoint_values = thick_ratio_other.sel(layer=layer, icell2d=mask).values qpoints = list( zip( thick_ratio_other.coords["x"].sel(icell2d=~mask).values, - thick_ratio_other.coords["y"].sel(icell2d=~mask).values, strict=False, + thick_ratio_other.coords["y"].sel(icell2d=~mask).values, + strict=False, ) ) qvalues = griddata( @@ -776,14 +780,16 @@ def combine_two_layer_models( griddata_points = list( zip( vari.coords["x"].sel(icell2d=~transi).values, - vari.coords["y"].sel(icell2d=~transi).values, strict=False, + vari.coords["y"].sel(icell2d=~transi).values, + strict=False, ) ) gridpoint_values = vari.sel(icell2d=~transi).values qpoints = list( zip( vari.coords["x"].sel(icell2d=transi).values, - vari.coords["y"].sel(icell2d=transi).values, strict=False, + vari.coords["y"].sel(icell2d=transi).values, + strict=False, ) ) qvalues = griddata( diff --git a/src/nhflotools/well.py b/src/nhflotools/well.py index e63363c..1200558 100644 --- a/src/nhflotools/well.py +++ b/src/nhflotools/well.py @@ -1,3 +1,5 @@ +"""Functions to get wells data for PWN model.""" + import os import geopandas as gpd diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_hhnk.py b/tests/test_hhnk.py index e69de29..d007b83 100644 --- a/tests/test_hhnk.py +++ b/tests/test_hhnk.py @@ -0,0 +1 @@ +"""Test HHNK tools.""" From 5844d513f4f41e476bce759002d120d8224f24c6 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:30:26 -0600 Subject: [PATCH 06/12] Update linting scripts and improve function docstring in bergen_utils.py --- pyproject.toml | 11 ++++++++--- src/nhflotools/bergen_utils.py | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0b27704..2d8c3a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,9 +63,14 @@ detached = true features = ["lintformat"] [tool.hatch.envs.lintformat.scripts] -format = ["ruff check --fix --unsafe-fixes src/nhflodata/*.py tests", "ruff format src/nhflodata/*.py tests"] -lint = ["ruff check src/nhflodata/*.py tests", "mypy src/nhflodata/*.py"] -lintminimal = ["ruff check src/nhflodata/*.py tests --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] +format = [ + "ruff check --fix --unsafe-fixes src/nhflotools/*.py tests", + "ruff format src/nhflotools/*.py tests" +] +lint = [ + "ruff check tests/test_pwnlayers.py src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} +] +lintminimal = ["ruff check src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] [tool.pytest.ini_options] testpaths = ["tests"] diff --git a/src/nhflotools/bergen_utils.py b/src/nhflotools/bergen_utils.py index 200efb2..7b123fd 100644 --- a/src/nhflotools/bergen_utils.py +++ b/src/nhflotools/bergen_utils.py @@ -12,8 +12,8 @@ from shapely.geometry import Point, Polygon -def get_pwn_layer_model(modelgrid, shpdir, plot=False): - """Reads PWN shapefiles and converts to a layer model Dataset. +def get_pwn_layer_model(modelgrid, shpdir, plot=False): # noqa: C901 + """Read PWN shapefiles and convert to a layer model Dataset. Parameters ---------- From ec021b80b46fca6cbfb7249c4354583e1aa6ffcf Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:32:57 -0600 Subject: [PATCH 07/12] Fix lint command syntax in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 2d8c3a1..844cefd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ format = [ "ruff format src/nhflotools/*.py tests" ] lint = [ - "ruff check tests/test_pwnlayers.py src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} + "ruff check tests/test_pwnlayers.py src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py}" ] lintminimal = ["ruff check src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] From 95fa252cce32751500df88934b5089e8b7ae27e5 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:34:51 -0600 Subject: [PATCH 08/12] Refactor lint command in pyproject.toml for improved clarity and consistency --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 844cefd..1dff589 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,9 +68,9 @@ format = [ "ruff format src/nhflotools/*.py tests" ] lint = [ - "ruff check tests/test_pwnlayers.py src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py}" + "ruff check tests/test_pwnlayers.py src/nhflotools/pwnlayers src/nhflotools/{major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py}" ] -lintminimal = ["ruff check src/nhflotools/{pwnlayers,major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] +lintminimal = ["ruff check src/nhflotools/pwnlayers src/nhflotools/{major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] [tool.pytest.ini_options] testpaths = ["tests"] From 749bf736468f8b93b33a1660b7cc096a5284da7e Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:36:43 -0600 Subject: [PATCH 09/12] Update lint command in pyproject.toml for improved file specification --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 1dff589..edfe992 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,9 +68,9 @@ format = [ "ruff format src/nhflotools/*.py tests" ] lint = [ - "ruff check tests/test_pwnlayers.py src/nhflotools/pwnlayers src/nhflotools/{major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py}" + "ruff check tests/test_pwnlayers.py src/nhflotools/pwnlayers src/nhflotools/major_surface_waters.py src/nhflotools/nhi_chloride.py src/nhflotools/panden.py src/nhflotools/polder.py src/nhflotools/well.py}" ] -lintminimal = ["ruff check src/nhflotools/pwnlayers src/nhflotools/{major_surface_waters.py,nhi_chloride.py,panden.py,polder.py,well.py} --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] +lintminimal = ["ruff check src/nhflotools/pwnlayers src/nhflotools/major_surface_waters.py src/nhflotools/nhi_chloride.py src/nhflotools/panden.py src/nhflotools/polder.py src/nhflotools/well.py --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] [tool.pytest.ini_options] testpaths = ["tests"] From 19b5231f1b05f187d6d36178707c33775642a43a Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:37:27 -0600 Subject: [PATCH 10/12] Fix lint command syntax in pyproject.toml by removing an extraneous character --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index edfe992..7918175 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -68,7 +68,7 @@ format = [ "ruff format src/nhflotools/*.py tests" ] lint = [ - "ruff check tests/test_pwnlayers.py src/nhflotools/pwnlayers src/nhflotools/major_surface_waters.py src/nhflotools/nhi_chloride.py src/nhflotools/panden.py src/nhflotools/polder.py src/nhflotools/well.py}" + "ruff check tests/test_pwnlayers.py src/nhflotools/pwnlayers src/nhflotools/major_surface_waters.py src/nhflotools/nhi_chloride.py src/nhflotools/panden.py src/nhflotools/polder.py src/nhflotools/well.py" ] lintminimal = ["ruff check src/nhflotools/pwnlayers src/nhflotools/major_surface_waters.py src/nhflotools/nhi_chloride.py src/nhflotools/panden.py src/nhflotools/polder.py src/nhflotools/well.py --config \"lint.select=['E4', 'E7', 'E9', 'F']\""] From 25030107316cfd5d5ac00f0cc3f4e5b82fc53466 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:38:32 -0600 Subject: [PATCH 11/12] Update lint command in GitHub Actions workflow to use minimal linting format --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b389f82..75335d2 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -30,4 +30,4 @@ jobs: - name: Install hatch run: uv tool install hatch - name: Lint Python files - run: hatch run lintformat:lint + run: hatch run lintformat:lintminimal From 56326cbc01c842794b8fdd94c59e11b0379aa0e1 Mon Sep 17 00:00:00 2001 From: Bas des Tombe Date: Mon, 25 Nov 2024 15:42:05 -0600 Subject: [PATCH 12/12] Add itertools and collections imports to polder.py for enhanced functionality --- src/nhflotools/polder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/nhflotools/polder.py b/src/nhflotools/polder.py index 2f1a77c..d017bba 100644 --- a/src/nhflotools/polder.py +++ b/src/nhflotools/polder.py @@ -1,3 +1,6 @@ +import itertools +from collections import Counter, defaultdict + import nlmod import numpy as np import scipy.interpolate as si