terrakio-core 0.4.98.1b4__py3-none-any.whl → 0.4.98.1b6__py3-none-any.whl
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.
Potentially problematic release.
This version of terrakio-core might be problematic. Click here for more details.
- terrakio_core/endpoints/mass_stats.py +470 -317
- terrakio_core/endpoints/model_management.py +0 -125
- {terrakio_core-0.4.98.1b4.dist-info → terrakio_core-0.4.98.1b6.dist-info}/METADATA +1 -1
- {terrakio_core-0.4.98.1b4.dist-info → terrakio_core-0.4.98.1b6.dist-info}/RECORD +5 -5
- {terrakio_core-0.4.98.1b4.dist-info → terrakio_core-0.4.98.1b6.dist-info}/WHEEL +0 -0
|
@@ -1,34 +1,34 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
2
3
|
import time
|
|
3
|
-
import typer
|
|
4
4
|
from typing import Dict, Any, Optional, List
|
|
5
|
-
from dateutil import parser
|
|
6
5
|
|
|
6
|
+
import aiohttp
|
|
7
|
+
import typer
|
|
8
|
+
from dateutil import parser
|
|
7
9
|
from rich.console import Console
|
|
8
10
|
from rich.progress import Progress, TextColumn, BarColumn, TaskProgressColumn, TimeElapsedColumn
|
|
9
11
|
|
|
10
12
|
from ..exceptions import (
|
|
13
|
+
CancelAllTasksError,
|
|
14
|
+
CancelCollectionTasksError,
|
|
15
|
+
CancelTaskError,
|
|
16
|
+
CollectionAlreadyExistsError,
|
|
17
|
+
CollectionNotFoundError,
|
|
11
18
|
CreateCollectionError,
|
|
19
|
+
DeleteCollectionError,
|
|
20
|
+
DownloadFilesError,
|
|
12
21
|
GetCollectionError,
|
|
13
|
-
|
|
14
|
-
CollectionNotFoundError,
|
|
15
|
-
CollectionAlreadyExistsError,
|
|
22
|
+
GetTaskError,
|
|
16
23
|
InvalidCollectionTypeError,
|
|
17
|
-
|
|
24
|
+
ListCollectionsError,
|
|
18
25
|
ListTasksError,
|
|
19
|
-
UploadRequestsError,
|
|
20
|
-
UploadArtifactsError,
|
|
21
|
-
GetTaskError,
|
|
22
26
|
TaskNotFoundError,
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
CancelCollectionTasksError,
|
|
26
|
-
CancelAllTasksError,
|
|
27
|
+
UploadArtifactsError,
|
|
28
|
+
UploadRequestsError,
|
|
27
29
|
)
|
|
28
30
|
from ..helper.decorators import require_api_key
|
|
29
31
|
|
|
30
|
-
import aiohttp # Make sure this is imported at the top
|
|
31
|
-
|
|
32
32
|
|
|
33
33
|
class MassStats:
|
|
34
34
|
def __init__(self, client):
|
|
@@ -156,6 +156,7 @@ class MassStats:
|
|
|
156
156
|
|
|
157
157
|
self.console.print(f"[bold green]All {number_of_jobs} jobs finished![/bold green]")
|
|
158
158
|
|
|
159
|
+
# below are functions related to collection
|
|
159
160
|
@require_api_key
|
|
160
161
|
async def create_collection(
|
|
161
162
|
self,
|
|
@@ -202,45 +203,6 @@ class MassStats:
|
|
|
202
203
|
|
|
203
204
|
return response
|
|
204
205
|
|
|
205
|
-
@require_api_key
|
|
206
|
-
async def delete_collection(
|
|
207
|
-
self,
|
|
208
|
-
collection: str,
|
|
209
|
-
full: Optional[bool] = False,
|
|
210
|
-
outputs: Optional[list] = [],
|
|
211
|
-
data: Optional[bool] = False
|
|
212
|
-
) -> Dict[str, Any]:
|
|
213
|
-
"""
|
|
214
|
-
Delete a collection by name.
|
|
215
|
-
|
|
216
|
-
Args:
|
|
217
|
-
collection: The name of the collection to delete (required)
|
|
218
|
-
full: Delete the full collection (optional, defaults to False)
|
|
219
|
-
outputs: Specific output folders to delete (optional, defaults to empty list)
|
|
220
|
-
data: Whether to delete raw data (xdata folder) (optional, defaults to False)
|
|
221
|
-
|
|
222
|
-
Returns:
|
|
223
|
-
API response as a dictionary confirming deletion
|
|
224
|
-
|
|
225
|
-
Raises:
|
|
226
|
-
CollectionNotFoundError: If the collection is not found
|
|
227
|
-
DeleteCollectionError: If the API request fails due to unknown reasons
|
|
228
|
-
"""
|
|
229
|
-
payload = {
|
|
230
|
-
"full": full,
|
|
231
|
-
"outputs": outputs,
|
|
232
|
-
"data": data
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
response, status = await self._client._terrakio_request("DELETE", f"collections/{collection}", json=payload)
|
|
236
|
-
|
|
237
|
-
if status != 200:
|
|
238
|
-
if status == 404:
|
|
239
|
-
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
240
|
-
raise DeleteCollectionError(f"Delete collection failed with status {status}", status_code=status)
|
|
241
|
-
|
|
242
|
-
return response
|
|
243
|
-
|
|
244
206
|
@require_api_key
|
|
245
207
|
async def get_collection(self, collection: str) -> Dict[str, Any]:
|
|
246
208
|
"""
|
|
@@ -304,95 +266,72 @@ class MassStats:
|
|
|
304
266
|
return response
|
|
305
267
|
|
|
306
268
|
@require_api_key
|
|
307
|
-
async def
|
|
308
|
-
self,
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
269
|
+
async def delete_collection(
|
|
270
|
+
self,
|
|
271
|
+
collection: str,
|
|
272
|
+
full: Optional[bool] = False,
|
|
273
|
+
outputs: Optional[list] = [],
|
|
274
|
+
data: Optional[bool] = False
|
|
275
|
+
) -> Dict[str, Any]:
|
|
312
276
|
"""
|
|
313
|
-
|
|
277
|
+
Delete a collection by name.
|
|
314
278
|
|
|
315
279
|
Args:
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
280
|
+
collection: The name of the collection to delete (required)
|
|
281
|
+
full: Delete the full collection (optional, defaults to False)
|
|
282
|
+
outputs: Specific output folders to delete (optional, defaults to empty list)
|
|
283
|
+
data: Whether to delete raw data (xdata folder) (optional, defaults to False)
|
|
284
|
+
|
|
319
285
|
Returns:
|
|
320
|
-
API response as a
|
|
286
|
+
API response as a dictionary confirming deletion
|
|
321
287
|
|
|
322
288
|
Raises:
|
|
323
|
-
|
|
289
|
+
CollectionNotFoundError: If the collection is not found
|
|
290
|
+
DeleteCollectionError: If the API request fails due to unknown reasons
|
|
324
291
|
"""
|
|
325
|
-
|
|
326
|
-
"
|
|
327
|
-
"
|
|
292
|
+
payload = {
|
|
293
|
+
"full": full,
|
|
294
|
+
"outputs": outputs,
|
|
295
|
+
"data": data
|
|
328
296
|
}
|
|
329
|
-
response, status = await self._client._terrakio_request("GET", "tasks", params=params)
|
|
330
|
-
|
|
331
|
-
if status != 200:
|
|
332
|
-
raise ListTasksError(f"List tasks failed with status {status}", status_code=status)
|
|
333
|
-
|
|
334
|
-
return response
|
|
335
|
-
|
|
336
|
-
@require_api_key
|
|
337
|
-
async def upload_requests(
|
|
338
|
-
self,
|
|
339
|
-
collection: str
|
|
340
|
-
) -> Dict[str, Any]:
|
|
341
|
-
"""
|
|
342
|
-
Retrieve signed url to upload requests for a collection.
|
|
343
|
-
|
|
344
|
-
Args:
|
|
345
|
-
collection: Name of collection
|
|
346
297
|
|
|
347
|
-
|
|
348
|
-
API response as a dictionary containing the upload URL
|
|
349
|
-
|
|
350
|
-
Raises:
|
|
351
|
-
CollectionNotFoundError: If the collection is not found
|
|
352
|
-
UploadRequestsError: If the API request fails due to unknown reasons
|
|
353
|
-
"""
|
|
354
|
-
response, status = await self._client._terrakio_request("GET", f"collections/{collection}/upload/requests")
|
|
298
|
+
response, status = await self._client._terrakio_request("DELETE", f"collections/{collection}", json=payload)
|
|
355
299
|
|
|
356
300
|
if status != 200:
|
|
357
301
|
if status == 404:
|
|
358
302
|
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
359
|
-
raise
|
|
303
|
+
raise DeleteCollectionError(f"Delete collection failed with status {status}", status_code=status)
|
|
360
304
|
|
|
361
305
|
return response
|
|
362
306
|
|
|
307
|
+
# below are functions related to tasks
|
|
363
308
|
@require_api_key
|
|
364
|
-
async def
|
|
309
|
+
async def list_tasks(
|
|
365
310
|
self,
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
) -> Dict[str, Any]:
|
|
311
|
+
limit: Optional[int] = 10,
|
|
312
|
+
page: Optional[int] = 0
|
|
313
|
+
) -> List[Dict[str, Any]]:
|
|
370
314
|
"""
|
|
371
|
-
|
|
315
|
+
List tasks for the current user.
|
|
372
316
|
|
|
373
317
|
Args:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
compressed: Whether to compress the file using gzip or not (defaults to True)
|
|
318
|
+
limit: Number of tasks to return (optional, defaults to 10)
|
|
319
|
+
page: Page number (optional, defaults to 0)
|
|
377
320
|
|
|
378
321
|
Returns:
|
|
379
|
-
API response as a
|
|
380
|
-
|
|
322
|
+
API response as a list of dictionaries containing task information
|
|
323
|
+
|
|
381
324
|
Raises:
|
|
382
|
-
|
|
383
|
-
UploadArtifactsError: If the API request fails due to unknown reasons
|
|
325
|
+
ListTasksError: If the API request fails due to unknown reasons
|
|
384
326
|
"""
|
|
385
327
|
params = {
|
|
386
|
-
"
|
|
387
|
-
"
|
|
328
|
+
"limit": limit,
|
|
329
|
+
"page": page
|
|
388
330
|
}
|
|
389
|
-
|
|
390
|
-
response, status = await self._client._terrakio_request("GET", f"collections/{collection}/upload", params=params)
|
|
331
|
+
response, status = await self._client._terrakio_request("GET", "tasks", params=params)
|
|
391
332
|
|
|
392
333
|
if status != 200:
|
|
393
|
-
|
|
394
|
-
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
395
|
-
raise UploadArtifactsError(f"Upload artifacts failed with status {status}", status_code=status)
|
|
334
|
+
raise ListTasksError(f"List tasks failed with status {status}", status_code=status)
|
|
396
335
|
|
|
397
336
|
return response
|
|
398
337
|
|
|
@@ -424,205 +363,114 @@ class MassStats:
|
|
|
424
363
|
return response
|
|
425
364
|
|
|
426
365
|
@require_api_key
|
|
427
|
-
async def
|
|
366
|
+
async def cancel_task(
|
|
428
367
|
self,
|
|
429
|
-
|
|
430
|
-
output: str,
|
|
431
|
-
skip_existing: Optional[bool] = True,
|
|
432
|
-
force_loc: Optional[bool] = None,
|
|
433
|
-
server: Optional[str] = None
|
|
368
|
+
task_id: str
|
|
434
369
|
) -> Dict[str, Any]:
|
|
435
370
|
"""
|
|
436
|
-
|
|
371
|
+
Cancel a task by task ID.
|
|
437
372
|
|
|
438
373
|
Args:
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
force_loc: Write data directly to the cloud under this folder
|
|
442
|
-
skip_existing: Skip existing data
|
|
443
|
-
server: Server to use
|
|
444
|
-
|
|
374
|
+
task_id: ID of task to cancel
|
|
375
|
+
|
|
445
376
|
Returns:
|
|
446
377
|
API response as a dictionary containing task information
|
|
447
378
|
|
|
448
379
|
Raises:
|
|
449
|
-
|
|
450
|
-
|
|
380
|
+
TaskNotFoundError: If the task is not found
|
|
381
|
+
CancelTaskError: If the API request fails due to unknown reasons
|
|
451
382
|
"""
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
if force_loc is not None:
|
|
455
|
-
payload["force_loc"] = force_loc
|
|
456
|
-
if server is not None:
|
|
457
|
-
payload["server"] = server
|
|
383
|
+
response, status = await self._client._terrakio_request("POST", f"tasks/cancel/{task_id}")
|
|
458
384
|
|
|
459
|
-
response, status = await self._client._terrakio_request("POST", f"collections/{collection}/generate_data", json=payload)
|
|
460
|
-
|
|
461
385
|
if status != 200:
|
|
462
386
|
if status == 404:
|
|
463
|
-
raise
|
|
464
|
-
raise
|
|
465
|
-
|
|
387
|
+
raise TaskNotFoundError(f"Task {task_id} not found", status_code=status)
|
|
388
|
+
raise CancelTaskError(f"Cancel task failed with status {status}", status_code=status)
|
|
389
|
+
|
|
466
390
|
return response
|
|
467
391
|
|
|
468
392
|
@require_api_key
|
|
469
|
-
async def
|
|
393
|
+
async def cancel_collection_tasks(
|
|
470
394
|
self,
|
|
471
|
-
collection: str
|
|
472
|
-
expressions: list[str],
|
|
473
|
-
filters: list[str],
|
|
474
|
-
aoi: dict,
|
|
475
|
-
samples: int,
|
|
476
|
-
crs: str,
|
|
477
|
-
tile_size: int,
|
|
478
|
-
res: float,
|
|
479
|
-
output: str,
|
|
480
|
-
year_range: Optional[list[int]] = None,
|
|
481
|
-
server: Optional[str] = None
|
|
395
|
+
collection: str
|
|
482
396
|
) -> Dict[str, Any]:
|
|
483
397
|
"""
|
|
484
|
-
|
|
398
|
+
Cancel all tasks for a collection.
|
|
485
399
|
|
|
486
400
|
Args:
|
|
487
401
|
collection: Name of collection
|
|
488
|
-
expressions: List of expressions for each sample
|
|
489
|
-
filters: Expressions to filter sample areas
|
|
490
|
-
aoi: AOI to sample from (geojson dict)
|
|
491
|
-
samples: Number of samples to generate
|
|
492
|
-
crs: CRS of AOI
|
|
493
|
-
tile_size: Pixel width and height of samples
|
|
494
|
-
res: Resolution of samples
|
|
495
|
-
output: Sample output type
|
|
496
|
-
year_range: Optional year range filter
|
|
497
|
-
server: Server to use
|
|
498
402
|
|
|
499
403
|
Returns:
|
|
500
|
-
API response as a dictionary containing task information
|
|
404
|
+
API response as a dictionary containing task information for the collection
|
|
501
405
|
|
|
502
406
|
Raises:
|
|
503
407
|
CollectionNotFoundError: If the collection is not found
|
|
504
|
-
|
|
408
|
+
CancelCollectionTasksError: If the API request fails due to unknown reasons
|
|
505
409
|
"""
|
|
506
|
-
|
|
507
|
-
"expressions": expressions,
|
|
508
|
-
"filters": filters,
|
|
509
|
-
"aoi": aoi,
|
|
510
|
-
"samples": samples,
|
|
511
|
-
"crs": crs,
|
|
512
|
-
"tile_size": tile_size,
|
|
513
|
-
"res": res,
|
|
514
|
-
"output": output
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
if year_range is not None:
|
|
518
|
-
payload["year_range"] = year_range
|
|
519
|
-
if server is not None:
|
|
520
|
-
payload["server"] = server
|
|
410
|
+
response, status = await self._client._terrakio_request("POST", f"collections/{collection}/cancel")
|
|
521
411
|
|
|
522
|
-
response, status = await self._client._terrakio_request("POST", f"collections/{collection}/training_samples", json=payload)
|
|
523
|
-
|
|
524
412
|
if status != 200:
|
|
525
413
|
if status == 404:
|
|
526
414
|
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
527
|
-
raise
|
|
528
|
-
|
|
415
|
+
raise CancelCollectionTasksError(f"Cancel collection tasks failed with status {status}", status_code=status)
|
|
416
|
+
|
|
529
417
|
return response
|
|
530
418
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
# Raises:
|
|
550
|
-
# CollectionNotFoundError: If the collection is not found
|
|
551
|
-
# GetTaskError: If the API request fails due to unknown reasons
|
|
552
|
-
# """
|
|
553
|
-
# # payload = {
|
|
554
|
-
# # "folder": folder,
|
|
555
|
-
# # "consumer": consumer
|
|
556
|
-
# # }
|
|
557
|
-
# # we have the consumer as a string, we need to read in the file and then pass in the content
|
|
558
|
-
# with open(consumer, 'rb') as f:
|
|
559
|
-
# files = {
|
|
560
|
-
# 'consumer': ('consumer.py', f.read(), 'text/plain')
|
|
561
|
-
# }
|
|
562
|
-
# data = {
|
|
563
|
-
# 'folder': folder
|
|
564
|
-
# }
|
|
565
|
-
|
|
566
|
-
# # response, status = await self._client._terrakio_request("POST", f"collections/{collection}/post_process", json=payload)
|
|
567
|
-
# response, status = await self._client._terrakio_request(
|
|
568
|
-
# "POST",
|
|
569
|
-
# f"collections/{collection}/post_process",
|
|
570
|
-
# files=files,
|
|
571
|
-
# data=data
|
|
572
|
-
# )
|
|
573
|
-
# if status != 200:
|
|
574
|
-
# if status == 404:
|
|
575
|
-
# raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
576
|
-
# raise GetTaskError(f"Post processing failed with status {status}", status_code=status)
|
|
577
|
-
|
|
578
|
-
# return response
|
|
419
|
+
@require_api_key
|
|
420
|
+
async def cancel_all_tasks(
|
|
421
|
+
self
|
|
422
|
+
) -> Dict[str, Any]:
|
|
423
|
+
"""
|
|
424
|
+
Cancel all tasks for the current user.
|
|
425
|
+
|
|
426
|
+
Returns:
|
|
427
|
+
API response as a dictionary containing task information for all tasks
|
|
428
|
+
|
|
429
|
+
Raises:
|
|
430
|
+
CancelAllTasksError: If the API request fails due to unknown reasons
|
|
431
|
+
"""
|
|
432
|
+
response, status = await self._client._terrakio_request("POST", "tasks/cancel")
|
|
433
|
+
|
|
434
|
+
if status != 200:
|
|
435
|
+
raise CancelAllTasksError(f"Cancel all tasks failed with status {status}", status_code=status)
|
|
579
436
|
|
|
437
|
+
return response
|
|
580
438
|
|
|
439
|
+
# below are functions related to the web ui and needs to be deleted in the future
|
|
581
440
|
@require_api_key
|
|
582
|
-
async def
|
|
441
|
+
async def upload_artifacts(
|
|
583
442
|
self,
|
|
584
443
|
collection: str,
|
|
585
|
-
|
|
586
|
-
|
|
444
|
+
file_type: str,
|
|
445
|
+
compressed: Optional[bool] = True
|
|
587
446
|
) -> Dict[str, Any]:
|
|
588
447
|
"""
|
|
589
|
-
|
|
448
|
+
Retrieve signed url to upload artifact file to a collection.
|
|
590
449
|
|
|
591
450
|
Args:
|
|
592
451
|
collection: Name of collection
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
452
|
+
file_type: The extension of the file
|
|
453
|
+
compressed: Whether to compress the file using gzip or not (defaults to True)
|
|
454
|
+
|
|
596
455
|
Returns:
|
|
597
|
-
API response as a dictionary containing
|
|
456
|
+
API response as a dictionary containing the upload URL
|
|
598
457
|
|
|
599
458
|
Raises:
|
|
600
459
|
CollectionNotFoundError: If the collection is not found
|
|
601
|
-
|
|
460
|
+
UploadArtifactsError: If the API request fails due to unknown reasons
|
|
602
461
|
"""
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
filename='consumer.py', # Filename
|
|
611
|
-
content_type='text/x-python' # MIME type
|
|
612
|
-
)
|
|
613
|
-
|
|
614
|
-
# Send using data= with FormData object (NOT files=)
|
|
615
|
-
response, status = await self._client._terrakio_request(
|
|
616
|
-
"POST",
|
|
617
|
-
f"collections/{collection}/post_process",
|
|
618
|
-
data=form # ✅ Pass FormData as data
|
|
619
|
-
)
|
|
620
|
-
|
|
462
|
+
params = {
|
|
463
|
+
"file_type": file_type,
|
|
464
|
+
"compressed": str(compressed).lower(),
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
response, status = await self._client._terrakio_request("GET", f"collections/{collection}/upload", params=params)
|
|
468
|
+
|
|
621
469
|
if status != 200:
|
|
622
470
|
if status == 404:
|
|
623
471
|
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
624
|
-
raise
|
|
625
|
-
|
|
472
|
+
raise UploadArtifactsError(f"Upload artifacts failed with status {status}", status_code=status)
|
|
473
|
+
|
|
626
474
|
return response
|
|
627
475
|
|
|
628
476
|
@require_api_key
|
|
@@ -716,120 +564,425 @@ class MassStats:
|
|
|
716
564
|
|
|
717
565
|
return response
|
|
718
566
|
|
|
567
|
+
async def _upload_requests(
|
|
568
|
+
self,
|
|
569
|
+
collection: str
|
|
570
|
+
) -> Dict[str, Any]:
|
|
571
|
+
"""
|
|
572
|
+
Retrieve signed url to upload requests for a collection.
|
|
573
|
+
|
|
574
|
+
Args:
|
|
575
|
+
collection: Name of collection
|
|
576
|
+
|
|
577
|
+
Returns:
|
|
578
|
+
API response as a dictionary containing the upload URL
|
|
579
|
+
|
|
580
|
+
Raises:
|
|
581
|
+
CollectionNotFoundError: If the collection is not found
|
|
582
|
+
UploadRequestsError: If the API request fails due to unknown reasons
|
|
583
|
+
"""
|
|
584
|
+
response, status = await self._client._terrakio_request("GET", f"collections/{collection}/upload/requests")
|
|
585
|
+
|
|
586
|
+
if status != 200:
|
|
587
|
+
if status == 404:
|
|
588
|
+
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
589
|
+
raise UploadRequestsError(f"Upload requests failed with status {status}", status_code=status)
|
|
590
|
+
|
|
591
|
+
return response
|
|
592
|
+
|
|
593
|
+
@require_api_key
|
|
594
|
+
async def _upload_file(self, file_path: str, url: str, use_gzip: bool = True):
|
|
595
|
+
"""
|
|
596
|
+
Helper method to upload a JSON file to a signed URL.
|
|
597
|
+
|
|
598
|
+
Args:
|
|
599
|
+
file_path: Path to the JSON file
|
|
600
|
+
url: Signed URL to upload to
|
|
601
|
+
use_gzip: Whether to compress the file with gzip
|
|
602
|
+
"""
|
|
603
|
+
try:
|
|
604
|
+
with open(file_path, 'r') as file:
|
|
605
|
+
json_data = json.load(file)
|
|
606
|
+
except FileNotFoundError:
|
|
607
|
+
raise FileNotFoundError(f"JSON file not found: {file_path}")
|
|
608
|
+
except json.JSONDecodeError as e:
|
|
609
|
+
raise ValueError(f"Invalid JSON in file {file_path}: {e}")
|
|
610
|
+
|
|
611
|
+
return await self._upload_json_data(json_data, url, use_gzip)
|
|
612
|
+
|
|
613
|
+
@require_api_key
|
|
614
|
+
async def _upload_json_data(self, json_data, url: str, use_gzip: bool = True):
|
|
615
|
+
"""
|
|
616
|
+
Helper method to upload JSON data directly to a signed URL.
|
|
617
|
+
|
|
618
|
+
Args:
|
|
619
|
+
json_data: JSON data (dict or list) to upload
|
|
620
|
+
url: Signed URL to upload to
|
|
621
|
+
use_gzip: Whether to compress the data with gzip
|
|
622
|
+
"""
|
|
623
|
+
if hasattr(json, 'dumps') and 'ignore_nan' in json.dumps.__code__.co_varnames:
|
|
624
|
+
dumps_kwargs = {'ignore_nan': True}
|
|
625
|
+
else:
|
|
626
|
+
dumps_kwargs = {}
|
|
627
|
+
|
|
628
|
+
if use_gzip:
|
|
629
|
+
import gzip
|
|
630
|
+
body = gzip.compress(json.dumps(json_data, **dumps_kwargs).encode('utf-8'))
|
|
631
|
+
headers = {
|
|
632
|
+
'Content-Type': 'application/json',
|
|
633
|
+
'Content-Encoding': 'gzip'
|
|
634
|
+
}
|
|
635
|
+
else:
|
|
636
|
+
body = json.dumps(json_data, **dumps_kwargs).encode('utf-8')
|
|
637
|
+
headers = {
|
|
638
|
+
'Content-Type': 'application/json'
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
response = await self._client._regular_request("PUT", url, data=body, headers=headers)
|
|
642
|
+
return response
|
|
643
|
+
|
|
719
644
|
@require_api_key
|
|
720
|
-
async def
|
|
645
|
+
async def generate_data(
|
|
721
646
|
self,
|
|
722
647
|
collection: str,
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
648
|
+
file_path: str,
|
|
649
|
+
output: str,
|
|
650
|
+
skip_existing: Optional[bool] = True,
|
|
651
|
+
force_loc: Optional[bool] = None,
|
|
652
|
+
server: Optional[str] = None
|
|
727
653
|
) -> Dict[str, Any]:
|
|
728
654
|
"""
|
|
729
|
-
|
|
655
|
+
Generate data for a collection.
|
|
730
656
|
|
|
731
657
|
Args:
|
|
732
658
|
collection: Name of collection
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
659
|
+
file_path: Path to the file to upload
|
|
660
|
+
output: Output type (str)
|
|
661
|
+
force_loc: Write data directly to the cloud under this folder
|
|
662
|
+
skip_existing: Skip existing data
|
|
663
|
+
server: Server to use
|
|
664
|
+
|
|
738
665
|
Returns:
|
|
739
|
-
API response as a dictionary containing
|
|
666
|
+
API response as a dictionary containing task information
|
|
740
667
|
|
|
741
668
|
Raises:
|
|
742
669
|
CollectionNotFoundError: If the collection is not found
|
|
743
|
-
|
|
670
|
+
GetTaskError: If the API request fails due to unknown reasons
|
|
744
671
|
"""
|
|
745
|
-
|
|
672
|
+
await self.create_collection(
|
|
673
|
+
collection = collection
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
upload_urls = await self._upload_requests(
|
|
677
|
+
collection = collection
|
|
678
|
+
)
|
|
746
679
|
|
|
747
|
-
|
|
748
|
-
params["page"] = page
|
|
749
|
-
if page_size is not None:
|
|
750
|
-
params["page_size"] = page_size
|
|
751
|
-
if folder is not None:
|
|
752
|
-
params["folder"] = folder
|
|
680
|
+
url = upload_urls['url']
|
|
753
681
|
|
|
754
|
-
|
|
682
|
+
await self._upload_file(file_path, url)
|
|
683
|
+
|
|
684
|
+
payload = {"output": output, "skip_existing": skip_existing}
|
|
685
|
+
|
|
686
|
+
if force_loc is not None:
|
|
687
|
+
payload["force_loc"] = force_loc
|
|
688
|
+
if server is not None:
|
|
689
|
+
payload["server"] = server
|
|
690
|
+
|
|
691
|
+
response, status = await self._client._terrakio_request("POST", f"collections/{collection}/generate_data", json=payload)
|
|
755
692
|
|
|
756
693
|
if status != 200:
|
|
757
694
|
if status == 404:
|
|
758
695
|
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
759
|
-
raise
|
|
696
|
+
raise GetTaskError(f"Generate data failed with status {status}", status_code=status)
|
|
760
697
|
|
|
761
698
|
return response
|
|
762
699
|
|
|
763
700
|
@require_api_key
|
|
764
|
-
async def
|
|
701
|
+
async def post_processing(
|
|
765
702
|
self,
|
|
766
|
-
|
|
767
|
-
|
|
703
|
+
collection: str,
|
|
704
|
+
folder: str,
|
|
705
|
+
consumer: str
|
|
706
|
+
) -> Dict[str, Any]:
|
|
768
707
|
"""
|
|
769
|
-
|
|
708
|
+
Run post processing for a collection.
|
|
770
709
|
|
|
771
710
|
Args:
|
|
772
|
-
|
|
711
|
+
collection: Name of collection
|
|
712
|
+
folder: Folder to store output
|
|
713
|
+
consumer: Path to post processing script
|
|
773
714
|
|
|
774
715
|
Returns:
|
|
775
716
|
API response as a dictionary containing task information
|
|
776
717
|
|
|
777
718
|
Raises:
|
|
778
|
-
|
|
779
|
-
|
|
719
|
+
CollectionNotFoundError: If the collection is not found
|
|
720
|
+
GetTaskError: If the API request fails due to unknown reasons
|
|
780
721
|
"""
|
|
781
|
-
|
|
722
|
+
await self.create_collection(
|
|
723
|
+
collection = collection
|
|
724
|
+
)
|
|
725
|
+
|
|
726
|
+
with open(consumer, 'rb') as f:
|
|
727
|
+
form = aiohttp.FormData()
|
|
728
|
+
form.add_field('folder', folder)
|
|
729
|
+
form.add_field(
|
|
730
|
+
'consumer',
|
|
731
|
+
f.read(),
|
|
732
|
+
filename='consumer.py',
|
|
733
|
+
content_type='text/x-python'
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
response, status = await self._client._terrakio_request(
|
|
737
|
+
"POST",
|
|
738
|
+
f"collections/{collection}/post_process",
|
|
739
|
+
data=form
|
|
740
|
+
)
|
|
741
|
+
|
|
782
742
|
if status != 200:
|
|
783
743
|
if status == 404:
|
|
784
|
-
raise
|
|
785
|
-
raise
|
|
786
|
-
|
|
744
|
+
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
745
|
+
raise GetTaskError(f"Post processing failed with status {status}", status_code=status)
|
|
746
|
+
|
|
787
747
|
return response
|
|
788
748
|
|
|
789
749
|
@require_api_key
|
|
790
|
-
async def
|
|
750
|
+
async def training_samples(
|
|
791
751
|
self,
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
752
|
+
name: str,
|
|
753
|
+
aoi: str,
|
|
754
|
+
expression_x: str,
|
|
755
|
+
filter_x: str = "skip",
|
|
756
|
+
filter_x_rate: float = 1,
|
|
757
|
+
expression_y: str = "skip",
|
|
758
|
+
filter_y: str = "skip",
|
|
759
|
+
filter_y_rate: float = 1,
|
|
760
|
+
samples: int = 1000,
|
|
761
|
+
tile_size: float = 256,
|
|
762
|
+
crs: str = "epsg:3577",
|
|
763
|
+
res: float = 10,
|
|
764
|
+
res_y: float = None,
|
|
765
|
+
skip_test: bool = False,
|
|
766
|
+
start_year: int = None,
|
|
767
|
+
end_year: int = None,
|
|
768
|
+
bucket: str = None,
|
|
769
|
+
server: str = None,
|
|
770
|
+
extra_filters: list[str] = None,
|
|
771
|
+
extra_filters_rate: list[float] = None,
|
|
772
|
+
extra_filters_res: list[float] = None
|
|
773
|
+
) -> dict:
|
|
774
|
+
"""
|
|
775
|
+
Generate an AI dataset using specified parameters.
|
|
796
776
|
|
|
797
777
|
Args:
|
|
798
|
-
|
|
778
|
+
name: Name of the collection to create
|
|
779
|
+
aoi: Path to GeoJSON file containing area of interest
|
|
780
|
+
expression_x: Expression for X data (features)
|
|
781
|
+
filter_x: Filter expression for X data (default: "skip")
|
|
782
|
+
filter_x_rate: Filter rate for X data (default: 1)
|
|
783
|
+
expression_y: Expression for Y data (labels) (default: "skip")
|
|
784
|
+
filter_y: Filter expression for Y data (default: "skip")
|
|
785
|
+
filter_y_rate: Filter rate for Y data (default: 1)
|
|
786
|
+
samples: Number of samples to generate (default: 1000)
|
|
787
|
+
tile_size: Size of tiles in pixels (default: 256)
|
|
788
|
+
crs: Coordinate reference system (default: "epsg:3577")
|
|
789
|
+
res: Resolution for X data (default: 10)
|
|
790
|
+
res_y: Resolution for Y data, defaults to res if None
|
|
791
|
+
skip_test: Skip expression validation test (default: False)
|
|
792
|
+
start_year: Start year for temporal filtering
|
|
793
|
+
end_year: End year for temporal filtering
|
|
794
|
+
bucket: Storage bucket name
|
|
795
|
+
server: Server to use for processing
|
|
796
|
+
extra_filters: Additional filter expressions
|
|
797
|
+
extra_filters_rate: Rates for additional filters
|
|
798
|
+
extra_filters_res: Resolutions for additional filters
|
|
799
799
|
|
|
800
800
|
Returns:
|
|
801
|
-
|
|
801
|
+
Response containing task_id and collection name
|
|
802
802
|
|
|
803
803
|
Raises:
|
|
804
804
|
CollectionNotFoundError: If the collection is not found
|
|
805
|
-
|
|
805
|
+
GetTaskError: If the API request fails
|
|
806
|
+
TypeError: If extra filters have mismatched rate and resolution lists
|
|
806
807
|
"""
|
|
808
|
+
expressions = [{"expr": expression_x, "res": res, "prefix": "x"}]
|
|
809
|
+
|
|
810
|
+
res_y = res_y or res
|
|
811
|
+
|
|
812
|
+
if expression_y != "skip":
|
|
813
|
+
expressions.append({"expr": expression_y, "res": res_y, "prefix": "y"})
|
|
814
|
+
|
|
815
|
+
filters = []
|
|
816
|
+
if filter_x != "skip":
|
|
817
|
+
filters.append({"expr": filter_x, "res": res, "rate": filter_x_rate})
|
|
818
|
+
|
|
819
|
+
if filter_y != "skip":
|
|
820
|
+
filters.append({"expr": filter_y, "res": res_y, "rate": filter_y_rate})
|
|
821
|
+
|
|
822
|
+
if extra_filters:
|
|
823
|
+
try:
|
|
824
|
+
extra_filters_combined = zip(extra_filters, extra_filters_res, extra_filters_rate, strict=True)
|
|
825
|
+
except TypeError:
|
|
826
|
+
raise TypeError("Extra filters must have matching rate and resolution.")
|
|
827
|
+
|
|
828
|
+
for expr, filter_res, rate in extra_filters_combined:
|
|
829
|
+
filters.append({"expr": expr, "res": filter_res, "rate": rate})
|
|
830
|
+
|
|
831
|
+
if start_year is not None:
|
|
832
|
+
for expr_dict in expressions:
|
|
833
|
+
expr_dict["expr"] = expr_dict["expr"].replace("{year}", str(start_year))
|
|
834
|
+
|
|
835
|
+
for filter_dict in filters:
|
|
836
|
+
filter_dict["expr"] = filter_dict["expr"].replace("{year}", str(start_year))
|
|
837
|
+
|
|
838
|
+
if not skip_test:
|
|
839
|
+
for expr_dict in expressions:
|
|
840
|
+
test_request = self._client.model._generate_test_request(expr_dict["expr"], crs, -1)
|
|
841
|
+
await self._client._terrakio_request("POST", "geoquery", json=test_request)
|
|
842
|
+
|
|
843
|
+
for filter_dict in filters:
|
|
844
|
+
test_request = self._client.model._generate_test_request(filter_dict["expr"], crs, -1)
|
|
845
|
+
await self._client._terrakio_request("POST", "geoquery", json=test_request)
|
|
846
|
+
|
|
847
|
+
with open(aoi, 'r') as f:
|
|
848
|
+
aoi_data = json.load(f)
|
|
849
|
+
|
|
850
|
+
await self.create_collection(
|
|
851
|
+
collection = name,
|
|
852
|
+
bucket = bucket,
|
|
853
|
+
collection_type = "basic"
|
|
854
|
+
)
|
|
855
|
+
|
|
856
|
+
payload = {
|
|
857
|
+
"expressions": expressions,
|
|
858
|
+
"filters": filters,
|
|
859
|
+
"aoi": aoi_data,
|
|
860
|
+
"samples": samples,
|
|
861
|
+
"crs": crs,
|
|
862
|
+
"tile_size": tile_size,
|
|
863
|
+
"res": res,
|
|
864
|
+
"output": "nc",
|
|
865
|
+
"year_range": [start_year, end_year],
|
|
866
|
+
"server": server
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
task_id_dict, status = await self._client._terrakio_request("POST", f"collections/{name}/training_samples", json=payload)
|
|
807
870
|
|
|
808
|
-
response, status = await self._client._terrakio_request("POST", f"collections/{collection}/cancel")
|
|
809
871
|
if status != 200:
|
|
810
872
|
if status == 404:
|
|
811
|
-
raise CollectionNotFoundError(f"Collection {
|
|
812
|
-
raise
|
|
813
|
-
|
|
814
|
-
|
|
873
|
+
raise CollectionNotFoundError(f"Collection {name} not found", status_code=status)
|
|
874
|
+
raise GetTaskError(f"Training sample failed with status {status}", status_code=status)
|
|
875
|
+
|
|
876
|
+
task_id = task_id_dict["task_id"]
|
|
877
|
+
|
|
878
|
+
await self._client.mass_stats.track_progress(task_id)
|
|
879
|
+
|
|
880
|
+
return {"task_id": task_id, "collection": name}
|
|
815
881
|
|
|
816
882
|
@require_api_key
|
|
817
|
-
async def
|
|
818
|
-
self
|
|
819
|
-
|
|
883
|
+
async def download_files(
|
|
884
|
+
self,
|
|
885
|
+
collection: str,
|
|
886
|
+
file_type: str,
|
|
887
|
+
page: Optional[int] = 0,
|
|
888
|
+
page_size: Optional[int] = 100,
|
|
889
|
+
folder: Optional[str] = None,
|
|
890
|
+
url: Optional[bool] = True
|
|
891
|
+
) -> Dict[str, Any]:
|
|
820
892
|
"""
|
|
821
|
-
|
|
893
|
+
Get list of signed urls to download files in collection, or download the files directly.
|
|
894
|
+
|
|
895
|
+
Args:
|
|
896
|
+
collection: Name of collection
|
|
897
|
+
file_type: Type of files to download - must be either 'raw' or 'processed'
|
|
898
|
+
page: Page number (optional, defaults to 0)
|
|
899
|
+
page_size: Number of files to return per page (optional, defaults to 100)
|
|
900
|
+
folder: If processed file type, which folder to download files from (optional)
|
|
901
|
+
url: If True, return signed URLs; if False, download files directly (optional, defaults to True)
|
|
822
902
|
|
|
823
903
|
Returns:
|
|
824
|
-
API response as a dictionary containing
|
|
904
|
+
API response as a dictionary containing list of download URLs (if url=True),
|
|
905
|
+
or a dictionary with downloaded file information (if url=False)
|
|
825
906
|
|
|
826
907
|
Raises:
|
|
827
|
-
|
|
908
|
+
CollectionNotFoundError: If the collection is not found
|
|
909
|
+
DownloadFilesError: If the API request fails due to unknown reasons
|
|
910
|
+
ValueError: If file_type is not 'raw' or 'processed'
|
|
828
911
|
"""
|
|
912
|
+
if file_type not in ['raw', 'processed']:
|
|
913
|
+
raise ValueError(f"file_type must be either 'raw' or 'processed', got '{file_type}'")
|
|
914
|
+
|
|
915
|
+
params = {"file_type": file_type}
|
|
916
|
+
|
|
917
|
+
if page is not None:
|
|
918
|
+
params["page"] = page
|
|
919
|
+
if page_size is not None:
|
|
920
|
+
params["page_size"] = page_size
|
|
921
|
+
if folder is not None:
|
|
922
|
+
params["folder"] = folder
|
|
829
923
|
|
|
830
|
-
response, status = await self._client._terrakio_request("
|
|
924
|
+
response, status = await self._client._terrakio_request("GET", f"collections/{collection}/download", params=params)
|
|
831
925
|
|
|
832
926
|
if status != 200:
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
927
|
+
if status == 404:
|
|
928
|
+
raise CollectionNotFoundError(f"Collection {collection} not found", status_code=status)
|
|
929
|
+
raise DownloadFilesError(f"Download files failed with status {status}", status_code=status)
|
|
930
|
+
|
|
931
|
+
if url:
|
|
932
|
+
return response
|
|
933
|
+
|
|
934
|
+
downloaded_files = []
|
|
935
|
+
files_to_download = response.get('files', []) if isinstance(response, dict) else []
|
|
936
|
+
|
|
937
|
+
async with aiohttp.ClientSession() as session:
|
|
938
|
+
for file_info in files_to_download:
|
|
939
|
+
try:
|
|
940
|
+
file_url = file_info.get('url')
|
|
941
|
+
filename = file_info.get('file', '')
|
|
942
|
+
group = file_info.get('group', '')
|
|
943
|
+
|
|
944
|
+
if not file_url:
|
|
945
|
+
downloaded_files.append({
|
|
946
|
+
'filename': filename,
|
|
947
|
+
'group': group,
|
|
948
|
+
'error': 'No URL provided'
|
|
949
|
+
})
|
|
950
|
+
continue
|
|
951
|
+
|
|
952
|
+
async with session.get(file_url) as file_response:
|
|
953
|
+
if file_response.status == 200:
|
|
954
|
+
content = await file_response.read()
|
|
955
|
+
|
|
956
|
+
output_dir = folder if folder else "downloads"
|
|
957
|
+
if group:
|
|
958
|
+
output_dir = os.path.join(output_dir, group)
|
|
959
|
+
os.makedirs(output_dir, exist_ok=True)
|
|
960
|
+
filepath = os.path.join(output_dir, filename)
|
|
961
|
+
|
|
962
|
+
with open(filepath, 'wb') as f:
|
|
963
|
+
f.write(content)
|
|
964
|
+
|
|
965
|
+
downloaded_files.append({
|
|
966
|
+
'filename': filename,
|
|
967
|
+
'group': group,
|
|
968
|
+
'filepath': filepath,
|
|
969
|
+
'size': len(content)
|
|
970
|
+
})
|
|
971
|
+
else:
|
|
972
|
+
downloaded_files.append({
|
|
973
|
+
'filename': filename,
|
|
974
|
+
'group': group,
|
|
975
|
+
'error': f"Failed to download: HTTP {file_response.status}"
|
|
976
|
+
})
|
|
977
|
+
except Exception as e:
|
|
978
|
+
downloaded_files.append({
|
|
979
|
+
'filename': file_info.get('file', 'unknown'),
|
|
980
|
+
'group': file_info.get('group', ''),
|
|
981
|
+
'error': str(e)
|
|
982
|
+
})
|
|
983
|
+
|
|
984
|
+
return {
|
|
985
|
+
'collection': collection,
|
|
986
|
+
'downloaded_files': downloaded_files,
|
|
987
|
+
'total': len(downloaded_files)
|
|
988
|
+
}
|
|
@@ -59,131 +59,6 @@ class ModelManagement:
|
|
|
59
59
|
}
|
|
60
60
|
return req
|
|
61
61
|
|
|
62
|
-
@require_api_key
|
|
63
|
-
async def generate_ai_dataset(
|
|
64
|
-
self,
|
|
65
|
-
name: str,
|
|
66
|
-
aoi: str,
|
|
67
|
-
expression_x: str,
|
|
68
|
-
filter_x: str = "skip",
|
|
69
|
-
filter_x_rate: float = 1,
|
|
70
|
-
expression_y: str = "skip",
|
|
71
|
-
filter_y: str = "skip",
|
|
72
|
-
filter_y_rate: float = 1,
|
|
73
|
-
samples: int = 1000,
|
|
74
|
-
tile_size: float = 256,
|
|
75
|
-
crs: str = "epsg:3577",
|
|
76
|
-
res: float = 10,
|
|
77
|
-
res_y: float = None,
|
|
78
|
-
skip_test: bool = False,
|
|
79
|
-
start_year: int = None,
|
|
80
|
-
end_year: int = None,
|
|
81
|
-
bucket: str = None,
|
|
82
|
-
server: str = None,
|
|
83
|
-
extra_filters: list[str] = None,
|
|
84
|
-
extra_filters_rate: list[float] = None,
|
|
85
|
-
extra_filters_res: list[float] = None
|
|
86
|
-
) -> dict:
|
|
87
|
-
"""
|
|
88
|
-
Generate an AI dataset using specified parameters.
|
|
89
|
-
|
|
90
|
-
Args:
|
|
91
|
-
name (str): Name of the collection to create
|
|
92
|
-
aoi (str): Path to GeoJSON file containing area of interest
|
|
93
|
-
expression_x (str): Expression for X data (features)
|
|
94
|
-
filter_x (str): Filter expression for X data (default: "skip")
|
|
95
|
-
filter_x_rate (float): Filter rate for X data (default: 1)
|
|
96
|
-
expression_y (str): Expression for Y data (labels) (default: "skip")
|
|
97
|
-
filter_y (str): Filter expression for Y data (default: "skip")
|
|
98
|
-
filter_y_rate (float): Filter rate for Y data (default: 1)
|
|
99
|
-
samples (int): Number of samples to generate (default: 1000)
|
|
100
|
-
tile_size (float): Size of tiles in pixels (default: 256)
|
|
101
|
-
crs (str): Coordinate reference system (default: "epsg:3577")
|
|
102
|
-
res (float): Resolution for X data (default: 10)
|
|
103
|
-
res_y (float): Resolution for Y data, defaults to res if None
|
|
104
|
-
skip_test (bool): Skip expression validation test (default: False)
|
|
105
|
-
start_year (int): Start year for temporal filtering
|
|
106
|
-
end_year (int): End year for temporal filtering
|
|
107
|
-
bucket (str): Storage bucket name
|
|
108
|
-
server (str): Server to use for processing
|
|
109
|
-
extra_filters (list[str]): Additional filter expressions
|
|
110
|
-
extra_filters_rate (list[float]): Rates for additional filters
|
|
111
|
-
extra_filters_res (list[float]): Resolutions for additional filters
|
|
112
|
-
|
|
113
|
-
Returns:
|
|
114
|
-
dict: Response containing task_id and collection name
|
|
115
|
-
|
|
116
|
-
Raises:
|
|
117
|
-
APIError: If the API request fails
|
|
118
|
-
TypeError: If extra filters have mismatched rate and resolution lists
|
|
119
|
-
"""
|
|
120
|
-
expressions = [{"expr": expression_x, "res": res, "prefix": "x"}]
|
|
121
|
-
|
|
122
|
-
res_y = res_y or res
|
|
123
|
-
|
|
124
|
-
if expression_y != "skip":
|
|
125
|
-
expressions.append({"expr": expression_y, "res": res_y, "prefix": "y"})
|
|
126
|
-
|
|
127
|
-
filters = []
|
|
128
|
-
if filter_x != "skip":
|
|
129
|
-
filters.append({"expr": filter_x, "res": res, "rate": filter_x_rate})
|
|
130
|
-
|
|
131
|
-
if filter_y != "skip":
|
|
132
|
-
filters.append({"expr": filter_y, "res": res_y, "rate": filter_y_rate})
|
|
133
|
-
|
|
134
|
-
if extra_filters:
|
|
135
|
-
try:
|
|
136
|
-
extra_filters_combined = zip(extra_filters, extra_filters_res, extra_filters_rate, strict=True)
|
|
137
|
-
except TypeError:
|
|
138
|
-
raise TypeError("Extra filters must have matching rate and resolution.")
|
|
139
|
-
|
|
140
|
-
for expr, filter_res, rate in extra_filters_combined:
|
|
141
|
-
filters.append({"expr": expr, "res": filter_res, "rate": rate})
|
|
142
|
-
|
|
143
|
-
if start_year is not None:
|
|
144
|
-
for expr_dict in expressions:
|
|
145
|
-
expr_dict["expr"] = expr_dict["expr"].replace("{year}", str(start_year))
|
|
146
|
-
|
|
147
|
-
for filter_dict in filters:
|
|
148
|
-
filter_dict["expr"] = filter_dict["expr"].replace("{year}", str(start_year))
|
|
149
|
-
|
|
150
|
-
# this is making request to the server that is being used when doing the initialization
|
|
151
|
-
if not skip_test:
|
|
152
|
-
for expr_dict in expressions:
|
|
153
|
-
test_request = self._generate_test_request(expr_dict["expr"], crs, -1)
|
|
154
|
-
await self._client._terrakio_request("POST", "geoquery", json=test_request)
|
|
155
|
-
|
|
156
|
-
for filter_dict in filters:
|
|
157
|
-
test_request = self._generate_test_request(filter_dict["expr"], crs, -1)
|
|
158
|
-
await self._client._terrakio_request("POST", "geoquery", json=test_request)
|
|
159
|
-
|
|
160
|
-
with open(aoi, 'r') as f:
|
|
161
|
-
aoi_data = json.load(f)
|
|
162
|
-
|
|
163
|
-
await self._client.mass_stats.create_collection(
|
|
164
|
-
collection=name,
|
|
165
|
-
bucket=bucket,
|
|
166
|
-
collection_type="basic"
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
task_id_dict = await self._client.mass_stats.training_samples(
|
|
170
|
-
collection=name,
|
|
171
|
-
expressions=expressions,
|
|
172
|
-
filters=filters,
|
|
173
|
-
aoi=aoi_data,
|
|
174
|
-
samples=samples,
|
|
175
|
-
year_range=[start_year, end_year],
|
|
176
|
-
crs=crs,
|
|
177
|
-
tile_size=tile_size,
|
|
178
|
-
res=res,
|
|
179
|
-
output="nc",
|
|
180
|
-
server=server
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
task_id = task_id_dict["task_id"]
|
|
184
|
-
|
|
185
|
-
await self._client.mass_stats.track_progress(task_id)
|
|
186
|
-
|
|
187
62
|
@require_api_key
|
|
188
63
|
async def _get_url_for_upload_model_and_script(self, expression: str, model_name: str, script_name: str) -> str:
|
|
189
64
|
"""
|
|
@@ -11,13 +11,13 @@ terrakio_core/convenience_functions/zonal_stats.py,sha256=7PI--RI0hiF1pzZ7_7hqty
|
|
|
11
11
|
terrakio_core/endpoints/auth.py,sha256=5WvAO39aLsbJAVtxISwiOZseKr3B9I5tHjamPRehDBQ,8327
|
|
12
12
|
terrakio_core/endpoints/dataset_management.py,sha256=jpwftiKOI59NhXXypqm6wtILIkfyjy9NfYifRIvhZS0,16791
|
|
13
13
|
terrakio_core/endpoints/group_management.py,sha256=V0KOGTXwmePBFeym55G_m3ONR-jVj2IU4OVLiL5UKz4,15869
|
|
14
|
-
terrakio_core/endpoints/mass_stats.py,sha256=
|
|
15
|
-
terrakio_core/endpoints/model_management.py,sha256=
|
|
14
|
+
terrakio_core/endpoints/mass_stats.py,sha256=Bvke7gmZpNCsbEDyskqV7ZlkztkoBWxxFUPP0DCXz7Y,36970
|
|
15
|
+
terrakio_core/endpoints/model_management.py,sha256=tvJ4BOBsyXKKH430byGH25CkLIzXWgxaPaL0CvL8_0Y,51341
|
|
16
16
|
terrakio_core/endpoints/space_management.py,sha256=YWb55nkJnFJGlALJ520DvurxDqVqwYtsvqQPWzxzhDs,2266
|
|
17
17
|
terrakio_core/endpoints/user_management.py,sha256=L_g4ysrh2xyz_JbObUU_tCxgHxisrDUPntWgQOs15GE,7709
|
|
18
18
|
terrakio_core/helper/bounded_taskgroup.py,sha256=wiTH10jhKZgrsgrFUNG6gig8bFkUEPHkGRT2XY7Rgmo,677
|
|
19
19
|
terrakio_core/helper/decorators.py,sha256=L6om7wmWNgCei3Wy5U0aZ-70OzsCwclkjIf7SfQuhCg,2289
|
|
20
20
|
terrakio_core/helper/tiles.py,sha256=lcLCO6KiP05lCI9vngo3zCZJ6Z9C0pUxHSQS4H58EHc,2699
|
|
21
|
-
terrakio_core-0.4.98.
|
|
22
|
-
terrakio_core-0.4.98.
|
|
23
|
-
terrakio_core-0.4.98.
|
|
21
|
+
terrakio_core-0.4.98.1b6.dist-info/METADATA,sha256=zlli64p2DlufJj4q_xoIYbyuDPra2thNi5r2CtovLJA,1184
|
|
22
|
+
terrakio_core-0.4.98.1b6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
23
|
+
terrakio_core-0.4.98.1b6.dist-info/RECORD,,
|
|
File without changes
|