Skip to content

Commit

Permalink
handle non-deterministic pyproj failure
Browse files Browse the repository at this point in the history
For some transformations, pyproj attempts to download transformation
grids from the internet for improved accuracy when
Transformer.transform() is called. If it fails to connect to the
internet, it silently returns (inf, inf) and silently modifies its
behavior to not access the internet on subsequent calls, causing
them to succeed (though possibly with a loss of accuracy). See
pyproj4/pyproj#705 for details.

This workaround forces an error to be raised by setting
errcheck=True and ignoring the first error.
  • Loading branch information
AdeelH committed Oct 10, 2024
1 parent 1ca6357 commit 59149f8
Showing 1 changed file with 52 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import TYPE_CHECKING, Any
from pyproj import Transformer
import logging

from pyproj import Transformer
from pyproj.exceptions import ProjError
import numpy as np
import rasterio as rio
from rasterio.transform import (rowcol, xy)
Expand All @@ -12,6 +14,8 @@
if TYPE_CHECKING:
from typing import Self

log = logging.getLogger(__name__)


class RasterioCRSTransformer(CRSTransformer):
"""Transformer for a RasterioRasterSource."""
Expand Down Expand Up @@ -61,7 +65,7 @@ def __repr__(self) -> str:
out = f"""{cls_name}(
image_crs="{image_crs_str}",
map_crs="{map_crs_str}",
round_pixels="{self.round_pixels}",
round_pixels={self.round_pixels},
transform={transform_str})
"""
return out
Expand All @@ -78,7 +82,29 @@ def _map_to_pixel(
Returns:
(x, y) tuple in pixel coordinates
"""
image_point = self.map2image(*map_point)
# For some transformations, pyproj attempts to download transformation
# grids from the internet for improved accuracy when
# Transformer.transform() is called. If it fails to connect to the
# internet, it silently returns (inf, inf) and silently modifies its
# behavior to not access the internet on subsequent calls, causing
# them to succeed (though possibly with a loss of accuracy). See
# https://github.com/pyproj4/pyproj/issues/705 for details.
#
# The below workaround forces an error to be raised by setting
# errcheck=True and ignoring the first error.
try:
image_point = self.map2image(*map_point, errcheck=True)
except ProjError as e:
log.debug(f'pyproj: {e}')
if 'network' in str(e).lower():
log.warning(
'pyproj tried and failed to connect to the internet to '
'download transformation grids for the transformation from\n'
f'{self.map_crs}\nto\n{self.image_crs}.\nSee '
'https://github.com/pyproj4/pyproj/issues/705 for details.'
)
image_point = self.map2image(*map_point, errcheck=True)

x, y = image_point
if self.round_pixels:
row, col = rowcol(self.transform, x, y)
Expand All @@ -103,7 +129,29 @@ def _pixel_to_map(
col = col.astype(int) if isinstance(col, np.ndarray) else int(col)
row = row.astype(int) if isinstance(row, np.ndarray) else int(row)
image_point = xy(self.transform, row, col, offset='center')
map_point = self.image2map(*image_point)

# For some transformations, pyproj attempts to download transformation
# grids from the internet for improved accuracy when
# Transformer.transform() is called. If it fails to connect to the
# internet, it silently returns (inf, inf) and silently modifies its
# behavior to not access the internet on subsequent calls, causing
# them to succeed (though possibly with a loss of accuracy). See
# https://github.com/pyproj4/pyproj/issues/705 for details.
#
# The below workaround forces an error to be raised by setting
# errcheck=True and ignoring the first error.
try:
map_point = self.image2map(*image_point, errcheck=True)
except ProjError as e:
log.debug(f'pyproj: {e}')
if 'network' in str(e).lower():
log.warning(
'pyproj tried and failed to connect to the internet to '
'download transformation grids for the transformation from'
f'\n{self.image_crs}\nto\n{self.map_crs}.\nSee '
'https://github.com/pyproj4/pyproj/issues/705 for details.'
)
map_point = self.image2map(*image_point, errcheck=True)
return map_point

@classmethod
Expand Down

0 comments on commit 59149f8

Please sign in to comment.