Skip to content

Commit ad34f1f

Browse files
committed
ENH: Added only_best kwarg to Transformer.from_crs
1 parent f1fb8cd commit ad34f1f

File tree

5 files changed

+52
-6
lines changed

5 files changed

+52
-6
lines changed

docs/history.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Latest
77
`fwd` and `fwd_intermediate`, `inv` and `inv_intermediate`,
88
Note: BREAKING CHANGE for the default value `return_back_azimuth=True` in the functions `fwd_intermediate` and `inv_intermediate`
99
to mach the default value in `fwd` and `inv`
10+
- ENH: Added only_best kwarg to :meth:`.Transformer.from_crs` (issue #1228)
1011
- PERF: Optimize point transformations (pull #1204)
1112
- REF: Raise error when :meth:`.CRS.to_wkt`, :meth:`.CRS.to_json`, or :meth:`.CRS.to_proj4` returns None (issue #1036)
1213
- CLN: Remove `AzumuthalEquidistantConversion` & :class:`LambertAzumuthalEqualAreaConversion`. :class:`AzimuthalEquidistantConversion` & :class:`LambertAzimuthalEqualAreaConversion` should be used instead (pull #1219)

pyproj/_transformer.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class _Transformer(Base):
8484
accuracy: Optional[str] = None,
8585
allow_ballpark: Optional[bool] = None,
8686
force_over: bool = False,
87+
only_best: Optional[bool] = None,
8788
) -> "_Transformer": ...
8889
@staticmethod
8990
def from_pipeline(proj_pipeline: bytes) -> "_Transformer": ...

pyproj/_transformer.pyx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ cdef PJ* proj_create_crs_to_crs(
267267
str accuracy,
268268
allow_ballpark,
269269
bint force_over,
270+
only_best,
270271
) except NULL:
271272
"""
272273
This is the same as proj_create_crs_to_crs in proj.h
@@ -290,16 +291,15 @@ cdef PJ* proj_create_crs_to_crs(
290291
return NULL
291292

292293
cdef:
293-
const char* options[5]
294+
const char* options[6]
294295
bytes b_authority
295296
bytes b_accuracy
296297
int options_index = 0
298+
int options_init_iii = 0
299+
300+
for options_init_iii in range(6):
301+
options[options_init_iii] = NULL
297302

298-
options[0] = NULL
299-
options[1] = NULL
300-
options[2] = NULL
301-
options[3] = NULL
302-
options[4] = NULL
303303
if authority is not None:
304304
b_authority = cstrencode(f"AUTHORITY={authority}")
305305
options[options_index] = b_authority
@@ -317,6 +317,16 @@ cdef PJ* proj_create_crs_to_crs(
317317
options[options_index] = b"FORCE_OVER=YES"
318318
ELSE:
319319
raise NotImplementedError("force_over requires PROJ 9+.")
320+
options_index += 1
321+
if only_best is not None:
322+
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 2):
323+
if only_best:
324+
options[options_index] = b"ONLY_BEST=YES"
325+
else:
326+
options[options_index] = b"ONLY_BEST=NO"
327+
ELSE:
328+
raise NotImplementedError("only_best requires PROJ 9.2+.")
329+
320330

321331
cdef PJ* transform = proj_create_crs_to_crs_from_pj(
322332
ctx,
@@ -519,6 +529,7 @@ cdef class _Transformer(Base):
519529
str accuracy=None,
520530
allow_ballpark=None,
521531
bint force_over=False,
532+
only_best=None,
522533
):
523534
"""
524535
Create a transformer from CRS objects
@@ -560,6 +571,7 @@ cdef class _Transformer(Base):
560571
accuracy=accuracy,
561572
allow_ballpark=allow_ballpark,
562573
force_over=force_over,
574+
only_best=only_best,
563575
)
564576
finally:
565577
if pj_area_of_interest != NULL:

pyproj/transformer.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class TransformerFromCRS( # pylint: disable=too-many-instance-attributes
9393
accuracy: Optional[str]
9494
allow_ballpark: Optional[bool]
9595
force_over: bool = False
96+
only_best: Optional[bool] = None
9697

9798
def __call__(self) -> _Transformer:
9899
"""
@@ -109,6 +110,7 @@ def __call__(self) -> _Transformer:
109110
accuracy=self.accuracy,
110111
allow_ballpark=self.allow_ballpark,
111112
force_over=self.force_over,
113+
only_best=self.only_best,
112114
)
113115

114116

@@ -549,6 +551,7 @@ def from_crs(
549551
accuracy: Optional[float] = None,
550552
allow_ballpark: Optional[bool] = None,
551553
force_over: bool = False,
554+
only_best: Optional[bool] = None,
552555
) -> "Transformer":
553556
"""Make a Transformer from a :obj:`pyproj.crs.CRS` or input used to create one.
554557
@@ -561,6 +564,7 @@ def from_crs(
561564
.. versionadded:: 2.3.0 area_of_interest
562565
.. versionadded:: 3.1.0 authority, accuracy, allow_ballpark
563566
.. versionadded:: 3.4.0 force_over
567+
.. versionadded:: 3.5.0 only_best
564568
565569
Parameters
566570
----------
@@ -592,6 +596,18 @@ def from_crs(
592596
force_over: bool, default=False
593597
If True, it will to force the +over flag on the transformation.
594598
Requires PROJ 9+.
599+
only_best: bool, optional
600+
Can be set to True to cause PROJ to error out if the best
601+
transformation known to PROJ and usable by PROJ if all grids known and
602+
usable by PROJ were accessible, cannot be used. Best transformation should
603+
be understood as the transformation returned by
604+
:c:func:`proj_get_suggested_operation` if all known grids were
605+
accessible (either locally or through network).
606+
Note that the default value for this option can be also set with the
607+
:envvar:`PROJ_ONLY_BEST_DEFAULT` environment variable, or with the
608+
``only_best_default`` setting of :ref:`proj-ini`.
609+
The only_best kwarg overrides the default value if set.
610+
Requires PROJ 9.2+.
595611
596612
Returns
597613
-------
@@ -608,6 +624,7 @@ def from_crs(
608624
accuracy=accuracy if accuracy is None else str(accuracy),
609625
allow_ballpark=allow_ballpark,
610626
force_over=force_over,
627+
only_best=only_best,
611628
)
612629
)
613630

test/test_transformer.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import pickle
44
from array import array
5+
from contextlib import nullcontext
56
from functools import partial
67
from glob import glob
78
from itertools import permutations
@@ -666,6 +667,20 @@ def test_transformer__operations__scope_remarks():
666667
]
667668

668669

670+
@pytest.mark.grid
671+
def test_transformer__only_best():
672+
with nullcontext() if PROJ_GTE_92 else pytest.raises(
673+
NotImplementedError, match="only_best requires PROJ 9.2"
674+
):
675+
transformer = Transformer.from_crs(4326, 2964, only_best=True)
676+
if not grids_available("ca_nrc_ntv2_0.tif"):
677+
with pytest.raises(
678+
ProjError,
679+
match="Grid ca_nrc_ntv2_0.tif is not available.",
680+
):
681+
transformer.transform(60, -100, errcheck=True)
682+
683+
669684
def test_transformer_group():
670685
trans_group = TransformerGroup(7789, 8401)
671686
assert len(trans_group.transformers) == 2

0 commit comments

Comments
 (0)