Repository: regionmask/regionmask

Issue:
numpy 2.0 compatibility
Check and fix compatibility with numpy 2.0 and (e.g. `np.NaN` -> `np.nan`). Could be a good motivation for #323...

Discussion:
codecov-commenter: ## [Codecov](https://app.codecov.io/gh/regionmask/regionmask/pull/445?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) Report
> Merging [#445](https://app.codecov.io/gh/regionmask/regionmask/pull/445?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (e4a25b9) into [main](https://app.codecov.io/gh/regionmask/regionmask/commit/81e1aa85171de1a4d31c8e67d078ebce4c123e75?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) (81e1aa8) will **not change** coverage.
> The diff coverage is `100.00%`.

:exclamation: Your organization needs to install the [Codecov GitHub app](https://github.com/apps/codecov/installations/select_target) to enable full functionality.

```diff
@@           Coverage Diff           @@
##             main     #445   +/-   ##
=======================================
  Coverage   98.10%   98.10%           
=======================================
  Files          18       18           
  Lines        1478     1478           
=======================================
  Hits         1450     1450           
  Misses         28       28           
```

| [Flag](https://app.codecov.io/gh/regionmask/regionmask/pull/445/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | Coverage Δ | |
|---|---|---|
| [bare-minimum](https://app.codecov.io/gh/regionmask/regionmask/pull/445/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | `90.52% <100.00%> (ø)` | |
| [min-all-deps](https://app.codecov.io/gh/regionmask/regionmask/pull/445/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | `95.87% <100.00%> (ø)` | |
| [shapely_lt_2](https://app.codecov.io/gh/regionmask/regionmask/pull/445/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | `94.65% <100.00%> (ø)` | |
| [unittests](https://app.codecov.io/gh/regionmask/regionmask/pull/445/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | `98.10% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Files Changed](https://app.codecov.io/gh/regionmask/regionmask/pull/445?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask) | Coverage Δ | |
|---|---|---|
| [regionmask/core/mask.py](https://app.codecov.io/gh/regionmask/regionmask/pull/445?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=regionmask#diff-cmVnaW9ubWFzay9jb3JlL21hc2sucHk=) | `99.38% <100.00%> (ø)` | |



Patch:
diff --git a/regionmask/core/mask.py b/regionmask/core/mask.py
index 0edf884..3cc87e0 100644
--- a/regionmask/core/mask.py
+++ b/regionmask/core/mask.py
@@ -549,7 +549,7 @@ def _mask_edgepoints_shapely(
 
 
 def _mask_pygeos(
-    lon, lat, polygons, numbers, fill=np.NaN, is_unstructured=False, as_3D=False
+    lon, lat, polygons, numbers, fill=np.nan, is_unstructured=False, as_3D=False
 ):
     """create a mask using pygeos.STRtree"""
 
@@ -582,7 +582,7 @@ def _mask_pygeos(
 
 
 def _mask_shapely_v2(
-    lon, lat, polygons, numbers, fill=np.NaN, is_unstructured=False, as_3D=False
+    lon, lat, polygons, numbers, fill=np.nan, is_unstructured=False, as_3D=False
 ):
     """create a mask using pygeos.STRtree"""
 
@@ -614,7 +614,7 @@ def _mask_shapely_v2(
 
 
 def _mask_shapely(
-    lon, lat, polygons, numbers, fill=np.NaN, is_unstructured=False, as_3D=False
+    lon, lat, polygons, numbers, fill=np.nan, is_unstructured=False, as_3D=False
 ):
     """create a mask using shapely.vectorized.contains"""
 
@@ -725,7 +725,7 @@ def _transform_from_latlon(lon, lat):
 
 
 def _mask_rasterize_flip(
-    lon, lat, polygons, numbers, fill=np.NaN, as_3D=False, **kwargs
+    lon, lat, polygons, numbers, fill=np.nan, as_3D=False, **kwargs
 ):
 
     split_point = _find_splitpoint(lon)
@@ -740,7 +740,7 @@ def _mask_rasterize_flip(
 
 
 def _mask_rasterize_split(
-    lon, lat, polygons, numbers, fill=np.NaN, as_3D=False, **kwargs
+    lon, lat, polygons, numbers, fill=np.nan, as_3D=False, **kwargs
 ):
 
     split_point = _find_splitpoint(lon)
@@ -756,7 +756,7 @@ def _mask_rasterize_split(
     return np.concatenate((mask_l, mask_r), axis=-1)
 
 
-def _mask_rasterize(lon, lat, polygons, numbers, fill=np.NaN, as_3D=False, **kwargs):
+def _mask_rasterize(lon, lat, polygons, numbers, fill=np.nan, as_3D=False, **kwargs):
 
     if as_3D:
         return _mask_rasterize_3D_internal(lon, lat, polygons, **kwargs)
@@ -806,7 +806,7 @@ def _mask_rasterize_3D_internal(lon, lat, polygons, **kwargs):
     return np.concatenate(out, axis=2)[:n_polygons, ...]
 
 
-def _mask_rasterize_internal(lon, lat, polygons, numbers, fill=np.NaN, **kwargs):
+def _mask_rasterize_internal(lon, lat, polygons, numbers, fill=np.nan, **kwargs):
     """Rasterize a list of (geometry, fill_value) tuples onto the given coordinates.
 
     This only works for regularly spaced 1D lat and lon arrays.
@@ -822,7 +822,7 @@ def _mask_rasterize_internal(lon, lat, polygons, numbers, fill=np.NaN, **kwargs)
 
 
 def _mask_rasterize_no_offset(
-    lon, lat, polygons, numbers, fill=np.NaN, dtype=float, **kwargs
+    lon, lat, polygons, numbers, fill=np.nan, dtype=float, **kwargs
 ):
     """Rasterize a list of (geometry, fill_value) tuples onto the given coordinates.
 


Test patch:
diff --git a/regionmask/tests/test_geopandas.py b/regionmask/tests/test_geopandas.py
index aaa471e..1df8750 100644
--- a/regionmask/tests/test_geopandas.py
+++ b/regionmask/tests/test_geopandas.py
@@ -258,7 +258,7 @@ def test_mask_geopandas_warns_empty(geodataframe_clean, method):
 
     expected = expected_mask_2D(coords={"lon": lon, "lat": lat})
 
-    xr.testing.assert_equal(result, expected * np.NaN)
+    xr.testing.assert_equal(result, expected * np.nan)
 
 
 @pytest.mark.parametrize("drop", [True, False])
diff --git a/regionmask/tests/test_mask.py b/regionmask/tests/test_mask.py
index ed13769..ec7b92c 100644
--- a/regionmask/tests/test_mask.py
+++ b/regionmask/tests/test_mask.py
@@ -491,7 +491,7 @@ def test_transform_from_latlon(lon_start, dlon, lat_start, dlat):
 
 
 @pytest.mark.parametrize("a, b", [(0, 1), (4, 5)])
-@pytest.mark.parametrize("fill", [np.NaN, 3])
+@pytest.mark.parametrize("fill", [np.nan, 3])
 def test_rasterize(a, b, fill):
 
     expected = expected_mask_2D(a=a, b=b, fill=fill)
@@ -512,7 +512,7 @@ def test_mask_empty(method):
 
     expected = expected_mask_2D(coords={"lon": lon, "lat": lat})
 
-    xr.testing.assert_equal(result, expected * np.NaN)
+    xr.testing.assert_equal(result, expected * np.nan)
 
 
 # =============================================================================
@@ -667,7 +667,7 @@ def _expected_rectangle(ds, lon_min, lon_max, lat_min, lat_max, is_360):
     return expected & (LON > lon_min) & (LON <= lon_max)
 
 
-def expected_mask_edge(ds, is_360, number=0, fill=np.NaN):
+def expected_mask_edge(ds, is_360, number=0, fill=np.nan):
 
     expected = _expected_rectangle(ds, -100, -80, 28, 50, is_360)
 
@@ -680,7 +680,7 @@ def expected_mask_edge(ds, is_360, number=0, fill=np.NaN):
     return expected
 
 
-def expected_mask_interior_and_edge(ds, is_360, number=0, fill=np.NaN):
+def expected_mask_interior_and_edge(ds, is_360, number=0, fill=np.nan):
 
     expected_outerior = _expected_rectangle(ds, -100, -80, 28, 50, is_360)
     expected_interior = _expected_rectangle(ds, -94, -86, 34, 44, is_360)
@@ -900,7 +900,7 @@ def test_mask_whole_grid_nan_lon(regions, lon):
     # https://github.com/regionmask/regionmask/issues/426
 
     lat = np.arange(90, -91, -10)
-    lon = np.concatenate([lon, [np.NaN]])
+    lon = np.concatenate([lon, [np.nan]])
     mask = regions.mask(lon, lat)
 
     assert mask.isel(lon=-1).isnull().all()
diff --git a/regionmask/tests/test_wrapAngle.py b/regionmask/tests/test_wrapAngle.py
index 99199ed..43f6334 100644
--- a/regionmask/tests/test_wrapAngle.py
+++ b/regionmask/tests/test_wrapAngle.py
@@ -89,7 +89,7 @@ def test_wrapAngle():
 @pytest.mark.parametrize("lon", ([180.0, 190], [-180, 170]))
 def test_wrapAngle_nan(wrap_lon, lon):
 
-    result = _wrapAngle(lon + [np.NaN], wrap_lon=wrap_lon)[:-1]
+    result = _wrapAngle(lon + [np.nan], wrap_lon=wrap_lon)[:-1]
     expected = _wrapAngle(lon, wrap_lon=wrap_lon)
 
     np.testing.assert_equal(result, expected)
diff --git a/regionmask/tests/utils.py b/regionmask/tests/utils.py
index c10f38f..4997c8f 100644
--- a/regionmask/tests/utils.py
+++ b/regionmask/tests/utils.py
@@ -38,7 +38,7 @@ def expected_mask_1D():
 
 
 def expected_mask_2D(
-    a=0, b=1, fill=np.NaN, coords=None, lon_name="lon", lat_name="lat"
+    a=0, b=1, fill=np.nan, coords=None, lon_name="lon", lat_name="lat"
 ):
 
     mask = np.array([[a, fill], [b, fill]])