From 9db12ff446a8313dbfdbecf6ee7350adc1c90035 Mon Sep 17 00:00:00 2001 From: Josh <162485031+wiyth00@users.noreply.github.com> Date: Fri, 24 Jul 2026 23:15:17 -0400 Subject: [PATCH] fix: declare pyproj as a direct dependency chained_eclipse/search.py and chained_eclipse/sensitivity.py both import `pyproj.Geod`, but pyproj was only present transitively via cartopy. Declare it explicitly so the package cannot break if cartopy drops or vendors it. Adds a regression test that imports both modules. --- pyproject.toml | 1 + tests/test_declared_dependencies.py | 35 +++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/test_declared_dependencies.py diff --git a/pyproject.toml b/pyproject.toml index 1167255..7d5fdf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "matplotlib>=3.9", "numpy>=2.0", "pandas>=2.2", + "pyproj>=3.6", "pyyaml>=6.0", "rebound>=4.6,<5.0", "reboundx>=4.6,<5.0", diff --git a/tests/test_declared_dependencies.py b/tests/test_declared_dependencies.py new file mode 100644 index 0000000..426350f --- /dev/null +++ b/tests/test_declared_dependencies.py @@ -0,0 +1,35 @@ +"""Guard that third-party imports used by the package are declared dependencies. + +``chained_eclipse.search`` and ``chained_eclipse.sensitivity`` both do +``from pyproj import Geod``. Before this test, ``pyproj`` was installed only as a +transitive dependency of ``cartopy``; if cartopy ever dropped or vendored it, +these imports would fail at runtime with no declared-dependency safety net. +""" + +from __future__ import annotations + +import importlib +import tomllib +from pathlib import Path + +import pytest + +PYPROJECT = Path(__file__).resolve().parents[1] / "pyproject.toml" + + +@pytest.mark.parametrize( + "module_name", + ["chained_eclipse.search", "chained_eclipse.sensitivity"], +) +def test_pyproj_dependent_modules_import(module_name: str) -> None: + assert importlib.import_module(module_name) is not None + + +@pytest.mark.skipif(not PYPROJECT.exists(), reason="running from an installed wheel") +def test_pyproj_is_a_declared_runtime_dependency() -> None: + metadata = tomllib.loads(PYPROJECT.read_text(encoding="utf-8")) + declared = metadata["project"]["dependencies"] + assert any(spec.split(">")[0].split("=")[0].strip() == "pyproj" for spec in declared), ( + "pyproj is imported by chained_eclipse.search and chained_eclipse.sensitivity " + "and must be declared in [project] dependencies, not relied on transitively." + )