From 9211c4cb1301317af72a33d56b9f7a09727066b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sat, 17 Oct 2026 21:38:35 +0200 Subject: [PATCH 1/4] MNT: move the static part of cibuildwheel's configuration to pyproject.toml --- .github/workflows/release.yaml | 14 -------------- pyproject.toml | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a61fa32dc..1aefbbee9 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -159,22 +159,8 @@ jobs: PROJ_NETWORK=ON PROJ_VERSION=${{ env.PROJ_VERSION }} PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }} - # Rename Git's link.exe to avoid conflict with MSVC link.exe (meson issue) - CIBW_BEFORE_BUILD_WINDOWS: > - python -m pip install delvewheel && - if exist "C:\Program Files\Git\usr\bin\link.exe" (rename "C:\Program Files\Git\usr\bin\link.exe" "link.exe.bak") # Add Windows System32 explicitly to the path https://github.com/adang1345/delvewheel/issues/54 CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}" - CIBW_BEFORE_ALL_LINUX: bash ./ci/proj-compile-wheels.sh - CIBW_BEFORE_ALL_MACOS: bash ./ci/proj-compile-wheels.sh - CIBW_TEST_REQUIRES: cython pytest numpy --config-settings=setup-args="-Dallow-noblas=true" - # Install numpy first so Shapely can find numpy headers during build - CIBW_BEFORE_TEST: python -m pip install numpy && python -m pip install shapely pandas xarray || echo "Optional requirements install failed" - CIBW_TEST_COMMAND: > - pyproj -v && - python -c "import pyproj; pyproj.Proj(init='epsg:4269')" && - cp -r {package}/test . && - python -m pytest test -v -s - name: Upload artifacts uses: actions/upload-artifact@v7 diff --git a/pyproject.toml b/pyproject.toml index f003d114a..7257ca173 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,6 +104,28 @@ include = ["pyproj", "pyproj.*"] [tool.setuptools.dynamic] version = {attr = "pyproj.__version__"} +[tool.cibuildwheel] +test-groups = ["test"] +test-sources = ["test"] +test-command = [ + "pyproj -v", + '''python -c "import pyproj; pyproj.Proj(init='epsg:4269')"''', + "python -m pytest test -v -s", +] + +[tool.cibuildwheel.config-settings] +setup-args = "-Dallow-noblas=true" + +[tool.cibuildwheel.linux] +before-all = "bash ./ci/proj-compile-wheels.sh" + +[tool.cibuildwheel.macos] +before-all = "bash ./ci/proj-compile-wheels.sh" + +[tool.cibuildwheel.windows] +# Rename Git's link.exe to avoid conflict with MSVC link.exe (meson issue) +before-build = 'if exist "C:\Program Files\Git\usr\bin\link.exe" (rename "C:\Program Files\Git\usr\bin\link.exe" "link.exe.bak")' + [tool.ruff] line-length = 88 fix = true From 13a61700b1a8fe5ac29f39882c622cdcdbfb1e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sun, 18 Oct 2026 09:55:47 +0200 Subject: [PATCH 2/4] MNT: deduplicate static PROJ_* env vars in cibw settings --- .github/workflows/release.yaml | 12 +++--------- pyproject.toml | 5 +++++ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1aefbbee9..d858c6210 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -140,24 +140,18 @@ jobs: - name: Build wheels uses: pypa/cibuildwheel@v4.3.1 env: + PROJ_WHEEL: 'true' + PROJ_NETWORK: ON + PROJ_VERSION: ${{ env.PROJ_VERSION }} CIBW_ARCHS: ${{ matrix.arch }} CIBW_ENVIRONMENT_LINUX: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} PROJ_DIR=/project/pyproj/proj_dir CIBW_ENVIRONMENT_MACOS: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} PROJ_DIR=${GITHUB_WORKSPACE}/pyproj/proj_dir CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}' MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos_deployment_target }} LDFLAGS="${LDFLAGS} -Wl,-rpath,${GITHUB_WORKSPACE}/pyproj/proj_dir/lib" CIBW_ENVIRONMENT_WINDOWS: - PROJ_WHEEL=true - PROJ_NETWORK=ON - PROJ_VERSION=${{ env.PROJ_VERSION }} PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }} # Add Windows System32 explicitly to the path https://github.com/adang1345/delvewheel/issues/54 CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}" diff --git a/pyproject.toml b/pyproject.toml index 7257ca173..4ccb69601 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,6 +112,11 @@ test-command = [ '''python -c "import pyproj; pyproj.Proj(init='epsg:4269')"''', "python -m pytest test -v -s", ] +environment-pass = [ + "PROJ_NETWORK", + "PROJ_VERSION", + "PROJ_WHEEL", +] [tool.cibuildwheel.config-settings] setup-args = "-Dallow-noblas=true" From 4ecde379f13282c4d1a0ecb4c8dd34daed40c15c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sun, 18 Oct 2026 17:55:57 +0200 Subject: [PATCH 3/4] tentative dedupe env --- .github/workflows/release.yaml | 47 ++++++++++++++++++++++------------ pyproject.toml | 1 + 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d858c6210..90ce84e97 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -137,24 +137,39 @@ jobs: mkdir -p ${GITHUB_WORKSPACE}/pyproj/proj_dir/share/proj cp "$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }}/share/proj/"* ${GITHUB_WORKSPACE}/pyproj/proj_dir/share/proj/ + # Part of cibuildwheel's settings are set dynamically so they cannot + # be moved to pyproject.toml + # avoid duplication between jobs by setting environment variables + # via GITHUB_ENV so they persist between steps + + - name: Setup cibuildwheel environment (all platforms) + run: | + echo "PROJ_WHEEL='true'" >> "$GITHUB_ENV" + echo "PROJ_NETWORK=ON" >> "$GITHUB_ENV" + echo "PROJ_VERSION=${{ env.PROJ_VERSION }}" >> "$GITHUB_ENV" + echo "CIBW_ARCHS=${{ matrix.arch }}" >> "$GITHUB_ENV" + + - name: Setup additional environment (linux) + if: ${{ startswith( matrix.os , 'ubuntu' ) }} + run: | + echo "PROJ_DIR=/project/pyproj/proj_dir" >> "$GITHUB_ENV" + + - name: Setup additional environment (macos) + if: ${{ startswith( matrix.os , 'macos' ) }} + run: | + echo "PROJ_DIR=${GITHUB_WORKSPACE}/pyproj/proj_dir" >> "$GITHUB_ENV" + echo 'CIBW_ENVIRONMENT=CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}' MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos_deployment_target }} LDFLAGS="${LDFLAGS} -Wl,-rpath,${GITHUB_WORKSPACE}/pyproj/proj_dir/lib"' >> "$GITHUB_ENV" + + - name: Setup additional environment (windows) + if: ${{ startswith( matrix.os , 'windows' ) }} + # repair-wheel: add Windows System32 explicitly to the path + # see https://github.com/adang1345/delvewheel/issues/54 + run: | + echo 'PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }}' >> "$GITHUB_ENV" + echo 'CIBW_REPAIR_WHEEL_COMMAND="delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}"' >> "$GITHUB_ENV" + - name: Build wheels uses: pypa/cibuildwheel@v4.3.1 - env: - PROJ_WHEEL: 'true' - PROJ_NETWORK: ON - PROJ_VERSION: ${{ env.PROJ_VERSION }} - CIBW_ARCHS: ${{ matrix.arch }} - CIBW_ENVIRONMENT_LINUX: - PROJ_DIR=/project/pyproj/proj_dir - CIBW_ENVIRONMENT_MACOS: - PROJ_DIR=${GITHUB_WORKSPACE}/pyproj/proj_dir - CMAKE_OSX_ARCHITECTURES='${{ matrix.cmake_osx_architectures }}' - MACOSX_DEPLOYMENT_TARGET=${{ matrix.macos_deployment_target }} - LDFLAGS="${LDFLAGS} -Wl,-rpath,${GITHUB_WORKSPACE}/pyproj/proj_dir/lib" - CIBW_ENVIRONMENT_WINDOWS: - PROJ_DIR=$VCPKG_INSTALLATION_ROOT/installed/${{ matrix.triplet }} - # Add Windows System32 explicitly to the path https://github.com/adang1345/delvewheel/issues/54 - CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel repair --add-path C:/Windows/System32 --add-path C:/vcpkg/installed/${{ matrix.triplet }}/bin -w {dest_dir} {wheel}" - name: Upload artifacts uses: actions/upload-artifact@v7 diff --git a/pyproject.toml b/pyproject.toml index 4ccb69601..fae5f557d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -113,6 +113,7 @@ test-command = [ "python -m pytest test -v -s", ] environment-pass = [ + "PROJ_DIR", "PROJ_NETWORK", "PROJ_VERSION", "PROJ_WHEEL", From 7ffcff3074771b3543bcab2d4537a83b1f99b4da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Sun, 18 Oct 2026 18:55:02 +0200 Subject: [PATCH 4/4] BLD: improve build logs around proj directory discovery --- setup.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index 54d682065..a178b41d8 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ import shutil import subprocess import sys +from functools import partial from pathlib import Path from setuptools import Extension, setup @@ -69,27 +70,28 @@ def get_proj_dir() -> Path: This function finds the base PROJ directory. """ proj_dir_environ = os.environ.get("PROJ_DIR") - proj_dir: Path | None = None + log = partial(print, file=sys.stderr) if proj_dir_environ is not None: proj_dir = Path(proj_dir_environ) - if proj_dir is None and INTERNAL_PROJ_DIR.exists(): + log("Using proj specified by environment variable PROJ_DIR", end=" ") + elif INTERNAL_PROJ_DIR.exists(): proj_dir = INTERNAL_PROJ_DIR - print(f"Internally compiled directory being used {INTERNAL_PROJ_DIR}.") - elif proj_dir is None and not INTERNAL_PROJ_DIR.exists(): - proj = shutil.which("proj", path=sys.prefix) - if proj is None: - proj = shutil.which("proj") + log("Using proj from internal compiled directory", end=" ") + else: + proj = shutil.which("proj", path=sys.prefix) or shutil.which("proj") if proj is None: raise SystemExit( "proj executable not found. Please set the PROJ_DIR variable. " "For more information see: " "https://pyproj4.github.io/pyproj/stable/installation.html" ) - proj_dir = Path(proj).parent.parent - elif proj_dir is not None and proj_dir.exists(): - print("PROJ_DIR is set, using existing PROJ installation..\n") - else: - raise SystemExit(f"ERROR: Invalid path for PROJ_DIR {proj_dir}") + proj_dir = Path(proj).parents[1] + log("Using proj auto-discovered executable", end=" ") + log(proj_dir) + if not proj_dir.exists(): + raise SystemExit(f"ERROR: not such file or directory {proj_dir}") + if not proj_dir.is_dir(): + raise SystemExit(f"ERROR: {proj_dir} exists but is not a directory") return proj_dir