[Git][debian-gis-team/python-pyproj][upstream] New upstream version 3.7.1~rc0

Bas Couwenberg (@sebastic) gitlab at salsa.debian.org
Sat Feb 15 06:38:03 GMT 2025



Bas Couwenberg pushed to branch upstream at Debian GIS Project / python-pyproj


Commits:
22cef166 by Bas Couwenberg at 2025-02-15T07:30:48+01:00
New upstream version 3.7.1~rc0
- - - - -


30 changed files:

- .github/workflows/build_docs.yaml
- .github/workflows/release.yaml
- .github/workflows/test_proj_latest.yaml
- .github/workflows/tests.yaml
- .pre-commit-config.yaml
- HOW_TO_RELEASE.md
- ci/proj-compile-wheels.sh
- ci/vcpkg.json
- docs/history.rst
- docs/index.rst
- docs/past_versions.rst
- pyproj/__init__.py
- pyproj/_crs.pyi
- pyproj/_crs.pyx
- pyproj/_geod.pyi
- pyproj/_geod.pyx
- pyproj/_transformer.pyi
- pyproj/_transformer.pyx
- pyproj/aoi.py
- pyproj/crs/coordinate_operation.py
- pyproj/crs/crs.py
- pyproj/database.pyx
- pyproj/geod.py
- pyproj/sync.py
- pyproj/transformer.py
- pyproject.toml
- test/crs/test_crs_cf.py
- test/crs/test_crs_coordinate_system.py
- test/test_proj.py
- test/test_sync.py


Changes:

=====================================
.github/workflows/build_docs.yaml
=====================================
@@ -21,7 +21,7 @@ jobs:
           persist-credentials: false
 
       - name: Setup Conda
-        uses: mamba-org/setup-micromamba at v1
+        uses: mamba-org/setup-micromamba at v2
         with:
           init-shell: bash
           environment-name: docs


=====================================
.github/workflows/release.yaml
=====================================
@@ -15,7 +15,7 @@ concurrency:
   cancel-in-progress: true
 
 env:
-  PROJ_VERSION: "9.4.1"
+  PROJ_VERSION: "9.5.1"
   DEBIAN_FRONTEND: noninteractive
 
 jobs:
@@ -26,7 +26,7 @@ jobs:
       - uses: actions/checkout at v4
 
       - name: Setup Conda
-        uses: mamba-org/setup-micromamba at v1
+        uses: mamba-org/setup-micromamba at v2
         with:
           init-shell: bash
           environment-name: sdist_env
@@ -64,12 +64,12 @@ jobs:
         include:
         - os: ubuntu-22.04
           arch: x86_64
-        # - os: ubuntu-22.04
-        #   arch: i686
-        - os: macos-12
+        - os: ubuntu-22.04-arm
+          arch: aarch64
+        - os: macos-13
           arch: x86_64
           cmake_osx_architectures: x86_64
-          macos_deployment_target: "12.0"
+          macos_deployment_target: "13.0"
         - os: macos-14
           arch: arm64
           cmake_osx_architectures: arm64
@@ -125,9 +125,9 @@ jobs:
           cp "$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }}/share/proj/"* ${GITHUB_WORKSPACE}/pyproj/proj_dir/share/proj/
 
       - name: Build wheels
-        uses: pypa/cibuildwheel at v2.21
+        uses: pypa/cibuildwheel at v2.22
         env:
-          CIBW_SKIP: "*musllinux* pp*-win* pp31*"
+          CIBW_SKIP: "pp*-win* pp31*"
           CIBW_ARCHS: ${{ matrix.arch }}
           CIBW_ENVIRONMENT_LINUX:
             PROJ_WHEEL=true
@@ -185,7 +185,12 @@ jobs:
       - uses: actions/download-artifact at v4
         continue-on-error: ${{ github.event_name == 'push' && github.ref_type != 'tag' }}
         with:
-          name: wheels-macos-12-x86_64
+          name: wheels-ubuntu-22.04-arm-aarch64
+          path: dist
+      - uses: actions/download-artifact at v4
+        continue-on-error: ${{ github.event_name == 'push' && github.ref_type != 'tag' }}
+        with:
+          name: wheels-macos-13-x86_64
           path: dist
       - uses: actions/download-artifact at v4
         continue-on-error: ${{ github.event_name == 'push' && github.ref_type != 'tag' }}


=====================================
.github/workflows/test_proj_latest.yaml
=====================================
@@ -1,4 +1,4 @@
-name: Test PROJ Latest
+name: Test PROJ and Cython Latest
 
 on:
   push:
@@ -41,7 +41,7 @@ jobs:
         shell: bash
         run: |
           python -V
-          python -m pip install cython
+          python -m pip install --upgrade --pre --only-binary :all: -i https://pypi.anaconda.org/scientific-python-nightly-wheels/simple cython
           python -m pip install -e .
           python -m pip install -r requirements-test.txt
           pyproj -v


=====================================
.github/workflows/tests.yaml
=====================================
@@ -117,7 +117,7 @@ jobs:
       - uses: actions/checkout at v4
 
       - name: Setup Conda
-        uses: mamba-org/setup-micromamba at v1
+        uses: mamba-org/setup-micromamba at v2
         with:
           # https://github.com/mamba-org/setup-micromamba/issues/225
           micromamba-version: 1.5.10-0
@@ -198,4 +198,4 @@ jobs:
           micromamba run -n test sphinx-build -b html docs/ docs/_build/
           micromamba run -n test sphinx-build -b man docs/ docs/_build/
 
-      - uses: codecov/codecov-action at v4
+      - uses: codecov/codecov-action at v5


=====================================
.pre-commit-config.yaml
=====================================
@@ -37,3 +37,7 @@ repos:
         rev: v2.2.6
         hooks:
         -   id: codespell
+    -   repo: https://github.com/astral-sh/ruff-pre-commit
+        rev: v0.7.1
+        hooks:
+        - id: ruff


=====================================
HOW_TO_RELEASE.md
=====================================
@@ -18,10 +18,9 @@ The next step is to create a tag with the same name as the version just added. T
 
 ### Test the release builds
 
-1. Create a draft PR at https://github.com/pyproj4/pyproj-wheels and verify tests pass.
+1. Check the wheels built at https://github.com/pyproj4/pyproj using GitHub Actions.
 2. Create a draft PR at https://github.com/conda-forge/pyproj-feedstock and verify tests pass.
-3. Check the wheels built at https://github.com/pyproj4/pyproj using GitHub Actions.
-4. Verify Debian builds were successful.
+3. Verify Debian builds were successful.
 4. Verify Fedora builds were successful.
 5. Verify the docs build successfully.
 
@@ -41,10 +40,7 @@ Next, go through the history and add release notes (see: [automatically generate
 
 ### The wheels
 
-Most of the wheels are tested with each merge to main and uploaded to pypi on release in GitHub Actions. However, the arm64 wheels are built separately. This provides instructions for those wheels:
-
-1. linux arm64: Update the PR at https://github.com/pyproj4/pyproj-wheels with the release tag & merge. The wheels will automatically upload to pypi when the CI runs succeed.
-2. macos arm64: Download the release wheel artifacts from the Cirrus CI build and upload manually to pypi.
+The wheels are tested with each merge to main and uploaded to https://pypi.anaconda.org/scientific-python-nightly-wheels/simple in GitHub Actions. They are uploaded to pypi on pre-release and release in GitHub Actions.
 
 ### Verify conda-forge build is correct
 


=====================================
ci/proj-compile-wheels.sh
=====================================
@@ -19,6 +19,10 @@ if [ $(uname) == "Darwin" ]; then
   IS_MACOS=1;
 fi
 
+if [ -f /etc/alpine-release ]; then
+  IS_ALPINE=1
+fi
+
 if [ -z "$IS_MACOS" ]; then
     # Strip all binaries after compilation.
     STRIP_FLAGS=${STRIP_FLAGS:-"-Wl,-strip-all"}
@@ -100,6 +104,8 @@ function install_rsync {
     if [ -n "$IS_MACOS" ]; then
         # macOS. The colon in the next line is the null command
         :
+    elif [ -n "$IS_ALPINE" ]; then
+        [[ $(type -P rsync) ]] || apk add rsync
     elif [[ $MB_ML_VER == "_2_24" ]]; then
         # debian:9 based distro
         [[ $(type -P rsync) ]] || apt-get install -y rsync
@@ -177,6 +183,7 @@ function build_simple {
 
 function get_modern_cmake {
     # Install cmake >= 2.8
+    if [ -n "$IS_ALPINE" ]; then return; fi  # alpine has modern cmake already
     local cmake=cmake
     if [ -n "$IS_MACOS" ]; then
         brew install cmake > /dev/null
@@ -196,6 +203,7 @@ function get_modern_cmake {
 function build_zlib {
     # Gives an old but safe version
     if [ -n "$IS_MACOS" ]; then return; fi  # OSX has zlib already
+    if [ -n "$IS_ALPINE" ]; then return; fi  # alpine has zlib already
     if [ -e zlib-stamp ]; then return; fi
     if [[ $MB_ML_VER == "_2_24" ]]; then
         # debian:9 based distro
@@ -209,6 +217,7 @@ function build_zlib {
 
 function build_perl {
     if [ -n "$IS_MACOS" ]; then return; fi  # OSX has perl already
+    if [ -n "$IS_ALPINE" ]; then return; fi  # alpine has perl already
     if [ -e perl-stamp ]; then return; fi
     if [[ $MB_ML_VER == "_2_24" ]]; then
         # debian:9 based distro


=====================================
ci/vcpkg.json
=====================================
@@ -1,11 +1,11 @@
 {
     "name": "pyproj",
-    "version": "3.7.0",
+    "version": "3.7.1",
     "dependencies": [
         {
             "name": "proj",
-            "version>=": "9.4.1"
+            "version>=": "9.5.1"
         }
     ],
-    "builtin-baseline": "513aa7ceb3b5e9bf90882cb7edc06c9d5efcf0ee"
+    "builtin-baseline": "4ec74919dbf24931b29347b000c74374e8bbde35"
 }


=====================================
docs/history.rst
=====================================
@@ -1,6 +1,16 @@
 Change Log
 ==========
 
+3.7.1
+------
+- WHL: Add wheels for musllinux (pull #1461)
+- WHL: MacOS minimum deployment target moved to 13 (pull #1475)
+- WHL: Wheels contain PROJ 9.5.1 (pull #1477)
+- Cython 3.1+ fixes (pull #1452)
+- TST: remove checking is python >= 3.4 (pull #1446)
+- TST: Add assert statements at the end of tests (pull #1453)
+- LNT: Setup ruff & lint fixes (pull #1455 #1456)
+
 3.7.0
 ------
 - WHL: Wheels contain PROJ 9.4.1 (pull #1423)


=====================================
docs/index.rst
=====================================
@@ -5,7 +5,7 @@ Python interface to  `PROJ <https://proj.org/>`_ (cartographic projections and c
 
 GitHub Repository: https://github.com/pyproj4/pyproj
 
-.. note:: Minimum supported PROJ version is 9.0
+.. note:: Minimum supported PROJ version is 9.2
 
 .. note:: Minimum supported Python version is 3.10
 


=====================================
docs/past_versions.rst
=====================================
@@ -1,6 +1,7 @@
 Documentation Archive
 =====================
 
+- `3.7.0 <https://pyproj4.github.io/pyproj/3.7.0/>`_
 - `3.6.1 <https://pyproj4.github.io/pyproj/3.6.1/>`_
 - `3.5.0 <https://pyproj4.github.io/pyproj/3.5.0/>`_
 - `3.4.1 <https://pyproj4.github.io/pyproj/3.4.1/>`_


=====================================
pyproj/__init__.py
=====================================
@@ -71,7 +71,7 @@ from pyproj.transformer import (  # noqa: F401 pylint: disable=unused-import
     transform,
 )
 
-__version__ = "3.7.0"
+__version__ = "3.7.1rc0"
 __all__ = [
     "Proj",
     "Geod",


=====================================
pyproj/_crs.pyi
=====================================
@@ -12,8 +12,6 @@ class Axis:
     unit_name: str
     unit_auth_code: str
     unit_code: str
-    def __str__(self) -> str: ...
-    def __repr__(self) -> str: ...
 
 class AreaOfUse:
     west: float
@@ -21,8 +19,6 @@ class AreaOfUse:
     east: float
     north: float
     name: str
-    def __str__(self) -> str: ...
-    def __repr__(self) -> str: ...
     @property
     def bounds(self) -> tuple[float, float, float, float]: ...
 
@@ -40,14 +36,12 @@ class Base:
     ) -> str: ...
     def to_json(self, pretty: bool = False, indentation: int = 2) -> str: ...
     def to_json_dict(self) -> dict: ...
-    def __str__(self) -> str: ...
-    def __repr__(self) -> str: ...
-    def __eq__(self, other: Any) -> bool: ...
+    def __eq__(self, other: object) -> bool: ...
     def is_exact_same(self, other: Any) -> bool: ...
 
 class _CRSParts(Base):
     @classmethod
-    def from_user_input(cls, user_input: Any) -> "_CRSParts": ...
+    def from_user_input(cls, user_input: Any) -> _CRSParts: ...
 
 class Ellipsoid(_CRSParts):
     semi_major_metre: float
@@ -55,36 +49,36 @@ class Ellipsoid(_CRSParts):
     is_semi_minor_computed: float
     inverse_flattening: float
     @staticmethod
-    def from_authority(auth_name: str, code: int | str) -> "Ellipsoid": ...
+    def from_authority(auth_name: str, code: int | str) -> Ellipsoid: ...
     @staticmethod
-    def from_epsg(code: int | str) -> "Ellipsoid": ...
+    def from_epsg(code: int | str) -> Ellipsoid: ...
     @staticmethod
-    def from_string(ellipsoid_string: str) -> "Ellipsoid": ...
+    def from_string(ellipsoid_string: str) -> Ellipsoid: ...
     @staticmethod
-    def from_json_dict(ellipsoid_dict: dict) -> "Ellipsoid": ...
+    def from_json_dict(ellipsoid_dict: dict) -> Ellipsoid: ...
     @staticmethod
-    def from_json(ellipsoid_json_str: str) -> "Ellipsoid": ...
+    def from_json(ellipsoid_json_str: str) -> Ellipsoid: ...
     @staticmethod
-    def from_name(ellipsoid_name: str, auth_name: str | None = None) -> "Ellipsoid": ...
+    def from_name(ellipsoid_name: str, auth_name: str | None = None) -> Ellipsoid: ...
 
 class PrimeMeridian(_CRSParts):
     longitude: float
     unit_conversion_factor: str
     unit_name: str
     @staticmethod
-    def from_authority(auth_name: str, code: int | str) -> "PrimeMeridian": ...
+    def from_authority(auth_name: str, code: int | str) -> PrimeMeridian: ...
     @staticmethod
-    def from_epsg(code: int | str) -> "PrimeMeridian": ...
+    def from_epsg(code: int | str) -> PrimeMeridian: ...
     @staticmethod
-    def from_string(prime_meridian_string: str) -> "PrimeMeridian": ...
+    def from_string(prime_meridian_string: str) -> PrimeMeridian: ...
     @staticmethod
-    def from_json_dict(prime_meridian_dict: dict) -> "PrimeMeridian": ...
+    def from_json_dict(prime_meridian_dict: dict) -> PrimeMeridian: ...
     @staticmethod
-    def from_json(prime_meridian_json_str: str) -> "PrimeMeridian": ...
+    def from_json(prime_meridian_json_str: str) -> PrimeMeridian: ...
     @staticmethod
     def from_name(
         prime_meridian_name: str, auth_name: str | None = None
-    ) -> "PrimeMeridian": ...
+    ) -> PrimeMeridian: ...
 
 class Datum(_CRSParts):
     type_name: str
@@ -93,28 +87,28 @@ class Datum(_CRSParts):
     @property
     def prime_meridian(self) -> PrimeMeridian | None: ...
     @staticmethod
-    def from_authority(auth_name: str, code: int | str) -> "Datum": ...
+    def from_authority(auth_name: str, code: int | str) -> Datum: ...
     @staticmethod
-    def from_epsg(code: int | str) -> "Datum": ...
+    def from_epsg(code: int | str) -> Datum: ...
     @staticmethod
-    def from_string(datum_string: str) -> "Datum": ...
+    def from_string(datum_string: str) -> Datum: ...
     @staticmethod
-    def from_json_dict(datum_dict: dict) -> "Datum": ...
+    def from_json_dict(datum_dict: dict) -> Datum: ...
     @staticmethod
-    def from_json(datum_json_str: str) -> "Datum": ...
+    def from_json(datum_json_str: str) -> Datum: ...
     @staticmethod
-    def from_name(datum_name: str, auth_name: str | None = None) -> "Datum": ...
+    def from_name(datum_name: str, auth_name: str | None = None) -> Datum: ...
 
 class CoordinateSystem(_CRSParts):
     def __init__(self) -> None: ...
     @property
     def axis_list(self) -> Iterable[Axis]: ...
     @staticmethod
-    def from_string(coordinate_system_string: str) -> "CoordinateSystem": ...
+    def from_string(coordinate_system_string: str) -> CoordinateSystem: ...
     @staticmethod
-    def from_json_dict(coordinate_system_dict: dict) -> "CoordinateSystem": ...
+    def from_json_dict(coordinate_system_dict: dict) -> CoordinateSystem: ...
     @staticmethod
-    def from_json(coordinate_system_json_str: str) -> "CoordinateSystem": ...
+    def from_json(coordinate_system_json_str: str) -> CoordinateSystem: ...
     def to_cf(self, rotated_pole: bool = False) -> list[dict]: ...
 
 class Param:
@@ -127,8 +121,6 @@ class Param:
     unit_auth_name: str
     unit_code: str
     unit_category: str
-    def __str__(self) -> str: ...
-    def __repr__(self) -> str: ...
 
 class Grid:
     short_name: str
@@ -138,8 +130,6 @@ class Grid:
     direct_download: str
     open_license: str
     available: str
-    def __str__(self) -> str: ...
-    def __repr__(self) -> str: ...
 
 class CoordinateOperation(_CRSParts):
     method_name: str
@@ -158,19 +148,18 @@ class CoordinateOperation(_CRSParts):
     @property
     def towgs84(self) -> Iterable[float]: ...
     @property
-    def operations(self) -> tuple["CoordinateOperation"]: ...
+    def operations(self) -> tuple[CoordinateOperation]: ...
     def __init__(self) -> None: ...
-    def __repr__(self) -> str: ...
     @staticmethod
-    def from_authority(auth_name: str, code: int | str) -> "CoordinateOperation": ...
+    def from_authority(auth_name: str, code: int | str) -> CoordinateOperation: ...
     @staticmethod
-    def from_epsg(code: int | str) -> "CoordinateOperation": ...
+    def from_epsg(code: int | str) -> CoordinateOperation: ...
     @staticmethod
-    def from_string(ellipsoid_string: str) -> "CoordinateOperation": ...
+    def from_string(ellipsoid_string: str) -> CoordinateOperation: ...
     @staticmethod
-    def from_json_dict(ellipsoid_dict: dict) -> "CoordinateOperation": ...
+    def from_json_dict(ellipsoid_dict: dict) -> CoordinateOperation: ...
     @staticmethod
-    def from_json(ellipsoid_json_str: str) -> "CoordinateOperation": ...
+    def from_json(ellipsoid_json_str: str) -> CoordinateOperation: ...
     def to_proj4(self, version: ProjVersion | int = ProjVersion.PROJ_5) -> str: ...
     @staticmethod
     def from_name(
@@ -179,7 +168,7 @@ class CoordinateOperation(_CRSParts):
         coordinate_operation_type: (
             CoordinateOperationType | str
         ) = CoordinateOperationType.CONVERSION,
-    ) -> "CoordinateOperation": ...
+    ) -> CoordinateOperation: ...
 
 class AuthorityMatchInfo(NamedTuple):
     auth_name: str
@@ -201,13 +190,13 @@ class _CRS(Base):
     @property
     def datum(self) -> Datum | None: ...
     @property
-    def sub_crs_list(self) -> Iterable["_CRS"]: ...
+    def sub_crs_list(self) -> Iterable[_CRS]: ...
     @property
-    def source_crs(self) -> Optional["_CRS"]: ...
+    def source_crs(self) -> Optional[_CRS]: ...
     @property
-    def target_crs(self) -> Optional["_CRS"]: ...
+    def target_crs(self) -> Optional[_CRS]: ...
     @property
-    def geodetic_crs(self) -> Optional["_CRS"]: ...
+    def geodetic_crs(self) -> Optional[_CRS]: ...
     @property
     def coordinate_system(self) -> CoordinateSystem | None: ...
     @property
@@ -218,8 +207,8 @@ class _CRS(Base):
     def list_authority(
         self, auth_name: str | None = None, min_confidence: int = 70
     ) -> list[AuthorityMatchInfo]: ...
-    def to_3d(self, name: str | None = None) -> "_CRS": ...
-    def to_2d(self, name: str | None = None) -> "_CRS": ...
+    def to_3d(self, name: str | None = None) -> _CRS: ...
+    def to_2d(self, name: str | None = None) -> _CRS: ...
     @property
     def is_geographic(self) -> bool: ...
     @property
@@ -237,7 +226,7 @@ class _CRS(Base):
     def equals(self, other: Any, ignore_axis_order: bool) -> bool: ...
     @property
     def is_deprecated(self) -> bool: ...
-    def get_non_deprecated(self) -> list["_CRS"]: ...
+    def get_non_deprecated(self) -> list[_CRS]: ...
 
 def is_proj(proj_string: str) -> bool: ...
 def is_wkt(proj_string: str) -> bool: ...


=====================================
pyproj/_crs.pyx
=====================================
@@ -2352,13 +2352,13 @@ cdef class _CRS(Base):
         self._coordinate_operation = None
         self._type_name = None
 
-    def __init__(self, const char *proj_string):
+    def __init__(self, str proj_string):
         self.context = pyproj_context_create()
         self._context_manager = get_context_manager()
         # initialize projection
         self.projobj = proj_create(
             self.context,
-            proj_string,
+            cstrencode(proj_string),
         )
         if self.projobj == NULL:
             raise CRSError(f"Invalid projection: {proj_string}")


=====================================
pyproj/_geod.pyi
=====================================
@@ -20,8 +20,7 @@ class Geod:
     def __init__(
         self, a: float, f: float, sphere: bool, b: float, es: float
     ) -> None: ...
-    def __reduce__(self) -> tuple[type["Geod"], str]: ...
-    def __repr__(self) -> str: ...
+    def __reduce__(self) -> tuple[type[Geod], str]: ...
     def _fwd(
         self,
         lons: Any,


=====================================
pyproj/_geod.pyx
=====================================
@@ -90,10 +90,7 @@ cdef class Geod:
         geod_init(&self._geod_geodesic, <double> a, <double> f)
         self.a = a
         self.f = f
-        # convert 'a' only for initstring
-        a_str = int(a) if a.is_integer() else a
-        f_str = int(f) if f.is_integer() else f
-        self.initstring = f"+a={a_str} +f={f_str}"
+        self.initstring = f"+{a=} +{f=}"
         self.sphere = sphere
         self.b = b
         self.es = es


=====================================
pyproj/_transformer.pyi
=====================================
@@ -83,9 +83,9 @@ class _Transformer(Base):
         allow_ballpark: bool | None = None,
         force_over: bool = False,
         only_best: bool | None = None,
-    ) -> "_Transformer": ...
+    ) -> _Transformer: ...
     @staticmethod
-    def from_pipeline(proj_pipeline: bytes) -> "_Transformer": ...
+    def from_pipeline(proj_pipeline: bytes) -> _Transformer: ...
     def _transform(
         self,
         inx: Any,


=====================================
pyproj/_transformer.pyx
=====================================
@@ -151,7 +151,8 @@ cdef class _TransformerGroup:
             double north_lat_degree
 
         if authority is not None:
-            c_authority = authority
+            tmp = cstrencode(authority)
+            c_authority = tmp
 
         try:
             operation_factory_context = proj_create_operation_factory_context(


=====================================
pyproj/aoi.py
=====================================
@@ -69,7 +69,7 @@ class AreaOfUse(NamedTuple):
         return self.west, self.south, self.east, self.north
 
     def __str__(self) -> str:
-        return f"- name: {self.name}\n" f"- bounds: {self.bounds}"
+        return f"- name: {self.name}\n- bounds: {self.bounds}"
 
 
 @dataclass


=====================================
pyproj/crs/coordinate_operation.py
=====================================
@@ -604,7 +604,7 @@ class LambertCylindricalEqualAreaScaleConversion(CoordinateOperation):
             f"+k_0={scale_factor_natural_origin}"
         )
         return cls.from_json(
-            CRS(proj_string).coordinate_operation.to_json()  # type: ignore
+            CRS(proj_string).coordinate_operation.to_json()  # type: ignore[union-attr]
         )
 
 


=====================================
pyproj/crs/crs.py
=====================================
@@ -334,7 +334,7 @@ class CRS:
             elif isinstance(projparams, (list, tuple)) and len(projparams) == 2:
                 projstring = _prepare_from_authority(*projparams)
             elif hasattr(projparams, "to_wkt"):
-                projstring = projparams.to_wkt()  # type: ignore
+                projstring = projparams.to_wkt()
             else:
                 raise CRSError(f"Invalid CRS input: {projparams!r}")
 
@@ -1590,7 +1590,7 @@ class CRS:
         """
         return self._crs.get_non_deprecated()
 
-    def __eq__(self, other: Any) -> bool:
+    def __eq__(self, other: object) -> bool:
         return self.equals(other)
 
     def __getstate__(self) -> dict[str, str]:


=====================================
pyproj/database.pyx
=====================================
@@ -460,7 +460,7 @@ def get_database_metadata(str key not None):
     cdef const char* metadata = NULL
     metadata = proj_context_get_database_metadata(
         pyproj_context_create(),
-        cstrdecode(key),
+        cstrencode(key),
     )
     if metadata == NULL:
         return None


=====================================
pyproj/geod.py
=====================================
@@ -1003,7 +1003,7 @@ class Geod(_Geod):
             The total geodesic length of the geometry (meters).
         """
         try:
-            return self.line_length(*geometry.xy, radians=radians)  # type: ignore
+            return self.line_length(*geometry.xy, radians=radians)  # type: ignore[misc]
         except (AttributeError, NotImplementedError):
             pass
         if hasattr(geometry, "exterior"):
@@ -1074,7 +1074,7 @@ class Geod(_Geod):
             The geodesic area (meters^2) and perimeter (meters) of the polygon.
         """
         try:
-            return self.polygon_area_perimeter(  # type: ignore
+            return self.polygon_area_perimeter(  # type: ignore[misc]
                 *geometry.xy, radians=radians
             )
         except (AttributeError, NotImplementedError):
@@ -1114,7 +1114,7 @@ class Geod(_Geod):
         # no ellipse name found, call super class
         return super().__repr__()
 
-    def __eq__(self, other: Any) -> bool:
+    def __eq__(self, other: object) -> bool:
         """
         equality operator == for Geod objects
 


=====================================
pyproj/sync.py
=====================================
@@ -30,6 +30,8 @@ def _bbox_from_coords(coords: list) -> BBox | None:
     coord_bbox = None
     for coord_set in coords:
         bbox = _bbox_from_coords(coord_set)
+        if bbox is None:
+            continue
         if coord_bbox is None:
             coord_bbox = bbox
         else:
@@ -199,8 +201,7 @@ def _load_grid_geojson(target_directory: str | Path | None = None) -> dict[str,
         target_directory = get_user_data_dir(True)
     local_path = Path(target_directory, "files.geojson")
     if not local_path.exists() or (
-        (datetime.utcnow() - datetime.fromtimestamp(local_path.stat().st_mtime)).days
-        > 0
+        (datetime.now() - datetime.fromtimestamp(local_path.stat().st_mtime)).days > 0
     ):
         _download_resource_file(
             file_url=f"{get_proj_endpoint()}/files.geojson",


=====================================
pyproj/transformer.py
=====================================
@@ -1167,7 +1167,7 @@ class Transformer:
             f"Area of Use:\n{self.area_of_use or '- undefined'}"
         )
 
-    def __eq__(self, other: Any) -> bool:
+    def __eq__(self, other: object) -> bool:
         if not isinstance(other, Transformer):
             return False
         return self._transformer.__eq__(other._transformer)


=====================================
pyproject.toml
=====================================
@@ -64,3 +64,99 @@ version = {attr = "pyproj.__version__"}
 
 [tool.black]
 target_version = ["py310"]
+
+[tool.ruff]
+line-length = 88
+target-version = "py310"
+fix = true
+
+[tool.ruff.lint]
+unfixable = []
+
+select = [
+  # pyflakes
+  "F",
+  # pycodestyle
+  "E", "W",
+  # flake8-2020
+  "YTT",
+  # flake8-bugbear
+  "B",
+  # flake8-quotes
+  "Q",
+  # flake8-debugger
+  "T10",
+  # flake8-gettext
+  "INT",
+  # pylint
+#   "PL",
+  # flake8-pytest-style
+#   "PT",
+  # misc lints
+  "PIE",
+  # flake8-pyi
+  "PYI",
+  # tidy imports
+  "TID",
+  # implicit string concatenation
+  "ISC",
+  # type-checking imports
+  "TCH",
+  # comprehensions
+  "C4",
+  # pygrep-hooks
+  "PGH",
+  # Ruff-specific rules
+  "RUF",
+  # flake8-bandit: exec-builtin
+  "S102",
+  # NumPy-specific rules
+  "NPY",
+  # Perflint
+  "PERF",
+  # flynt
+  "FLY",
+  # flake8-logging-format
+  "G",
+  # flake8-future-annotations
+  "FA",
+  # flake8-slots
+  "SLOT",
+  # flake8-raise
+  "RSE",
+]
+
+ignore = [
+    ### Intentionally disabled
+    # Line too long
+    "E501",
+    # Unnecessary `dict` call (rewrite as a literal)
+    "C408",
+    # Consider iterable unpacking instead of concatenation
+    "RUF005",
+    # No explicit `stacklevel` keyword argument found
+    "B028",
+    # Unused `noqa` directive # Only work if ruff is the solve linter/formatter
+    "RUF100",
+    # `zip()` without an explicit `strict=` parameter
+    "B905",
+    # Only simple default values allowed for typed arguments
+    "PYI011",
+
+    ### TODO: Enable gradually
+    # Rename unused
+    "B007",
+    # Move standard library import into a type-checking block
+    "TCH003",
+    # Consider f-string instead of string join
+    "FLY002",
+    # Use a list comprehension to create a transformed list
+    "PERF401"
+
+]
+
+[tool.mypy]
+files = ["pyproj"]
+python_version = "3.10"
+ignore_errors = false
+enable_error_code = "ignore-without-code"


=====================================
test/crs/test_crs_cf.py
=====================================
@@ -1864,16 +1864,16 @@ def test_export_compound_crs_cs():
 
 def test_ellipsoidal_cs__geodetic():
     crs = CRS.from_epsg(4326)
-    crs.cs_to_cf() == [
+    assert crs.cs_to_cf() == [
         {
             "standard_name": "latitude",
-            "long_name": "geodetic latitude coordinate",
+            "long_name": "latitude coordinate",
             "units": "degrees_north",
             "axis": "Y",
         },
         {
             "standard_name": "longitude",
-            "long_name": "geodetic longitude coordinate",
+            "long_name": "longitude coordinate",
             "units": "degrees_east",
             "axis": "X",
         },
@@ -1935,16 +1935,16 @@ def test_3d_ellipsoidal_cs_depth():
             },
         }
     )
-    crs.cs_to_cf() == [
+    assert crs.cs_to_cf() == [
         {
             "standard_name": "latitude",
-            "long_name": "geodetic latitude coordinate",
+            "long_name": "latitude coordinate",
             "units": "degrees_north",
             "axis": "Y",
         },
         {
             "standard_name": "longitude",
-            "long_name": "geodetic longitude coordinate",
+            "long_name": "longitude coordinate",
             "units": "degrees_east",
             "axis": "X",
         },


=====================================
test/crs/test_crs_coordinate_system.py
=====================================
@@ -210,7 +210,7 @@ def test_ellipsoidal3dcs_to_cf():
 
 def test_cartesian2dcs_ft_to_cf():
     csft = Cartesian2DCS(axis=Cartesian2DCSAxis.NORTHING_EASTING_FT)
-    csft.to_cf() == [
+    assert csft.to_cf() == [
         {
             "axis": "Y",
             "long_name": "Northing",
@@ -228,25 +228,25 @@ def test_cartesian2dcs_ft_to_cf():
 
 def test_cartesian2dcs_to_cf():
     csm = Cartesian2DCS(axis=Cartesian2DCSAxis.EASTING_NORTHING_FT)
-    csm.to_cf() == [
-        {
-            "axis": "Y",
-            "long_name": "Northing",
-            "standard_name": "projection_y_coordinate",
-            "units": "metre",
-        },
+    assert csm.to_cf() == [
         {
             "axis": "X",
             "long_name": "Easting",
             "standard_name": "projection_x_coordinate",
-            "units": "metre",
+            "units": "0.3048 metre",
+        },
+        {
+            "axis": "Y",
+            "long_name": "Northing",
+            "standard_name": "projection_y_coordinate",
+            "units": "0.3048 metre",
         },
     ]
 
 
 def test_verticalcs_depth_to_cf():
     vcs = VerticalCS(axis=VerticalCSAxis.DEPTH)
-    vcs.to_cf() == [
+    assert vcs.to_cf() == [
         {
             "standard_name": "height_above_reference_ellipsoid",
             "long_name": "Depth",
@@ -259,7 +259,7 @@ def test_verticalcs_depth_to_cf():
 
 def test_verticalcs_height_to_cf():
     vcs = VerticalCS(axis=VerticalCSAxis.GRAVITY_HEIGHT_US_FT)
-    vcs.to_cf() == [
+    assert vcs.to_cf() == [
         {
             "standard_name": "height_above_reference_ellipsoid",
             "long_name": "Gravity-related height",


=====================================
test/test_proj.py
=====================================
@@ -1,7 +1,6 @@
 import concurrent.futures
 import math
 import os
-import sys
 import unittest
 from unittest.mock import patch
 
@@ -159,9 +158,6 @@ class ProjLatLongTypeErrorTest(unittest.TestCase):
             lon, lat = transform(p, p.to_latlong(), 200000, 400000)
 
 
- at unittest.skipIf(
-    sys.version_info < (3, 4), "Python 3.4 or newer required for subTest()"
-)
 class ForwardInverseTest(unittest.TestCase):
     def test_fwd_inv(self):
         for pj in pj_list.keys():
@@ -232,7 +228,7 @@ class ReprTests(unittest.TestCase):
     def test_sphere(self):
         # ellipse is Venus 2000 (IAU2000:29900), which is a sphere
         g = Geod("+a=6051800 +b=6051800")
-        self.assertEqual(repr(g), "Geod('+a=6051800 +f=0')")
+        self.assertEqual(repr(g), "Geod('+a=6051800.0 +f=0.0')")
 
     # test __repr__ for Geod object
     def test_ellps_name_round_trip(self):


=====================================
test/test_sync.py
=====================================
@@ -195,7 +195,7 @@ def test_download_resource_file__bad_sha256sum(urlretrieve_mock, tmp_path):
 @patch("pyproj.sync.Path.stat")
 def test__load_grid_geojson_old_file(stat_mock, tmp_path):
     return_timestamp = MagicMock()
-    return_timestamp.st_mtime = (datetime.utcnow() - timedelta(days=2)).timestamp()
+    return_timestamp.st_mtime = (datetime.now() - timedelta(days=2)).timestamp()
     stat_mock.return_value = return_timestamp
     tmp_path.joinpath("files.geojson").touch()
     grids = _load_grid_geojson(target_directory=tmp_path)



View it on GitLab: https://salsa.debian.org/debian-gis-team/python-pyproj/-/commit/22cef1665c95015514259c9ef5c05483aafbda98

-- 
View it on GitLab: https://salsa.debian.org/debian-gis-team/python-pyproj/-/commit/22cef1665c95015514259c9ef5c05483aafbda98
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/20250215/dbcb64be/attachment-0001.htm>


More information about the Pkg-grass-devel mailing list