Skip to content

Commit 24a7b7f

Browse files
authored
DEP: Minimum PROJ version 9.2 (#1394)
1 parent 42da2cf commit 24a7b7f

15 files changed

+103
-208
lines changed

.github/workflows/tests.yaml

+3-11
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,12 @@ jobs:
4141
fail-fast: false
4242
matrix:
4343
python-version: ['3.10', '3.11', '3.12']
44-
proj-version: ['9.3.0']
44+
proj-version: ['9.4.0']
4545
include:
4646
- python-version: '3.10'
47-
proj-version: '9.2.1'
48-
- python-version: '3.10'
49-
proj-version: '9.1.1'
47+
proj-version: '9.3.1'
5048
- python-version: '3.10'
51-
proj-version: '9.1.0'
52-
- python-version: '3.10'
53-
proj-version: '9.0.1'
49+
proj-version: '9.2.1'
5450
steps:
5551
- uses: actions/checkout@v4
5652

@@ -134,10 +130,6 @@ jobs:
134130
# python-version: '*'
135131
# python-implementation: pypy
136132
# proj-version: '*'
137-
- os: ubuntu-latest
138-
python-version: '*'
139-
python-implementation: python
140-
proj-version: '9.1.1'
141133
steps:
142134
- uses: actions/checkout@v4
143135

docs/history.rst

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Latest
55
------
66
- WHL: Wheels contain PROJ 9.4.0 (pull #1386)
77
- DEP: Minimum supported Python version 3.10 (pull #1357)
8+
- DEP: Minimum PROJ version 9.2 (pull #1394)
89
- ENH: Add :meth:`CRS.is_deprecated` and :meth:`CRS.get_non_deprecated` (pull #1383)
910

1011
3.6.1

docs/installation.rst

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pyproj PROJ
7676
3.3 8.0-9.1
7777
3.4+ 8.2+
7878
3.5+ 9+
79+
3.7+ 9.2+
7980
============ ============
8081

8182
Setup PROJ

pyproj/_crs.pyx

+5-13
Original file line numberDiff line numberDiff line change
@@ -2342,10 +2342,9 @@ cdef dict _CRS_TYPE_MAP = {
23422342
PJ_TYPE_ENGINEERING_CRS: "Engineering CRS",
23432343
PJ_TYPE_BOUND_CRS: "Bound CRS",
23442344
PJ_TYPE_OTHER_CRS: "Other CRS",
2345+
PJ_TYPE_DERIVED_PROJECTED_CRS: "Derived Projected CRS",
23452346
}
23462347

2347-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 2):
2348-
_CRS_TYPE_MAP[PJ_TYPE_DERIVED_PROJECTED_CRS] = "Derived Projected CRS"
23492348

23502349
cdef class _CRS(Base):
23512350
"""
@@ -2396,21 +2395,14 @@ cdef class _CRS(Base):
23962395
if self._type_name is not None:
23972396
return self._type_name
23982397
self._type_name = _CRS_TYPE_MAP[self._type]
2399-
if not self.is_derived or self._type == PJ_TYPE_PROJECTED_CRS:
2398+
if not self.is_derived or self._type in (
2399+
PJ_TYPE_PROJECTED_CRS,
2400+
PJ_TYPE_DERIVED_PROJECTED_CRS,
2401+
):
24002402
# Projected CRS are derived by definition
24012403
# https://github.com/OSGeo/PROJ/issues/3525#issuecomment-1365790999
24022404
return self._type_name
24032405

2404-
# Handle Derived Projected CRS
2405-
# https://github.com/OSGeo/PROJ/issues/3525#issuecomment-1366002289
2406-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) < (9, 2):
2407-
if self._type == PJ_TYPE_OTHER_CRS:
2408-
self._type_name = "Derived Projected CRS"
2409-
return self._type_name
2410-
ELSE:
2411-
if self._type == PJ_TYPE_DERIVED_PROJECTED_CRS:
2412-
return self._type_name
2413-
24142406
self._type_name = f"Derived {self._type_name}"
24152407
return self._type_name
24162408

pyproj/_transformer.pyx

+21-31
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ proj_version_str = f"{PROJ_VERSION_MAJOR}.{PROJ_VERSION_MINOR}.{PROJ_VERSION_PAT
3535
PROJ_VERSION = (PROJ_VERSION_MAJOR, PROJ_VERSION_MINOR, PROJ_VERSION_PATCH)
3636
_AUTH_CODE_RE = re.compile(r"(?P<authority>\w+)\:(?P<code>\w+)")
3737

38-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 1):
39-
cdef extern from "proj.h" nogil:
40-
PJ* proj_trans_get_last_used_operation(PJ *P)
41-
4238

4339
cdef dict _TRANSFORMER_TYPE_MAP = {
4440
PJ_TYPE_UNKNOWN: "Unknown Transformer",
@@ -322,13 +318,10 @@ cdef PJ* proj_create_crs_to_crs(
322318
options[options_index] = b"FORCE_OVER=YES"
323319
options_index += 1
324320
if only_best is not None:
325-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 2):
326-
if only_best:
327-
options[options_index] = b"ONLY_BEST=YES"
328-
else:
329-
options[options_index] = b"ONLY_BEST=NO"
330-
ELSE:
331-
raise NotImplementedError("only_best requires PROJ 9.2+.")
321+
if only_best:
322+
options[options_index] = b"ONLY_BEST=YES"
323+
else:
324+
options[options_index] = b"ONLY_BEST=NO"
332325

333326
cdef PJ* transform = NULL
334327
with nogil:
@@ -468,27 +461,24 @@ cdef class _Transformer(Base):
468461
return self._operations
469462

470463
def get_last_used_operation(self):
471-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 1):
472-
cdef PJ* last_used_operation = proj_trans_get_last_used_operation(self.projobj)
473-
if last_used_operation == NULL:
474-
raise ProjError(
475-
"Last used operation not found. "
476-
"This is likely due to not initiating a transform."
477-
)
478-
cdef PJ_CONTEXT* context = NULL
479-
try:
480-
context = pyproj_context_create()
481-
except:
482-
proj_destroy(last_used_operation)
483-
raise
484-
proj_assign_context(last_used_operation, context)
485-
return _Transformer._from_pj(
486-
context,
487-
last_used_operation,
488-
False,
464+
cdef PJ* last_used_operation = proj_trans_get_last_used_operation(self.projobj)
465+
if last_used_operation == NULL:
466+
raise ProjError(
467+
"Last used operation not found. "
468+
"This is likely due to not initiating a transform."
489469
)
490-
ELSE:
491-
raise NotImplementedError("PROJ 9.1+ required to get last used operation.")
470+
cdef PJ_CONTEXT* context = NULL
471+
try:
472+
context = pyproj_context_create()
473+
except:
474+
proj_destroy(last_used_operation)
475+
raise
476+
proj_assign_context(last_used_operation, context)
477+
return _Transformer._from_pj(
478+
context,
479+
last_used_operation,
480+
False,
481+
)
492482

493483
@property
494484
def is_network_enabled(self):

pyproj/database.pyx

+1-7
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,15 @@ cdef dict _PJ_TYPE_MAP = {
3838
PJType.TRANSFORMATION: PJ_TYPE_TRANSFORMATION,
3939
PJType.CONCATENATED_OPERATION: PJ_TYPE_CONCATENATED_OPERATION,
4040
PJType.OTHER_COORDINATE_OPERATION: PJ_TYPE_OTHER_COORDINATE_OPERATION,
41+
PJType.DERIVED_PROJECTED_CRS: PJ_TYPE_DERIVED_PROJECTED_CRS,
4142
}
42-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 2):
43-
_PJ_TYPE_MAP[PJType.DERIVED_PROJECTED_CRS] = PJ_TYPE_DERIVED_PROJECTED_CRS
4443

4544
cdef dict _INV_PJ_TYPE_MAP = {value: key for key, value in _PJ_TYPE_MAP.items()}
4645

4746

4847
cdef PJ_TYPE get_pj_type(pj_type) except *:
4948
if not isinstance(pj_type, PJType):
5049
pj_type = PJType.create(pj_type)
51-
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) < (9, 2):
52-
if pj_type is PJType.DERIVED_PROJECTED_CRS:
53-
raise NotImplementedError(
54-
"DERIVED_PROJECTED_CRS requires PROJ 9.2+"
55-
)
5650
return _PJ_TYPE_MAP[pj_type]
5751

5852

pyproj/proj.pxi

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ cdef extern from "proj.h" nogil:
122122
double* out_ymax,
123123
int densify_pts
124124
)
125+
PJ* proj_trans_get_last_used_operation(PJ *P)
125126
ctypedef struct PJ_AREA
126127
PJ *proj_create_crs_to_crs_from_pj(
127128
PJ_CONTEXT *ctx,

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from setuptools import Extension, setup
1010

11-
PROJ_MIN_VERSION = (9, 0, 0)
11+
PROJ_MIN_VERSION = (9, 2, 0)
1212
CURRENT_FILE_PATH = Path(__file__).absolute().parent
1313
BASE_INTERNAL_PROJ_DIR = Path("proj_dir")
1414
INTERNAL_PROJ_DIR = CURRENT_FILE_PATH / "pyproj" / BASE_INTERNAL_PROJ_DIR

test/conftest.py

-5
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@
1212

1313
_NETWORK_ENABLED = pyproj.network.is_network_enabled()
1414
PROJ_LOOSE_VERSION = version.parse(pyproj.__proj_version__)
15-
PROJ_911 = PROJ_LOOSE_VERSION == version.parse("9.1.1")
16-
PROJ_GTE_901 = PROJ_LOOSE_VERSION >= version.parse("9.0.1")
17-
PROJ_GTE_91 = PROJ_LOOSE_VERSION >= version.parse("9.1")
18-
PROJ_GTE_911 = PROJ_LOOSE_VERSION >= version.parse("9.1.1")
19-
PROJ_GTE_92 = PROJ_LOOSE_VERSION >= version.parse("9.2.0")
2015
PROJ_GTE_921 = PROJ_LOOSE_VERSION >= version.parse("9.2.1")
2116
PROJ_GTE_93 = PROJ_LOOSE_VERSION >= version.parse("9.3.0")
2217

test/crs/test_crs.py

+5-22
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,7 @@
2020
from pyproj.enums import ProjVersion, WktVersion
2121
from pyproj.exceptions import CRSError
2222
from pyproj.transformer import TransformerGroup
23-
from test.conftest import (
24-
PROJ_GTE_91,
25-
PROJ_GTE_901,
26-
PROJ_GTE_911,
27-
PROJ_GTE_921,
28-
assert_can_pickle,
29-
grids_available,
30-
)
23+
from test.conftest import PROJ_GTE_921, assert_can_pickle, grids_available
3124

3225

3326
class CustomCRS:
@@ -348,9 +341,6 @@ def test_repr_epsg():
348341

349342

350343
def test_repr__undefined():
351-
datum_name = "unknown"
352-
if PROJ_GTE_901:
353-
datum_name = f"{datum_name} using nadgrids=@null"
354344
assert repr(
355345
CRS(
356346
"+proj=merc +a=6378137.0 +b=6378137.0 +nadgrids=@null"
@@ -367,7 +357,7 @@ def test_repr__undefined():
367357
"Coordinate Operation:\n"
368358
"- name: unknown to WGS84\n"
369359
"- method: NTv2\n"
370-
f"Datum: {datum_name}\n"
360+
"Datum: unknown using nadgrids=@null\n"
371361
"- Ellipsoid: unknown\n"
372362
"- Prime Meridian: Greenwich\n"
373363
"Source CRS: unknown\n"
@@ -440,9 +430,7 @@ def test_datum_unknown():
440430
datum_name = "Unknown based on WGS84 ellipsoid"
441431
if PROJ_GTE_921:
442432
datum_name = "Unknown based on WGS 84 ellipsoid"
443-
if PROJ_GTE_901:
444-
datum_name = f"{datum_name} using towgs84=0,0,0,0,0,0,0"
445-
assert crs.datum.name == datum_name
433+
assert crs.datum.name == f"{datum_name} using towgs84=0,0,0,0,0,0,0"
446434

447435

448436
def test_epsg__not_found():
@@ -679,17 +667,12 @@ def test_coordinate_operation_grids__alternative_grid_name():
679667
assert grid.short_name == "ca_nrc_ntv1_can.tif"
680668
assert grid.package_name == ""
681669
assert grid.url == "https://cdn.proj.org/ca_nrc_ntv1_can.tif"
682-
if (PROJ_GTE_91 and grids_available(grid.short_name, check_network=False)) or (
683-
not PROJ_GTE_91 and grids_available(grid.short_name)
684-
):
670+
if grids_available(grid.short_name, check_network=False):
685671
assert grid.available is True
686672
assert grid.full_name.endswith(grid.short_name)
687-
elif PROJ_GTE_911 and pyproj.network.is_network_enabled():
673+
elif pyproj.network.is_network_enabled():
688674
assert grid.available is True
689675
assert grid.full_name == grid.url
690-
elif PROJ_GTE_91 and pyproj.network.is_network_enabled():
691-
assert grid.available is True
692-
assert grid.full_name == ""
693676
else:
694677
assert grid.available is False
695678
assert grid.full_name == ""

test/crs/test_crs_cf.py

+3-7
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
VerticalPerspectiveConversion,
1919
)
2020
from pyproj.exceptions import CRSError
21-
from test.conftest import PROJ_GTE_901, PROJ_LOOSE_VERSION
21+
from test.conftest import PROJ_LOOSE_VERSION
2222

2323

2424
def _to_dict(operation):
@@ -82,13 +82,9 @@ def test_to_cf_transverse_mercator():
8282
)
8383
towgs84_test = [-122.74, -34.27, -22.83, -1.884, -3.4, -3.03, -15.62]
8484
horizontal_datum_name = (
85-
"Unknown based on International 1924 (Hayford 1909, 1910) ellipsoid"
85+
"Unknown based on International 1924 (Hayford 1909, 1910) ellipsoid using "
86+
"towgs84=-122.74,-34.27,-22.83,-1.884,-3.400,-3.030,-15.62"
8687
)
87-
if PROJ_GTE_901:
88-
horizontal_datum_name = (
89-
f"{horizontal_datum_name} using "
90-
"towgs84=-122.74,-34.27,-22.83,-1.884,-3.400,-3.030,-15.62"
91-
)
9288
expected_cf = {
9389
"semi_major_axis": 6378388.0,
9490
"semi_minor_axis": crs.ellipsoid.semi_minor_metre,

test/crs/test_crs_maker.py

+2-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from pyproj.crs.datum import CustomDatum
2424
from pyproj.crs.enums import VerticalCSAxis
2525
from pyproj.exceptions import CRSError
26-
from test.conftest import PROJ_GTE_901, assert_can_pickle
26+
from test.conftest import assert_can_pickle
2727

2828

2929
def assert_maker_inheritance_valid(new_crs, class_type):
@@ -98,10 +98,7 @@ def test_geographic_crs__from_methods():
9898
def test_make_geographic_3d_crs():
9999
gcrs = GeographicCRS(ellipsoidal_cs=Ellipsoidal3DCS())
100100
assert gcrs.type_name == "Geographic 3D CRS"
101-
expected_authority = ("IGNF", "WGS84GEODD")
102-
if PROJ_GTE_901:
103-
expected_authority = ("OGC", "CRS84h")
104-
assert gcrs.to_authority() == expected_authority
101+
assert gcrs.to_authority() == ("OGC", "CRS84h")
105102

106103

107104
def test_make_derived_geographic_crs(tmp_path):

test/test_database.py

+2-15
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
query_utm_crs_info,
1212
)
1313
from pyproj.enums import PJType
14-
from test.conftest import PROJ_GTE_92
1514

1615

1716
def test_backwards_compatible_import_paths():
@@ -111,13 +110,7 @@ def test_get_codes__empty(auth, pj_type):
111110

112111

113112
def test_get_codes__derived_projected_crs():
114-
if PROJ_GTE_92:
115-
assert not get_codes("EPSG", PJType.DERIVED_PROJECTED_CRS)
116-
else:
117-
with pytest.raises(
118-
NotImplementedError, match="DERIVED_PROJECTED_CRS requires PROJ 9.2+"
119-
):
120-
get_codes("EPSG", PJType.DERIVED_PROJECTED_CRS)
113+
assert not get_codes("EPSG", PJType.DERIVED_PROJECTED_CRS)
121114

122115

123116
def test_get_codes__invalid_auth():
@@ -152,13 +145,7 @@ def test_query_crs_info(auth, pj_type, deprecated):
152145

153146

154147
def test_query_crs_info__derived_projected_crs():
155-
if PROJ_GTE_92:
156-
assert not query_crs_info(pj_types=PJType.DERIVED_PROJECTED_CRS)
157-
else:
158-
with pytest.raises(
159-
NotImplementedError, match="DERIVED_PROJECTED_CRS requires PROJ 9.2+"
160-
):
161-
query_crs_info(pj_types=PJType.DERIVED_PROJECTED_CRS)
148+
assert not query_crs_info(pj_types=PJType.DERIVED_PROJECTED_CRS)
162149

163150

164151
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)