[Git][debian-gis-team/pyresample][master] 5 commits: New upstream version 1.35.0
Antonio Valentino (@antonio.valentino)
gitlab at salsa.debian.org
Wed Dec 10 07:44:20 GMT 2025
Antonio Valentino pushed to branch master at Debian GIS Project / pyresample
Commits:
1b705922 by Antonio Valentino at 2025-12-05T18:55:49+00:00
New upstream version 1.35.0
- - - - -
b88bdc60 by Antonio Valentino at 2025-12-05T18:56:00+00:00
Update upstream source from tag 'upstream/1.35.0'
Update to upstream version '1.35.0'
with Debian dir 01336c7e48e1177ff7711da1776f3e5bee489d97
- - - - -
d94c7f50 by Antonio Valentino at 2025-12-05T18:56:37+00:00
New upstream release
- - - - -
3ce89f9c by Antonio Valentino at 2025-12-05T19:02:56+00:00
Refresh all patches
- - - - -
baeb028a by Antonio Valentino at 2025-12-05T19:03:18+00:00
Set distribution to unstable
- - - - -
24 changed files:
- .github/workflows/ci.yaml
- .github/workflows/deploy.yaml
- .pre-commit-config.yaml
- CHANGELOG.md
- debian/changelog
- − debian/patches/0005-Compatibility-with-numpy-2.0.patch
- debian/patches/0006-Use-sphinxcontrib.apidoc.patch → debian/patches/0005-Use-sphinxcontrib.apidoc.patch
- debian/patches/series
- pyproject.toml
- pyresample/_formatting_html.py
- pyresample/_spatial_mp.py
- pyresample/bilinear/xarr.py
- pyresample/boundary/legacy_boundary.py
- pyresample/bucket/__init__.py
- pyresample/geometry.py
- pyresample/resampler.py
- pyresample/slicer.py
- pyresample/spherical.py
- pyresample/spherical_utils.py
- pyresample/test/test_boundary/test_legacy_boundary.py
- pyresample/test/test_geometry/test_swath_boundary.py
- pyresample/utils/proj4.py
- pyresample/version.py
- setup.py
Changes:
=====================================
.github/workflows/ci.yaml
=====================================
@@ -30,7 +30,7 @@ jobs:
steps:
- name: Checkout source
- uses: actions/checkout at v4
+ uses: actions/checkout at v6
- name: Setup Conda Environment
uses: conda-incubator/setup-miniconda at v3
@@ -89,7 +89,7 @@ jobs:
uses: codecov/codecov-action at v5
with:
flags: unittests
- file: ./coverage.xml
+ files: ./coverage.xml
env_vars: OS,PYTHON_VERSION,UNSTABLE
- name: Coveralls Parallel
=====================================
.github/workflows/deploy.yaml
=====================================
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout source
- uses: actions/checkout at v4
+ uses: actions/checkout at v6
- name: Create sdist
shell: bash -l {0}
@@ -28,7 +28,7 @@ jobs:
python -m build -s
- name: Upload sdist to build artifacts
- uses: actions/upload-artifact at v4
+ uses: actions/upload-artifact at v5
with:
name: sdist
path: dist/*.tar.gz
@@ -41,9 +41,9 @@ jobs:
fail-fast: false
matrix:
include:
- - os: windows-2019
+ - os: windows-latest
cibw_archs: "AMD64"
- - os: windows-2019
+ - os: windows-latest
cibw_archs: "ARM64"
- os: macos-13
cibw_archs: "x86_64"
@@ -55,21 +55,22 @@ jobs:
cibw_archs: "x86_64"
steps:
- - uses: actions/checkout at v4
+ - uses: actions/checkout at v6
- run: |
git fetch --prune --unshallow
- name: Build wheels
- uses: pypa/cibuildwheel at v2.23.3
+ uses: pypa/cibuildwheel at v3.3.0
env:
- CIBW_SKIP: "cp36-* cp37-* cp38-* cp39-* cp310-* pp* *i686 *-musllinux*"
+ CIBW_SKIP: "cp39-* cp310-* *i686 *-musllinux*"
+ CIBW_ENABLE: cpython-freethreading
CIBW_ARCHS: "${{ matrix.cibw_archs }}"
CIBW_TEST_COMMAND: "python -c \"import pyresample; assert 'unknown' not in pyresample.__version__, 'incorrect version found'\""
CIBW_TEST_SKIP: "*-win_arm64"
CIBW_BUILD_VERBOSITY: 1
- name: Upload wheel(s) as build artifacts
- uses: actions/upload-artifact at v4
+ uses: actions/upload-artifact at v5
with:
name: "wheels-${{ matrix.os }}-${{ matrix.cibw_archs }}"
path: ./wheelhouse/*.whl
@@ -81,19 +82,19 @@ jobs:
if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
steps:
- name: Download sdist artifact
- uses: actions/download-artifact at v4
+ uses: actions/download-artifact at v6
with:
name: sdist
path: dist
- name: Download wheels artifact
- uses: actions/download-artifact at v4
+ uses: actions/download-artifact at v6
with:
pattern: wheels-*
merge-multiple: true
path: dist
- name: Publish package to PyPI
if: github.event.action != 'published'
- uses: pypa/gh-action-pypi-publish at v1.12.4
+ uses: pypa/gh-action-pypi-publish at v1.13.0
with:
user: __token__
password: ${{ secrets.test_pypi_password }}
@@ -104,19 +105,19 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download sdist artifact
- uses: actions/download-artifact at v4
+ uses: actions/download-artifact at v6
with:
name: sdist
path: dist
- name: Download wheels artifact
- uses: actions/download-artifact at v4
+ uses: actions/download-artifact at v6
with:
pattern: wheels-*
merge-multiple: true
path: dist
- name: Publish package to PyPI
if: github.event.action == 'published'
- uses: pypa/gh-action-pypi-publish at v1.12.4
+ uses: pypa/gh-action-pypi-publish at v1.13.0
with:
user: __token__
password: ${{ secrets.pypi_password }}
=====================================
.pre-commit-config.yaml
=====================================
@@ -2,23 +2,23 @@ exclude: '^$'
fail_fast: false
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: 'v0.11.8'
+ rev: 'v0.14.7'
hooks:
- id: ruff
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v5.0.0
+ rev: v6.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
args: [--unsafe]
- repo: https://github.com/PyCQA/bandit
- rev: '1.8.3' # Update me!
+ rev: '1.9.2' # Update me!
hooks:
- id: bandit
args: [--ini, .bandit]
- repo: https://github.com/pre-commit/mirrors-mypy
- rev: 'v1.15.0' # Use the sha / tag you want to point at
+ rev: 'v1.19.0' # Use the sha / tag you want to point at
hooks:
- id: mypy
additional_dependencies:
@@ -32,7 +32,7 @@ repos:
- pytest
args: [ --warn-unused-configs ]
- repo: https://github.com/pycqa/isort
- rev: 6.0.1
+ rev: 7.0.0
hooks:
- id: isort
language_version: python3
=====================================
CHANGELOG.md
=====================================
@@ -1,3 +1,28 @@
+## Version 1.35.0 (2025/12/01)
+
+### Issues Closed
+
+* [Issue 684](https://github.com/pytroll/pyresample/issues/684) - areas with non-matching descriptions compare equal
+* [Issue 666](https://github.com/pytroll/pyresample/issues/666) - data_reduce doesn't work for VIIRS L1B data
+* [Issue 664](https://github.com/pytroll/pyresample/issues/664) - How we define the "same" AreaDefinition?
+
+In this release 3 issues were closed.
+
+### Pull Requests Merged
+
+#### Bugs fixed
+
+* [PR 677](https://github.com/pytroll/pyresample/pull/677) - Fix boundaries losing precision for accurate polygon calculations
+* [PR 675](https://github.com/pytroll/pyresample/pull/675) - Fix BucketResampler using area's proj_dict instead crs
+* [PR 674](https://github.com/pytroll/pyresample/pull/674) - Revert change of map_blocks name= kwarg in favor of token=
+
+#### Features added
+
+* [PR 676](https://github.com/pytroll/pyresample/pull/676) - Enable free-threading in cython extensions
+
+In this release 4 pull requests were closed.
+
+
## Version 1.34.2 (2025/05/29)
### Pull Requests Merged
=====================================
debian/changelog
=====================================
@@ -1,9 +1,15 @@
-pyresample (1.34.2-3) UNRELEASED; urgency=medium
+pyresample (1.35.0-1) unstable; urgency=medium
- * Team upload.
+ [ Bas Couwenberg ]
* Use test-build-validate-cleanup instead of test-build-twice.
- -- Bas Couwenberg <sebastic at debian.org> Sat, 25 Oct 2025 13:04:37 +0200
+ [ Antonio Valentino ]
+ * New upstream release.
+ * debian/patches:
+ - Drop 0005-Compatibility-with-numpy-2.0.patch.
+ - Refresh and renumber remaining patches.
+
+ -- Antonio Valentino <antonio.valentino at tiscali.it> Fri, 05 Dec 2025 19:02:59 +0000
pyresample (1.34.2-2) unstable; urgency=medium
=====================================
debian/patches/0005-Compatibility-with-numpy-2.0.patch deleted
=====================================
@@ -1,20 +0,0 @@
-From: Antonio Valentino <antonio.valentino at tiscali.it>
-Date: Wed, 17 Apr 2024 06:47:05 +0000
-Subject: Compatibility with numpy<2.0
-
-Forwarded: not-needed
----
- pyproject.toml | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/pyproject.toml b/pyproject.toml
-index 1152b73..59b58eb 100644
---- a/pyproject.toml
-+++ b/pyproject.toml
-@@ -1,5 +1,5 @@
- [build-system]
--requires = ["setuptools", "wheel", "numpy>=2.0.0rc1,<2.3", "Cython>=3", "versioneer[toml]"]
-+requires = ["setuptools", "wheel", "numpy<2.3", "Cython>=3", "versioneer[toml]"]
- build-backend = "setuptools.build_meta"
-
- [tool.ruff]
=====================================
debian/patches/0006-Use-sphinxcontrib.apidoc.patch → debian/patches/0005-Use-sphinxcontrib.apidoc.patch
=====================================
=====================================
debian/patches/series
=====================================
@@ -2,5 +2,4 @@
0002-Skip-test-on-deprecated-basemap.patch
0003-Fix-mathjax-path.patch
0004-Fix-privacy-breachs.patch
-0005-Compatibility-with-numpy-2.0.patch
-0006-Use-sphinxcontrib.apidoc.patch
+0005-Use-sphinxcontrib.apidoc.patch
=====================================
pyproject.toml
=====================================
@@ -1,5 +1,5 @@
[build-system]
-requires = ["setuptools", "wheel", "numpy>=2.0.0rc1,<2.3", "Cython>=3", "versioneer[toml]"]
+requires = ["setuptools", "wheel", "numpy>=2.0.0,<3", "Cython>=3.1", "versioneer[toml]"]
build-backend = "setuptools.build_meta"
[tool.ruff]
=====================================
pyresample/_formatting_html.py
=====================================
@@ -104,7 +104,7 @@ def plot_area_def(area: Union['geom.AreaDefinition', 'geom.SwathDefinition'], #
crs = cartopy.crs.Mercator()
fig, ax = plt.subplots(subplot_kw=dict(projection=crs))
- poly = Polygon(list(zip(lx[::-1], ly[::-1]))) # make lat/lon counterclockwise for shapely
+ poly = Polygon(list(zip(lx[::-1], ly[::-1], strict=True))) # make lat/lon counterclockwise for shapely
ax.add_geometries([poly], crs=cartopy.crs.CRS(area.crs), facecolor="none", edgecolor="red")
bounds = poly.buffer(5).bounds
ax.set_extent([bounds[0], bounds[2], bounds[1], bounds[3]], crs=cartopy.crs.CRS(area.crs))
=====================================
pyresample/_spatial_mp.py
=====================================
@@ -188,7 +188,7 @@ def _run_jobs(target, args, nprocs):
p.join()
if ierr.value != 0:
raise RuntimeError('%d errors in worker processes. Last one reported:\n%s' %
- (ierr.value, warn_msg.value._object_hook()))
+ (ierr.value, warn_msg.value))
# This is executed in an external process:
=====================================
pyresample/bilinear/xarr.py
=====================================
@@ -210,7 +210,7 @@ class XArrayBilinearResampler(BilinearBase):
def load_resampling_info(self, filename):
"""Load bilinear resampling look-up tables and initialize the resampler."""
try:
- fid = zarr.open(filename, 'r')
+ fid = zarr.open(filename, mode='r')
for val in BIL_COORDINATES:
cache = da.array(fid[val])
setattr(self, val, cache)
=====================================
pyresample/boundary/legacy_boundary.py
=====================================
@@ -45,8 +45,9 @@ class Boundary(object):
def contour_poly(self):
"""Get the Spherical polygon corresponding to the Boundary."""
if self._contour_poly is None:
+ # force 64-bit for more accuracy
self._contour_poly = SphPolygon(
- np.deg2rad(np.vstack(self.contour()).T))
+ np.deg2rad(np.vstack(self.contour()).T, dtype=np.float64))
return self._contour_poly
def draw(self, mapper, options, **more_options):
@@ -66,7 +67,7 @@ class AreaBoundary(Boundary):
if len(sides) != 4:
raise ValueError("AreaBoundary expects 4 sides.")
# Retrieve sides
- self.sides_lons, self.sides_lats = zip(*sides)
+ self.sides_lons, self.sides_lats = zip(*sides, strict=True)
self.sides_lons = list(self.sides_lons)
self.sides_lats = list(self.sides_lats)
@@ -81,7 +82,7 @@ class AreaBoundary(Boundary):
np.array([vmn, ..., vm1, vm0]),
np.array([vm0, ... ,v10, v00])]
"""
- boundary = cls(*zip(lon_sides, lat_sides))
+ boundary = cls(*zip(lon_sides, lat_sides, strict=True))
return boundary
def contour(self):
@@ -125,7 +126,7 @@ class AreaDefBoundary(AreaBoundary):
"Use the Swath/AreaDefinition 'boundary' method instead!.",
PendingDeprecationWarning, stacklevel=2)
AreaBoundary.__init__(self,
- *zip(lons, lats))
+ *zip(lons, lats, strict=True))
if frequency != 1:
self.decimate(frequency)
=====================================
pyresample/bucket/__init__.py
=====================================
@@ -145,7 +145,7 @@ class BucketResampler(object):
self.target_area = target_area
self.source_lons = source_lons
self.source_lats = source_lats
- self.prj = Proj(self.target_area.proj_dict)
+ self.prj = Proj(self.target_area.crs)
self.x_idxs = None
self.y_idxs = None
self.idxs = None
=====================================
pyresample/geometry.py
=====================================
@@ -1,7 +1,4 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-# Copyright (C) 2010-2023 Pyresample developers
+# Copyright (C) 2010-2025 Pyresample developers
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
@@ -143,7 +140,13 @@ class BaseDefinition:
return existing_hash
def __eq__(self, other):
- """Test for approximate equality."""
+ """Test for approximate equality.
+
+ Equality considers only the projection coordinates, not metadata such
+ as description or projection ID. In other words, areas are considered
+ equal if they produce approximately the same output when used for
+ resampling, within floating point tolerances.
+ """
if self is other:
return True
if not isinstance(other, BaseDefinition):
@@ -186,7 +189,7 @@ class BaseDefinition:
return lons, lats
def __ne__(self, other):
- """Test for approximate equality."""
+ """Test for approximate inequality."""
return not self.__eq__(other)
def get_area_extent_for_subset(self, row_LR, col_LR, row_UL, col_UL):
@@ -345,7 +348,8 @@ class BaseDefinition:
sides_dim1, sides_dim2 = zip(*[(top_dim1.squeeze(), top_dim2.squeeze()),
(right_dim1.squeeze(), right_dim2.squeeze()),
(bottom_dim1.squeeze(), bottom_dim2.squeeze()),
- (left_dim1.squeeze(), left_dim2.squeeze())])
+ (left_dim1.squeeze(), left_dim2.squeeze())],
+ strict=True)
if hasattr(sides_dim1[0], 'compute') and da is not None:
sides_dim1, sides_dim2 = da.compute(sides_dim1, sides_dim2)
return self._filter_sides_nans(sides_dim1, sides_dim2)
@@ -358,7 +362,7 @@ class BaseDefinition:
"""Remove nan and inf values present in each side."""
new_dim1_sides = []
new_dim2_sides = []
- for dim1_side, dim2_side in zip(dim1_sides, dim2_sides):
+ for dim1_side, dim2_side in zip(dim1_sides, dim2_sides, strict=True):
# FIXME: ~(~np.isfinite(dim1_side) | ~np.isfinite(dim1_side))
is_valid_mask = ~(np.isnan(dim1_side) | np.isnan(dim2_side))
if not is_valid_mask.any():
@@ -2109,7 +2113,12 @@ class AreaDefinition(_ProjectionDefinition):
return area_def_str
def __eq__(self, other):
- """Test for equality."""
+ """Test for equality.
+
+ Equality considers only the projection coordinates, not metadata such
+ as description or projection ID. In other words, areas are considered
+ equal if they produce the same output when used for resampling.
+ """
try:
return ((np.allclose(self.area_extent, other.area_extent)) and
(self.crs == other.crs) and
@@ -2118,7 +2127,7 @@ class AreaDefinition(_ProjectionDefinition):
return super().__eq__(other)
def __ne__(self, other):
- """Test for equality."""
+ """Test for inequality."""
return not self.__eq__(other)
def update_hash(self, existing_hash: Optional[hashlib._Hash] = None) -> hashlib._Hash:
=====================================
pyresample/resampler.py
=====================================
@@ -355,7 +355,7 @@ def crop_source_area(source_geo_def, target_geo_def):
def _enumerate_dst_area_chunks(dst_area, dst_chunks):
"""Enumerate the chunks in function of the dst_area."""
for position, slices in _enumerate_chunk_slices(dst_chunks):
- chunk_shape = tuple(chunk[pos] for pos, chunk in zip(position, dst_chunks))
+ chunk_shape = tuple(chunk[pos] for pos, chunk in zip(position, dst_chunks, strict=True))
target_geo_def = dst_area[slices[-2:]]
block_info = {"num-chunks": [len(chunk) for chunk in dst_chunks],
"chunk-location": position,
=====================================
pyresample/slicer.py
=====================================
@@ -105,7 +105,7 @@ class SwathSlicer(Slicer):
from shapely.geometry import Polygon
x, y = self.area_to_contain.get_edge_bbox_in_projection_coordinates(10)
- poly = Polygon(zip(*self._source_transformer.transform(x, y)))
+ poly = Polygon(zip(*self._source_transformer.transform(x, y), strict=True))
return poly
def get_slices_from_polygon(self, poly):
@@ -121,7 +121,7 @@ class SwathSlicer(Slicer):
@staticmethod
def _assemble_slices(chunk_slices):
"""Assemble slices to one slice per dimension."""
- lines, cols = zip(*chunk_slices)
+ lines, cols = zip(*chunk_slices, strict=True)
line_slice = slice(min(slc.start for slc in lines), max(slc.stop for slc in lines))
col_slice = slice(min(slc.start for slc in cols), max(slc.stop for slc in cols))
slices = col_slice, line_slice
@@ -132,7 +132,7 @@ class SwathSlicer(Slicer):
from shapely.geometry import Polygon
for (lons, lats), (line_slice, col_slice) in _get_chunk_bboxes_for_swath_to_crop(swath_to_crop):
- smaller_poly = Polygon(zip(*self._target_transformer.transform(lons, lats)))
+ smaller_poly = Polygon(zip(*self._target_transformer.transform(lons, lats), strict=True))
yield (smaller_poly, (line_slice, col_slice))
@@ -176,14 +176,14 @@ class AreaSlicer(Slicer):
if self.area_to_crop.is_geostationary:
x_geos, y_geos = get_geostationary_bounding_box_in_proj_coords(self.area_to_crop, 360)
x_geos, y_geos = self._source_transformer.transform(x_geos, y_geos, direction=TransformDirection.INVERSE)
- geos_poly = Polygon(zip(x_geos, y_geos))
- poly = Polygon(zip(x, y))
+ geos_poly = Polygon(zip(x_geos, y_geos, strict=True))
+ poly = Polygon(zip(x, y, strict=True))
poly = poly.intersection(geos_poly)
if poly.is_empty:
raise IncompatibleAreas("No slice on area.")
- x, y = zip(*poly.exterior.coords)
+ x, y = zip(*poly.exterior.coords, strict=True)
- return Polygon(zip(*self._source_transformer.transform(x, y)))
+ return Polygon(zip(*self._source_transformer.transform(x, y), strict=True))
def get_slices_from_polygon(self, poly_to_contain):
"""Get the slices based on the polygon."""
@@ -201,7 +201,9 @@ class AreaSlicer(Slicer):
raise InvalidArea("Invalid area") from err
from shapely.geometry import Polygon
- poly_to_crop = Polygon(zip(*self.area_to_crop.get_edge_bbox_in_projection_coordinates(frequency=10)))
+ poly_to_crop = Polygon(zip(
+ *self.area_to_crop.get_edge_bbox_in_projection_coordinates(frequency=10),
+ strict=True))
if not poly_to_crop.intersects(buffered_poly):
raise IncompatibleAreas("Areas not overlapping.")
bounds = self._sanitize_polygon_bounds(bounds)
@@ -238,7 +240,7 @@ def _enumerate_chunk_slices(chunks):
"""Enumerate chunks with slices."""
for position in np.ndindex(tuple(map(len, (chunks)))):
slices = []
- for pos, chunk in zip(position, chunks):
+ for pos, chunk in zip(position, chunks, strict=True):
chunk_size = chunk[pos]
offset = sum(chunk[:pos])
slices.append(slice(offset, offset + chunk_size))
=====================================
pyresample/spherical.py
=====================================
@@ -229,7 +229,7 @@ class SCoordinate(object):
def __iter__(self):
"""Get iterator over lon/lat pairs."""
- return zip([self.lon, self.lat]).__iter__()
+ return zip([self.lon, self.lat], strict=True).__iter__()
def plot(self, ax=None,
projection_crs=None,
=====================================
pyresample/spherical_utils.py
=====================================
@@ -82,7 +82,7 @@ class GetNonOverlapUnionsBaseClass():
return None
for id_, komb_pair in zip(itertools.combinations(geoms.keys(), 2),
- itertools.combinations(geoms.values(), 2)):
+ itertools.combinations(geoms.values(), 2), strict=True):
if self._overlaps(komb_pair[0], komb_pair[1]):
return id_, komb_pair[0].union(komb_pair[1])
=====================================
pyresample/test/test_boundary/test_legacy_boundary.py
=====================================
@@ -42,10 +42,10 @@ class TestAreaBoundary(unittest.TestCase):
boundary = AreaBoundary.from_lonlat_sides(lon_sides, lat_sides)
# Assert sides coincides
- for b_lon, src_lon in zip(boundary.sides_lons, lon_sides):
+ for b_lon, src_lon in zip(boundary.sides_lons, lon_sides, strict=True):
assert np.allclose(b_lon, src_lon)
- for b_lat, src_lat in zip(boundary.sides_lats, lat_sides):
+ for b_lat, src_lat in zip(boundary.sides_lats, lat_sides, strict=True):
assert np.allclose(b_lat, src_lat)
def test_creation(self):
@@ -61,10 +61,10 @@ class TestAreaBoundary(unittest.TestCase):
boundary = AreaBoundary(*list_sides)
# Assert sides coincides
- for b_lon, src_lon in zip(boundary.sides_lons, lon_sides):
+ for b_lon, src_lon in zip(boundary.sides_lons, lon_sides, strict=True):
assert np.allclose(b_lon, src_lon)
- for b_lat, src_lat in zip(boundary.sides_lats, lat_sides):
+ for b_lat, src_lat in zip(boundary.sides_lats, lat_sides, strict=True):
assert np.allclose(b_lat, src_lat)
def test_number_sides_required(self):
@@ -108,3 +108,25 @@ class TestAreaBoundary(unittest.TestCase):
lons, lats = boundary.contour()
assert np.allclose(lons, np.array([1., 1.5, 2., 3., 3.5, 4.]))
assert np.allclose(lats, np.array([6., 6.5, 7., 8., 8.5, 9.]))
+
+ def test_countour_poly_north_pole(self):
+ """Test that a polygon can be made with 32-bit north pole coordinates.
+
+ In a real world case, 32-bit geolocation including a point at exactly the
+ north pole lead to a validity check failure because the radians value for
+ 90N was just barely above pi / 2.
+
+ """
+ list_sides = [
+ (np.array([1., 1.5, 2.], dtype=np.float32), np.array([87.0, 87.5, 88.0], dtype=np.float32)),
+ (np.array([2., 3.], dtype=np.float32), np.array([88.0, 89.0], dtype=np.float32)),
+ (np.array([3., 3.5, 4.], dtype=np.float32), np.array([89., 89.5, 90.0], dtype=np.float32)),
+ (np.array([4., 1.], dtype=np.float32), np.array([90.0, 87.0], dtype=np.float32)),
+ ]
+ boundary = AreaBoundary(*list_sides)
+ poly = boundary.contour_poly
+ # validity checks happen here:
+ aedges = list(poly.aedges())
+ # ensure 90 degree latitude coordinate is retained
+ np.testing.assert_allclose(aedges[4].end.lat, np.radians(90.0))
+ np.testing.assert_allclose(aedges[5].start.lat, np.radians(90.0))
=====================================
pyresample/test/test_geometry/test_swath_boundary.py
=====================================
@@ -138,7 +138,7 @@ def _check_bbox_structure_and_values(bbox_lons, bbox_lats):
assert not any(np.isnan(side_lat).any() for side_lat in bbox_lats)
assert len(bbox_lons) == len(bbox_lats)
assert len(bbox_lons) == 4
- for side_lons, side_lats in zip(bbox_lons, bbox_lats):
+ for side_lons, side_lats in zip(bbox_lons, bbox_lats, strict=True):
assert isinstance(side_lons, np.ndarray)
assert isinstance(side_lats, np.ndarray)
assert side_lons.shape == side_lats.shape
@@ -163,7 +163,7 @@ def _is_clockwise(lons, lats):
# https://stackoverflow.com/a/1165943/433202
prev_point = (lons[0], lats[0])
edge_sum = 0
- for point in zip(lons[1:], lats[1:]):
+ for point in zip(lons[1:], lats[1:], strict=True):
xdiff = point[0] - prev_point[0]
ysum = point[1] + prev_point[1]
edge_sum += xdiff * ysum
=====================================
pyresample/utils/proj4.py
=====================================
@@ -150,7 +150,7 @@ class DaskFriendlyTransformer:
crs_from.to_wkt(), crs_to.to_wkt(),
dtype=np.float64, chunks=x.chunks + ((num_results,),),
meta=np.array((), dtype=np.float64),
- name="transform_coords",
+ token="transform_coords", # nosec: B106
kwargs=self.kwargs,
transform_kwargs=kwargs,
new_axis=x.ndim)
=====================================
pyresample/version.py
=====================================
@@ -26,9 +26,9 @@ def get_keywords() -> Dict[str, str]:
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
- git_refnames = " (tag: v1.34.2)"
- git_full = "47f3fae0d2517249539c25b04bec2a9b08018125"
- git_date = "2025-05-29 09:23:56 -0500"
+ git_refnames = " (HEAD -> main, tag: v1.35.0)"
+ git_full = "9c14be4cc720514991028ddb2a7a93152a8cf930"
+ git_date = "2025-12-01 20:45:30 -0600"
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
return keywords
=====================================
setup.py
=====================================
@@ -25,13 +25,10 @@ from setuptools import find_packages, setup
import versioneer
requirements = ['pyproj>=3.0', 'configobj',
- 'pykdtree>=1.3.1', 'pyyaml', 'numpy>=1.21.0',
+ 'pykdtree>=1.3.1', 'pyyaml', 'numpy>=1.25.0',
"shapely", "donfig", "platformdirs",
]
-if sys.version_info < (3, 10):
- requirements.append('importlib_metadata')
-
test_requires = ['rasterio', 'dask', 'xarray', 'cartopy>=0.20.0', 'pillow', 'matplotlib', 'scipy', 'zarr',
'pytest-lazy-fixtures', 'shapely', 'odc-geo']
extras_require = {'numexpr': ['numexpr'],
@@ -58,8 +55,8 @@ extensions = [
Extension("pyresample.ewa._ll2cr", sources=["pyresample/ewa/_ll2cr.pyx"],
include_dirs=[np.get_include()],
extra_compile_args=extra_compile_args,
- cython_directives={"language_level": 3},
- define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
+ cython_directives={"language_level": 3, "freethreading_compatible": True},
+ define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_25_API_VERSION")],
),
Extension("pyresample.ewa._fornav",
sources=["pyresample/ewa/_fornav.pyx",
@@ -67,15 +64,15 @@ extensions = [
include_dirs=[np.get_include()],
language="c++", extra_compile_args=extra_compile_args,
depends=["pyresample/ewa/_fornav_templates.h"],
- cython_directives={"language_level": 3},
- define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
+ cython_directives={"language_level": 3, "freethreading_compatible": True},
+ define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_25_API_VERSION")],
),
Extension("pyresample.gradient._gradient_search",
sources=["pyresample/gradient/_gradient_search.pyx"],
include_dirs=[np.get_include()],
extra_compile_args=extra_compile_args,
- cython_directives={"language_level": 3},
- define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
+ cython_directives={"language_level": 3, "freethreading_compatible": True},
+ define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_25_API_VERSION")],
),
]
@@ -109,13 +106,15 @@ if __name__ == "__main__":
ext_modules=extensions,
entry_points=entry_points,
zip_safe=False,
+ license="LGPL-3.0-or-later",
+ license_files=["LICENSE.txt"],
classifiers=[
'Development Status :: 5 - Production/Stable',
- 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)',
'Programming Language :: Python',
'Programming Language :: Cython',
'Operating System :: OS Independent',
'Intended Audience :: Science/Research',
- 'Topic :: Scientific/Engineering'
+ 'Topic :: Scientific/Engineering',
+ 'Programming Language :: Python :: Free Threading :: 1 - Unstable',
]
)
View it on GitLab: https://salsa.debian.org/debian-gis-team/pyresample/-/compare/9aa2b6ba27b5461f77f60eca16a81349dcd52e09...baeb028abe53301281b06557cd1d3f0d925ed98b
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/pyresample/-/compare/9aa2b6ba27b5461f77f60eca16a81349dcd52e09...baeb028abe53301281b06557cd1d3f0d925ed98b
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20251210/ad70e8fa/attachment-0001.htm>
More information about the Pkg-grass-devel
mailing list