Skip to content

Commit faf681b

Browse files
committed
[beta] Add function to download a vector layer
1 parent 414ab8f commit faf681b

File tree

3 files changed

+74
-4
lines changed

3 files changed

+74
-4
lines changed

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
setup(
66
name="picterra",
7-
version="1.1.0",
7+
version="1.2.0",
88
description="Picterra API client",
99
package_dir={"": "src"},
1010
packages=find_packages("src"),

src/picterra/client.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,11 @@ def request(self, *args, **kwargs):
4141

4242

4343
def _download_to_file(url, filename):
44-
if not (os.path.exists(filename) and os.path.isfile(filename)):
45-
raise ValueError("Invalid file: " + filename)
4644
# Given we do not use self.sess the timeout is disabled (requests default), and this
4745
# is good as file download can take a long time
4846
with requests.get(url, stream=True) as r:
4947
r.raise_for_status()
50-
with open(filename, "wb") as f:
48+
with open(filename, "wb+") as f:
5149
logger.debug("Downloading to file %s.." % filename)
5250
for chunk in r.iter_content(chunk_size=CHUNK_SIZE_BYTES):
5351
if chunk: # filter out keep-alive new chunks
@@ -943,6 +941,30 @@ def delete_vector_layer(self, vector_layer_id: UUID):
943941
if not resp.ok:
944942
raise APIError(resp.text)
945943

944+
def download_vector_layer_to_file(self, vector_layer_id: UUID, filename: str):
945+
"""
946+
Downloads a vector layer
947+
948+
This a **beta** function, subject to change.
949+
950+
Args:
951+
vector_layer_id: The id of the vector layer to download
952+
filename: existing file to save the vector layer in
953+
"""
954+
resp = self.sess.get(self._api_url("vector_layers/%s/" % vector_layer_id))
955+
if not resp.ok:
956+
raise APIError(resp.text)
957+
urls = resp.json()["geojson_urls"]
958+
final_fc = {"type": "FeatureCollection", "features": []}
959+
for url in urls:
960+
with tempfile.NamedTemporaryFile("w+") as f:
961+
_download_to_file(url, f.name)
962+
fc = json.load(f)
963+
for feature in fc["features"]:
964+
final_fc["features"].append(feature)
965+
with open(filename, "w") as fp:
966+
json.dump(final_fc, fp)
967+
946968
def list_raster_markers(self, raster_id):
947969
"""
948970
This a **beta** function, subject to change.

tests/test_client.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,40 @@ def add_mock_vector_layer_responses(upload_id, raster_id, name, color):
337337
)
338338

339339

340+
def add_mock_vector_layer_download_responses(layer_id, urls_num=1):
341+
url = "vector_layers/%s/" % layer_id
342+
data = {
343+
"name": "layer%s" % layer_id,
344+
"raster_id": "raster-id",
345+
"count": 1,
346+
"color": "#aa0000",
347+
"id": layer_id,
348+
"geojson_urls": [
349+
"http://layer%s.geojson.example.com" % str(i) for i in range(urls_num)
350+
],
351+
}
352+
_add_api_response(url, json=data)
353+
features = []
354+
for i in range(urls_num):
355+
url = "http://layer%s.geojson.example.com" % str(i)
356+
temp_features = [
357+
{
358+
"type": "Feature",
359+
"geometry": make_geojson_multipolygon(j + 1),
360+
"properties": {},
361+
}
362+
for j in range(i + 1)
363+
]
364+
for f in temp_features:
365+
features.append(f)
366+
responses.add(
367+
responses.GET,
368+
url,
369+
body=json.dumps({"type": "FeatureCollection", "features": temp_features}),
370+
)
371+
return {"type": "FeatureCollection", "features": features}
372+
373+
340374
def make_geojson_multipolygon(npolygons=1):
341375
coords = []
342376
for i in range(npolygons):
@@ -872,6 +906,20 @@ def test_edit_vector_layer():
872906
assert len(responses.calls) == 1
873907

874908

909+
@responses.activate
910+
def test_download_vector_layer_to_file():
911+
expected_content = add_mock_vector_layer_download_responses("foobar", 2)
912+
client = _client()
913+
with tempfile.NamedTemporaryFile() as fp:
914+
client.download_vector_layer_to_file("foobar", fp.name)
915+
fc = json.load(fp)
916+
assert fc == expected_content and len(fc["features"]) == 3
917+
assert (
918+
fc["type"] == "FeatureCollection" and fc["features"][0]["type"] == "Feature"
919+
)
920+
assert len(responses.calls) == 3
921+
922+
875923
@responses.activate
876924
def test_list_raster_markers():
877925
client = _client()

0 commit comments

Comments
 (0)