ee-client 2.5.2__tar.gz → 2.6.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ee_client-2.5.2 → ee_client-2.6.1}/PKG-INFO +22 -2
- {ee_client-2.5.2 → ee_client-2.6.1}/README.rst +21 -1
- {ee_client-2.5.2 → ee_client-2.6.1}/ee_client.egg-info/PKG-INFO +22 -2
- {ee_client-2.5.2 → ee_client-2.6.1}/ee_client.egg-info/SOURCES.txt +1 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/__init__.py +1 -1
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/export/image.py +20 -2
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/export/table.py +14 -1
- {ee_client-2.5.2 → ee_client-2.6.1}/pyproject.toml +2 -2
- ee_client-2.6.1/tests/test_export_image.py +89 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_export_table.py +23 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/LICENSE +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/ee_client.egg-info/dependency_links.txt +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/ee_client.egg-info/requires.txt +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/ee_client.egg-info/top_level.txt +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/cache.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/client.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/data.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/exceptions.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/export/__init__.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/helpers.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/interfaces/__init__.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/interfaces/export.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/interfaces/operations.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/interfaces/tasks.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/models.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/oauth_app.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/sepal_credential_mixin.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/eeclient/tasks.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/setup.cfg +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_cache.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_client.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_data.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_integration_get_assets.py +0 -0
- {ee_client-2.5.2 → ee_client-2.6.1}/tests/test_models.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ee-client
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.1
|
|
4
4
|
Summary: extends the capabilities of the earthengine-api by providing custom session management and client interactions
|
|
5
5
|
Author-email: Daniel Guerrero <dfgm2006@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/dfguerrerom/ee-client
|
|
@@ -32,7 +32,27 @@ Dynamic: license-file
|
|
|
32
32
|
Earth Engine Client 🌎
|
|
33
33
|
==============================
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
.. image:: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml/badge.svg?branch=main
|
|
36
|
+
:target: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml
|
|
37
|
+
:alt: Tests
|
|
38
|
+
|
|
39
|
+
.. image:: https://img.shields.io/pypi/v/ee-client.svg
|
|
40
|
+
:target: https://pypi.org/project/ee-client/
|
|
41
|
+
:alt: PyPI version
|
|
42
|
+
|
|
43
|
+
.. image:: https://img.shields.io/pypi/pyversions/ee-client.svg
|
|
44
|
+
:target: https://pypi.org/project/ee-client/
|
|
45
|
+
:alt: Python versions
|
|
46
|
+
|
|
47
|
+
.. image:: https://img.shields.io/conda/vn/conda-forge/ee-client.svg
|
|
48
|
+
:target: https://anaconda.org/conda-forge/ee-client
|
|
49
|
+
:alt: Conda-Forge version
|
|
50
|
+
|
|
51
|
+
.. image:: https://img.shields.io/pypi/l/ee-client.svg
|
|
52
|
+
:target: https://github.com/dfguerrerom/ee-client/blob/main/LICENSE
|
|
53
|
+
:alt: License
|
|
54
|
+
|
|
55
|
+
The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
|
|
36
56
|
|
|
37
57
|
**Why This Package?**
|
|
38
58
|
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
Earth Engine Client 🌎
|
|
2
2
|
==============================
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
.. image:: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml/badge.svg?branch=main
|
|
5
|
+
:target: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml
|
|
6
|
+
:alt: Tests
|
|
7
|
+
|
|
8
|
+
.. image:: https://img.shields.io/pypi/v/ee-client.svg
|
|
9
|
+
:target: https://pypi.org/project/ee-client/
|
|
10
|
+
:alt: PyPI version
|
|
11
|
+
|
|
12
|
+
.. image:: https://img.shields.io/pypi/pyversions/ee-client.svg
|
|
13
|
+
:target: https://pypi.org/project/ee-client/
|
|
14
|
+
:alt: Python versions
|
|
15
|
+
|
|
16
|
+
.. image:: https://img.shields.io/conda/vn/conda-forge/ee-client.svg
|
|
17
|
+
:target: https://anaconda.org/conda-forge/ee-client
|
|
18
|
+
:alt: Conda-Forge version
|
|
19
|
+
|
|
20
|
+
.. image:: https://img.shields.io/pypi/l/ee-client.svg
|
|
21
|
+
:target: https://github.com/dfguerrerom/ee-client/blob/main/LICENSE
|
|
22
|
+
:alt: License
|
|
23
|
+
|
|
24
|
+
The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
|
|
5
25
|
|
|
6
26
|
**Why This Package?**
|
|
7
27
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ee-client
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.6.1
|
|
4
4
|
Summary: extends the capabilities of the earthengine-api by providing custom session management and client interactions
|
|
5
5
|
Author-email: Daniel Guerrero <dfgm2006@gmail.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/dfguerrerom/ee-client
|
|
@@ -32,7 +32,27 @@ Dynamic: license-file
|
|
|
32
32
|
Earth Engine Client 🌎
|
|
33
33
|
==============================
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
.. image:: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml/badge.svg?branch=main
|
|
36
|
+
:target: https://github.com/dfguerrerom/ee-client/actions/workflows/tests.yaml
|
|
37
|
+
:alt: Tests
|
|
38
|
+
|
|
39
|
+
.. image:: https://img.shields.io/pypi/v/ee-client.svg
|
|
40
|
+
:target: https://pypi.org/project/ee-client/
|
|
41
|
+
:alt: PyPI version
|
|
42
|
+
|
|
43
|
+
.. image:: https://img.shields.io/pypi/pyversions/ee-client.svg
|
|
44
|
+
:target: https://pypi.org/project/ee-client/
|
|
45
|
+
:alt: Python versions
|
|
46
|
+
|
|
47
|
+
.. image:: https://img.shields.io/conda/vn/conda-forge/ee-client.svg
|
|
48
|
+
:target: https://anaconda.org/conda-forge/ee-client
|
|
49
|
+
:alt: Conda-Forge version
|
|
50
|
+
|
|
51
|
+
.. image:: https://img.shields.io/pypi/l/ee-client.svg
|
|
52
|
+
:target: https://github.com/dfguerrerom/ee-client/blob/main/LICENSE
|
|
53
|
+
:alt: License
|
|
54
|
+
|
|
55
|
+
The **Earth Engine Session Client** is a Python package that extends the Google Earth Engine (GEE) API by introducing multi-user session management through custom authentication.
|
|
36
56
|
|
|
37
57
|
**Why This Package?**
|
|
38
58
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
from typing import TYPE_CHECKING, Optional, Union
|
|
3
|
-
from pydantic import BaseModel, ConfigDict, model_validator
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, field_validator, model_validator
|
|
4
4
|
from pydantic.alias_generators import to_camel
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
@@ -44,11 +44,23 @@ class EarthEngineDestination(BaseExportModel):
|
|
|
44
44
|
name: str
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
_IMAGE_FILE_FORMAT_ALIASES = {
|
|
48
|
+
"GeoTIFF": "GEO_TIFF",
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
47
52
|
class DriveOptions(BaseExportModel):
|
|
48
53
|
# Removed default so that users must supply a file_format.
|
|
49
54
|
file_format: ImageFileFormat
|
|
50
55
|
drive_destination: DriveDestination
|
|
51
56
|
|
|
57
|
+
@field_validator("file_format", mode="before")
|
|
58
|
+
@classmethod
|
|
59
|
+
def _accept_legacy_aliases(cls, v):
|
|
60
|
+
if isinstance(v, str):
|
|
61
|
+
return _IMAGE_FILE_FORMAT_ALIASES.get(v, v)
|
|
62
|
+
return v
|
|
63
|
+
|
|
52
64
|
# TODO: Add support for other export options
|
|
53
65
|
# TODO: add support for format_options
|
|
54
66
|
# See the api: https://developers.google.com/earth-engine/reference/rest/v1alpha/ImageFileExportOptions
|
|
@@ -173,7 +185,13 @@ async def _export_image(
|
|
|
173
185
|
image, updated_image_params, dimensions_consumed = image._apply_crs_and_affine(
|
|
174
186
|
image_params
|
|
175
187
|
)
|
|
176
|
-
|
|
188
|
+
# _apply_selection_and_scale returns a new image wrapped in
|
|
189
|
+
# clipToBoundsAndScale(geometry=region); discarding the return value would
|
|
190
|
+
# serialize the original unbounded image and cause GEE to reject the task
|
|
191
|
+
# with "Unable to export unbounded image." (issue #20)
|
|
192
|
+
image, _ = image._apply_selection_and_scale(
|
|
193
|
+
updated_image_params, dimensions_consumed
|
|
194
|
+
)
|
|
177
195
|
|
|
178
196
|
expression = serializer.encode(image, for_cloud_api=True)
|
|
179
197
|
request_params["expression"] = expression
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
2
|
from typing import TYPE_CHECKING, Optional
|
|
3
|
-
from pydantic import BaseModel, ConfigDict
|
|
3
|
+
from pydantic import BaseModel, ConfigDict, field_validator
|
|
4
4
|
from pydantic.alias_generators import to_camel
|
|
5
5
|
|
|
6
6
|
if TYPE_CHECKING:
|
|
@@ -38,11 +38,24 @@ class EarthEngineDestination(BaseExportModel):
|
|
|
38
38
|
name: str
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
_TABLE_FILE_FORMAT_ALIASES = {
|
|
42
|
+
"GeoJSON": "GEO_JSON",
|
|
43
|
+
"Shapefile": "SHP",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
41
47
|
class DriveOptions(BaseExportModel):
|
|
42
48
|
# Removed default so that users must supply a file_format.
|
|
43
49
|
file_format: TableFileFormat
|
|
44
50
|
drive_destination: DriveDestination
|
|
45
51
|
|
|
52
|
+
@field_validator("file_format", mode="before")
|
|
53
|
+
@classmethod
|
|
54
|
+
def _accept_legacy_aliases(cls, v):
|
|
55
|
+
if isinstance(v, str):
|
|
56
|
+
return _TABLE_FILE_FORMAT_ALIASES.get(v, v)
|
|
57
|
+
return v
|
|
58
|
+
|
|
46
59
|
|
|
47
60
|
class AssetOptions(BaseExportModel):
|
|
48
61
|
earth_engine_destination: EarthEngineDestination
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ee-client"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.6.1"
|
|
8
8
|
description = "extends the capabilities of the earthengine-api by providing custom session management and client interactions"
|
|
9
9
|
readme = { file = "README.rst", content-type = "text/x-rst" }
|
|
10
10
|
authors = [
|
|
@@ -66,7 +66,7 @@ branch = true
|
|
|
66
66
|
[tool.commitizen]
|
|
67
67
|
tag_format = "v$major.$minor.$patch$prerelease"
|
|
68
68
|
update_changelog_on_bump = false
|
|
69
|
-
version = "2.
|
|
69
|
+
version = "2.6.1"
|
|
70
70
|
version_files = [
|
|
71
71
|
"pyproject.toml:version",
|
|
72
72
|
"eeclient/__init__.py:__version__",
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from eeclient.export.image import (
|
|
6
|
+
DriveDestination,
|
|
7
|
+
DriveOptions,
|
|
8
|
+
ImageFileFormat,
|
|
9
|
+
_export_image,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def test_drive_options_accepts_legacy_geotiff_alias():
|
|
14
|
+
opts = DriveOptions(
|
|
15
|
+
file_format="GeoTIFF",
|
|
16
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
17
|
+
)
|
|
18
|
+
assert opts.file_format == ImageFileFormat.GEO_TIFF
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_drive_options_accepts_canonical_value():
|
|
22
|
+
opts = DriveOptions(
|
|
23
|
+
file_format="GEO_TIFF",
|
|
24
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
25
|
+
)
|
|
26
|
+
assert opts.file_format == ImageFileFormat.GEO_TIFF
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_drive_options_rejects_unknown_string():
|
|
30
|
+
with pytest.raises(ValueError):
|
|
31
|
+
DriveOptions(
|
|
32
|
+
file_format="NotAFormat",
|
|
33
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@pytest.mark.asyncio
|
|
38
|
+
async def test_export_image_uses_clipped_image_from_selection_and_scale():
|
|
39
|
+
"""Regression test for issue #20.
|
|
40
|
+
|
|
41
|
+
`ee.Image._apply_selection_and_scale` returns a new image wrapped in
|
|
42
|
+
`clipToBoundsAndScale(geometry=region)`. The export flow must serialize
|
|
43
|
+
that clipped image, not the original, or GEE rejects the task as
|
|
44
|
+
"Unable to export unbounded image".
|
|
45
|
+
"""
|
|
46
|
+
original_image = MagicMock(name="original_image")
|
|
47
|
+
crs_applied_image = MagicMock(name="crs_applied_image")
|
|
48
|
+
clipped_image = MagicMock(name="clipped_image")
|
|
49
|
+
|
|
50
|
+
original_image._apply_crs_and_affine.return_value = (
|
|
51
|
+
crs_applied_image,
|
|
52
|
+
{"region": "geom", "scale": 30},
|
|
53
|
+
False,
|
|
54
|
+
)
|
|
55
|
+
crs_applied_image._apply_selection_and_scale.return_value = (
|
|
56
|
+
clipped_image,
|
|
57
|
+
{},
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
client = MagicMock()
|
|
61
|
+
client.rest_call = AsyncMock(
|
|
62
|
+
return_value={"name": "projects/p/operations/op", "metadata": {}}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
drive_options = DriveOptions(
|
|
66
|
+
file_format=ImageFileFormat.GEO_TIFF,
|
|
67
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
with (
|
|
71
|
+
patch("eeclient.export.image.serializer.encode") as mock_encode,
|
|
72
|
+
patch("eeclient.export.image.Task.model_validate") as mock_validate,
|
|
73
|
+
):
|
|
74
|
+
mock_encode.return_value = {"result": "encoded"}
|
|
75
|
+
mock_validate.return_value = MagicMock()
|
|
76
|
+
|
|
77
|
+
await _export_image(
|
|
78
|
+
client=client,
|
|
79
|
+
image=original_image,
|
|
80
|
+
drive_options=drive_options,
|
|
81
|
+
region="geom",
|
|
82
|
+
scale=30,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# The serialized expression must be the clipped image, not the original
|
|
86
|
+
# or the intermediate crs-applied image.
|
|
87
|
+
mock_encode.assert_called_once()
|
|
88
|
+
encoded_image = mock_encode.call_args.args[0]
|
|
89
|
+
assert encoded_image is clipped_image
|
|
@@ -42,6 +42,29 @@ def test_drive_export_options_serialize_as_file_export_options():
|
|
|
42
42
|
assert "assetExportOptions" not in payload
|
|
43
43
|
|
|
44
44
|
|
|
45
|
+
@pytest.mark.parametrize(
|
|
46
|
+
"alias,canonical",
|
|
47
|
+
[
|
|
48
|
+
("GeoJSON", TableFileFormat.GEO_JSON),
|
|
49
|
+
("Shapefile", TableFileFormat.SHP),
|
|
50
|
+
],
|
|
51
|
+
)
|
|
52
|
+
def test_drive_options_accepts_legacy_table_aliases(alias, canonical):
|
|
53
|
+
opts = DriveOptions(
|
|
54
|
+
file_format=alias,
|
|
55
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
56
|
+
)
|
|
57
|
+
assert opts.file_format == canonical
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_drive_options_rejects_unknown_string():
|
|
61
|
+
with pytest.raises(ValueError):
|
|
62
|
+
DriveOptions(
|
|
63
|
+
file_format="NotAFormat",
|
|
64
|
+
drive_destination=DriveDestination(filename_prefix="out"),
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
45
68
|
@pytest.mark.asyncio
|
|
46
69
|
async def test_table_to_asset_async_sends_asset_export_options():
|
|
47
70
|
client = AsyncMock()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|