Skip to content

Commit 555e3f6

Browse files
committed
Add experimental streaming remote import from source
1 parent c8e8450 commit 555e3f6

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

src/picterra/client.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def _upload_file_to_blobstore(upload_url: str, filename: str):
6767
logger.error("Error when uploading to blobstore %s" % upload_url)
6868
raise APIError(resp.text)
6969

70+
7071
class Feature(TypedDict):
7172
type: Literal["Feature"]
7273
properties: dict[str, Any]
@@ -1033,3 +1034,51 @@ def create_marker(
10331034
if not resp.ok:
10341035
raise APIError(resp.text)
10351036
return resp.json()
1037+
1038+
def import_raster_from_remote_source(
1039+
self,
1040+
raster_name: str,
1041+
folder_id: str,
1042+
source_id: str,
1043+
aoi_filename: str,
1044+
method: Literal["streaming"] = "streaming",
1045+
) -> str:
1046+
"""
1047+
This is an experimental feature
1048+
1049+
Import a raster from a remote imagery source given a GeoJSON file for the AOI
1050+
1051+
Args:
1052+
raster_name: Name of the new raster
1053+
folder_id: The id of the folder / project the raster will live in
1054+
source_id: The id of the remote imagery source to import from
1055+
filename: The filename of a GeoJSON file. This should contain a FeatureCollection of
1056+
Polygon/MultiPolygon representing the AOI of the new raster
1057+
1058+
Raises:
1059+
APIError: There was an error during import
1060+
"""
1061+
# Get upload URL
1062+
resp = self.sess.post(self._api_url("rasters/import/"))
1063+
if not resp.ok:
1064+
raise APIError(resp.text)
1065+
data = resp.json()
1066+
upload_url = data["upload_url"]
1067+
upload_id = data["upload_id"]
1068+
# Upload to blobstore
1069+
_upload_file_to_blobstore(upload_url, aoi_filename)
1070+
# Commit upload
1071+
resp = self.sess.post(
1072+
self._api_url(f"rasters/import/{upload_id}/commit/"),
1073+
json={
1074+
"method": method,
1075+
"source_id": source_id,
1076+
"folder_id": folder_id,
1077+
"name": raster_name,
1078+
},
1079+
)
1080+
if not resp.ok:
1081+
raise APIError(resp.text)
1082+
# Poll operation and get raster identifier
1083+
operation = self._wait_until_operation_completes(resp.json())
1084+
return operation["metadata"]["raster_id"]

tests/test_client.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,23 @@ def add_mock_detection_areas_upload_responses(raster_id):
312312
)
313313

314314

315+
def add_mock_remote_import_responses(upload_id, post_body):
316+
match = responses.json_params_matcher(post_body)
317+
# Upload initiation
318+
data = {"upload_url": "http://storage.example.com", "upload_id": upload_id}
319+
_add_api_response("rasters/import/", responses.POST, data)
320+
# Storage PUT
321+
responses.add(responses.PUT, "http://storage.example.com", status=200)
322+
# Commit
323+
_add_api_response(
324+
f"rasters/import/{upload_id}/commit/",
325+
responses.POST,
326+
OP_RESP,
327+
match=match,
328+
status=200,
329+
)
330+
331+
315332
def add_mock_detector_run_responses(detector_id):
316333
op_id = 43
317334
_add_api_response("detectors/%s/run/" % detector_id, responses.POST, OP_RESP)
@@ -1051,3 +1068,26 @@ def test_run_advanced_tool():
10511068
== "mock_operation_type"
10521069
)
10531070
assert len(responses.calls) == 2
1071+
1072+
1073+
@responses.activate
1074+
def test_import_raster_from_remote_source():
1075+
body = {
1076+
"method": "streaming",
1077+
"source_id": "source",
1078+
"folder_id": "project",
1079+
"name": "image",
1080+
}
1081+
add_mock_remote_import_responses("upload_id", body)
1082+
add_mock_operations_responses("success")
1083+
1084+
client = _client()
1085+
# This just tests that this doesn't raise
1086+
with tempfile.NamedTemporaryFile() as f:
1087+
assert (
1088+
client.import_raster_from_remote_source(
1089+
"image", "project", "source", f.name
1090+
)
1091+
== "foo"
1092+
)
1093+
assert len(responses.calls) == 4

0 commit comments

Comments
 (0)