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

Issue #437 Better documentation of CRS code usage, and slightly more … #462

Closed
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ openeo.util
-------------

.. automodule:: openeo.util
:members: to_bbox_dict, BBoxDict, load_json_resource
:members: to_bbox_dict, BBoxDict, load_json_resource, normalize_crs


openeo.processes
Expand Down
20 changes: 18 additions & 2 deletions openeo/rest/datacube.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ def filter_bbox(
>>> cube.filter_bbox(west=3, south=51, east=4, north=52, crs=4326)

- With a (west, south, east, north) list or tuple
(note that EPSG:4326 is the default CRS, so it's not nececarry to specify it explicitly)::
(note that EPSG:4326 is the default CRS, so it's not necessary to specify it explicitly)::

>>> cube.filter_bbox([3, 51, 4, 52])
>>> cube.filter_bbox(bbox=[3, 51, 4, 52])
Expand All @@ -308,7 +308,7 @@ def filter_bbox(
>>> cube.filter_bbox(bbox_param)
>>> cube.filter_bbox(bbox=bbox_param)

- With a CRS other than EPSG 4326::
- With a CRS other than EPSG 4326 (**see also parameters: crs**)::
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved

>>> cube.filter_bbox(west=652000, east=672000, north=5161000, south=5181000, crs=32632)

Expand All @@ -318,6 +318,17 @@ def filter_bbox(
>>> west, east, north, south = 3, 4, 52, 51
>>> cube.filter_bbox(west, east, north, south)

:param crs: data structure that encodes a CRS, typically just an int or string value.
If the ``pyproj`` library is available, everything supported by it is allowed.
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved

Integers always refer to the EPSG code that has that number assigned.
A string that contains only an integer it is treated the same way.

You can also specify EPSG codes as a formatted string, "EPSG:number".
For example, the following string and int values all specify to the same CRS:
``"EPSG:4326"``, ``"4326"``, and the integer ``4326``.

.. seealso:: `openEO Python Client documentation on openeo.util.normalize_crs <api.html#openeo.util.normalize_crs>`_ for the most up to date information.
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved
"""
if args and any(k is not None for k in (west, south, east, north, bbox)):
raise ValueError("Don't mix positional arguments with keyword arguments.")
Expand Down Expand Up @@ -810,6 +821,11 @@ def _get_geometry_argument(
) -> Union[dict, Parameter, PGNode]:
"""
Convert input to a geometry as "geojson" subtype object.

:param crs: data structure that encodes a CRS, typically just an int or string value.
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved
If the ``pyproj`` library is available, everything supported by it is allowed.
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved
.. seealso:: `openEO Python Client documentation on openeo.util.normalize_crs <api.html#openeo.util.normalize_crs>`_ for the most up to date information.

"""
if isinstance(geometry, (str, pathlib.Path)):
# Assumption: `geometry` is path to polygon is a path to vector file at backend.
Expand Down
23 changes: 22 additions & 1 deletion openeo/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,19 @@ class BBoxDict(dict):
Dictionary based helper to easily create/work with bounding box dictionaries
(having keys "west", "south", "east", "north", and optionally "crs").

crs:
data structure that encodes a CRS, typically just an int or string value.
If the ``pyproj`` library is available, everything supported by it is allowed.

Integers always refer to the EPSG code that has that number assigned.
A string that contains only an integer it is treated the same way.

You can also specify EPSG codes as a formatted string, "EPSG:number".
For example, the following string and int values all specify to the same CRS:
``"EPSG:4326"``, ``"4326"``, and the integer ``4326``.

.. seealso:: `openEO Python Client documentation on openeo.util.normalize_crs <api.html#openeo.util.normalize_crs>`_ for the most up to date information.

.. versionadded:: 0.10.1
"""

Expand Down Expand Up @@ -657,7 +670,15 @@ def normalize_crs(crs: Any, *, use_pyproj: bool = True) -> Union[None, int, str]
Other data structures will not be accepted.

:param crs: data structure that encodes a CRS, typically just an int or string value.
If the ``pyproj`` library is available, everything supported by it is allowed
If the ``pyproj`` library is available, everything supported by it is allowed.

Integers always refer to the EPSG code that has that number assigned.
JohanKJSchreurs marked this conversation as resolved.
Show resolved Hide resolved
A string that contains only an integer it is treated the same way.

You can also specify EPSG codes as a formatted string, "EPSG:number".
For example, the following string and int values all specify to the same CRS:
``"EPSG:4326"``, ``"4326"``, and the integer ``4326``.

:param use_pyproj: whether ``pyproj`` should be leveraged at all
(mainly useful for testing the "no pyproj available" code path)

Expand Down
52 changes: 52 additions & 0 deletions tests/test_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,21 @@ def test_init(self):
"crs": 4326,
}

@pytest.mark.skipif(
# TODO #460 this skip is only necessary for python 3.6 and lower
pyproj.__version__ < ComparableVersion("3.3.1"),
reason="pyproj below 3.3.1 does not support int-like strings",
)
def test_init_python_for_pyprojv331(self):
"""Extra test case that does not work with old pyproj versions that we get on python version 3.7 and below."""
assert BBoxDict(west=1, south=2, east=3, north=4, crs="4326") == {
"west": 1,
"south": 2,
"east": 3,
"north": 4,
"crs": 4326,
}

def test_repr(self):
d = BBoxDict(west=1, south=2, east=3, north=4)
assert repr(d) == "{'west': 1, 'south': 2, 'east': 3, 'north': 4}"
Expand All @@ -728,6 +743,21 @@ def test_to_bbox_dict_from_sequence(self):
"crs": 4326,
}

@pytest.mark.skipif(
# TODO #460 this skip is only necessary for python 3.6 and lower
pyproj.__version__ < ComparableVersion("3.3.1"),
reason="pyproj below 3.3.1 does not support int-like strings",
)
def test_to_bbox_dict_from_sequence_pyprojv331(self):
"""Extra test cases that do not work with old pyproj versions that we get on python version 3.7 and below."""
assert to_bbox_dict([1, 2, 3, 4], crs="4326") == {
"west": 1,
"south": 2,
"east": 3,
"north": 4,
"crs": 4326,
}

def test_to_bbox_dict_from_sequence_mismatch(self):
with pytest.raises(InvalidBBoxException, match="Expected sequence with 4 items, but got 3."):
to_bbox_dict([1, 2, 3])
Expand Down Expand Up @@ -771,6 +801,28 @@ def test_to_bbox_dict_from_dict(self):
}
) == {"west": 1, "south": 2, "east": 3, "north": 4, "crs": 4326}

@pytest.mark.skipif(
# TODO #460 this skip is only necessary for python 3.6 and lower
pyproj.__version__ < ComparableVersion("3.3.1"),
reason="pyproj below 3.3.1 does not support int-like strings",
)
def test_to_bbox_dict_from_dict_for_pyprojv331(self):
"""Extra test cases that do not work with old pyproj versions that we get on python version 3.7 and below."""
assert to_bbox_dict({"west": 1, "south": 2, "east": 3, "north": 4, "crs": "4326"}) == {
"west": 1,
"south": 2,
"east": 3,
"north": 4,
"crs": 4326,
}
assert to_bbox_dict({"west": 1, "south": 2, "east": 3, "north": 4}, crs="4326") == {
"west": 1,
"south": 2,
"east": 3,
"north": 4,
"crs": 4326,
}

def test_to_bbox_dict_from_dict_missing_field(self):
with pytest.raises(InvalidBBoxException, match=re.escape("Missing bbox fields ['north', 'south', 'west']")):
to_bbox_dict({"east": 3})
Expand Down