Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Added Transformer.get_last_used_operation #1124

Merged
merged 1 commit into from
Aug 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ disable=cyclic-import,


[FORMAT]
max-module-lines=1300
max-module-lines=1350
1 change: 1 addition & 0 deletions docs/history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Latest
- BUG: Fix transformer list for 3D transformations in :class:`.TransformerGroup` (discussion #1072)
- ENH: Added authority, accuracy, and allow_ballpark kwargs to :class:`.TransformerGroup` (pull #1076)
- ENH: Added ``force_over`` kwarg to :meth:`.Transformer.from_crs` (issue #997)
- ENH: Added :meth:`.Transformer.get_last_used_operation` (issue #1071)
- CLN: Remove deprecated ``skip_equivalent`` kwarg from transformers and ``errcheck`` kwarg from :meth:`.CRS.from_cf` (pull #1077)
- REF: use regex to process PROJ strings in :meth:`.CRS.to_dict` (pull #1086)
- BUG: :class:`.MercatorAConversion` defined only for lat_0 = 0 (issue #1089)
Expand Down
1 change: 1 addition & 0 deletions pyproj/_transformer.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class _Transformer(Base):
def target_crs(self) -> Optional[_CRS]: ...
@property
def operations(self) -> Union[Tuple[CoordinateOperation], None]: ...
def get_last_used_operation(self) -> _Transformer: ...
@property
def is_network_enabled(self) -> bool: ...
def to_proj4(
Expand Down
27 changes: 27 additions & 0 deletions pyproj/_transformer.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ proj_version_str = f"{PROJ_VERSION_MAJOR}.{PROJ_VERSION_MINOR}.{PROJ_VERSION_PAT
PROJ_VERSION = (PROJ_VERSION_MAJOR, PROJ_VERSION_MINOR, PROJ_VERSION_PATCH)
_AUTH_CODE_RE = re.compile(r"(?P<authority>\w+)\:(?P<code>\w+)")

IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 1):
cdef extern from "proj.h" nogil:
PJ* proj_trans_get_last_used_operation(PJ *P)


cdef dict _PJ_DIRECTION_MAP = {
TransformDirection.FORWARD: PJ_FWD,
Expand Down Expand Up @@ -425,6 +429,29 @@ cdef class _Transformer(Base):
self._operations = _get_concatenated_operations(self.context, self.projobj)
return self._operations

def get_last_used_operation(self):
IF (CTE_PROJ_VERSION_MAJOR, CTE_PROJ_VERSION_MINOR) >= (9, 1):
cdef PJ* last_used_operation = proj_trans_get_last_used_operation(self.projobj)
if last_used_operation == NULL:
raise ProjError(
"Last used operation not found. "
"This is likely due to not initiating a transform."
)
cdef PJ_CONTEXT* context = NULL
try:
context = pyproj_context_create()
except:
proj_destroy(last_used_operation)
raise
proj_assign_context(last_used_operation, context)
return _Transformer._from_pj(
context,
last_used_operation,
False,
)
ELSE:
raise NotImplementedError("PROJ 9.1+ required to get last used operation.")

@property
def is_network_enabled(self):
"""
Expand Down
1 change: 1 addition & 0 deletions pyproj/proj.pxi
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cdef extern from "proj.h" nogil:
PJ_CONTEXT *proj_context_create ()
PJ_CONTEXT *proj_context_clone (PJ_CONTEXT *ctx)
PJ_CONTEXT *proj_context_destroy (PJ_CONTEXT *ctx)
void proj_assign_context(PJ* pj, PJ_CONTEXT* ctx)

ctypedef enum PJ_LOG_LEVEL:
PJ_LOG_NONE = 0
Expand Down
17 changes: 17 additions & 0 deletions pyproj/transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,23 @@ def operations(self) -> Optional[Tuple[CoordinateOperation]]:
"""
return self._transformer.operations

def get_last_used_operation(self) -> "Transformer":
"""
.. versionadded:: 3.4.0

.. note:: Requires PROJ 9.1+

See: :c:func:`proj_trans_get_last_used_operation`

Returns
-------
Transformer:
The operation used in the transform call.
"""
return Transformer(
TransformerUnsafe(self._transformer.get_last_used_operation())
)

@property
def is_network_enabled(self) -> bool:
"""
Expand Down
23 changes: 23 additions & 0 deletions test/test_transformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1598,3 +1598,26 @@ def test_transformer_force_over():
else:
with pytest.raises(NotImplementedError, match="force_over requires PROJ 9"):
Transformer.from_crs("EPSG:4326", "EPSG:3857", force_over=True)


def test_transformer__get_last_used_operation():
transformer = Transformer.from_crs("EPSG:4326", "EPSG:3857")
if PROJ_GTE_91:
with pytest.raises(
ProjError,
match=(
r"Last used operation not found\. "
r"This is likely due to not initiating a transform\."
),
):
transformer.get_last_used_operation()
xxx, yyy = transformer.transform(1, 2)
operation = transformer.get_last_used_operation()
assert isinstance(operation, Transformer)
assert xxx, yyy == operation.transform(1, 2)
else:
with pytest.raises(
NotImplementedError,
match=r"PROJ 9\.1\+ required to get last used operation\.",
):
transformer.get_last_used_operation()