privateer-elements-sdk 2025.11.5__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.
- elements/__init__.py +0 -0
- elements/cli/__init__.py +0 -0
- elements/cli/commands/__init__.py +0 -0
- elements/cli/commands/algorithm.py +292 -0
- elements/cli/commands/algorithm_computation.py +154 -0
- elements/cli/commands/algorithm_config.py +188 -0
- elements/cli/commands/algorithm_version.py +157 -0
- elements/cli/commands/analysis.py +353 -0
- elements/cli/commands/analysis_computation.py +172 -0
- elements/cli/commands/analysis_config.py +174 -0
- elements/cli/commands/analysis_version.py +145 -0
- elements/cli/commands/aoi.py +79 -0
- elements/cli/commands/credit.py +51 -0
- elements/cli/commands/data.py +146 -0
- elements/cli/commands/environment.py +27 -0
- elements/cli/commands/imagery.py +145 -0
- elements/cli/commands/manifest.py +86 -0
- elements/cli/commands/permission.py +59 -0
- elements/cli/commands/tasks.py +515 -0
- elements/cli/commands/toi.py +59 -0
- elements/cli/commands/visualization.py +44 -0
- elements/cli/lib/__init__.py +0 -0
- elements/cli/lib/aliased_group.py +98 -0
- elements/cli/lib/utils.py +134 -0
- elements/cli/lib/workflow.py +1808 -0
- elements/cli/ts.py +40 -0
- elements/sdk/__init__.py +0 -0
- elements/sdk/api/__init__.py +0 -0
- elements/sdk/api/algorithm.py +666 -0
- elements/sdk/api/analysis.py +692 -0
- elements/sdk/api/aoi.py +342 -0
- elements/sdk/api/credit.py +168 -0
- elements/sdk/api/data.py +118 -0
- elements/sdk/api/filter.py +77 -0
- elements/sdk/api/order.py +71 -0
- elements/sdk/api/permission.py +124 -0
- elements/sdk/api/result.py +323 -0
- elements/sdk/api/tasking_order.py +68 -0
- elements/sdk/api/toi.py +79 -0
- elements/sdk/api/user.py +140 -0
- elements/sdk/api/visualization.py +51 -0
- elements/sdk/builder/__init__.py +0 -0
- elements/sdk/builder/algorithm.py +461 -0
- elements/sdk/builder/analysis.py +179 -0
- elements/sdk/builder/toi.py +181 -0
- elements/sdk/elements_sdk.py +156 -0
- elements/sdk/tools/__init__.py +0 -0
- elements/sdk/tools/io.py +128 -0
- elements/sdk/tools/sdk_support.py +38 -0
- privateer_elements_sdk-2025.11.5.dist-info/METADATA +470 -0
- privateer_elements_sdk-2025.11.5.dist-info/RECORD +67 -0
- privateer_elements_sdk-2025.11.5.dist-info/WHEEL +5 -0
- privateer_elements_sdk-2025.11.5.dist-info/entry_points.txt +2 -0
- privateer_elements_sdk-2025.11.5.dist-info/licenses/LICENSE +7 -0
- privateer_elements_sdk-2025.11.5.dist-info/top_level.txt +2 -0
- tests/integration/test_algorithm.py +867 -0
- tests/integration/test_algorithm_builder.py +43 -0
- tests/integration/test_analysis.py +481 -0
- tests/integration/test_analysis_builder.py +28 -0
- tests/integration/test_aoi.py +160 -0
- tests/integration/test_credit.py +186 -0
- tests/integration/test_data.py +43 -0
- tests/integration/test_permission.py +120 -0
- tests/integration/test_result.py +138 -0
- tests/integration/test_sdk_support.py +28 -0
- tests/integration/test_toi.py +245 -0
- tests/integration/test_visualization.py +9 -0
elements/__init__.py
ADDED
|
File without changes
|
elements/cli/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import asyncio
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import yaml
|
|
7
|
+
import json
|
|
8
|
+
import elements.cli.lib.utils as tsu
|
|
9
|
+
from elements.cli.lib.aliased_group import AliasedSuperGroup
|
|
10
|
+
import elements.cli.lib.workflow as wf
|
|
11
|
+
from elements.cli.commands.algorithm_version import version
|
|
12
|
+
from elements.cli.commands.algorithm_computation import computation
|
|
13
|
+
from elements.cli.commands.algorithm_config import config
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@click.command(cls=AliasedSuperGroup, help="'algorithm' super-group")
|
|
17
|
+
@click.pass_context
|
|
18
|
+
def algorithm(ctx):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
algorithm.add_command(version)
|
|
23
|
+
algorithm.add_command(computation)
|
|
24
|
+
algorithm.add_command(config)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@algorithm.command('get', help="Get algorithm info")
|
|
28
|
+
@click.pass_context
|
|
29
|
+
@click.option('-ia', '--algorithm_id', type=str, default=None)
|
|
30
|
+
@click.option('-na', '--algorithm_name', type=str, default=None)
|
|
31
|
+
@click.option('-t', '--truncate', type=int, default=36,
|
|
32
|
+
help="Truncate columns to this many chars. Use 0 for no truncation. (a full UUID is 36).")
|
|
33
|
+
@click.option('-v', '--verbose', is_flag=True, default=False)
|
|
34
|
+
def algorithm_get(ctx, algorithm_id=None, algorithm_name=None, truncate=0, verbose=False):
|
|
35
|
+
|
|
36
|
+
wf.check_environment_complete(raise_on_failure=True, verbose=verbose)
|
|
37
|
+
algos = []
|
|
38
|
+
if algorithm_id:
|
|
39
|
+
algos += asyncio.run(wf.get_algorithms(algorithm_ids=[algorithm_id]))
|
|
40
|
+
if algorithm_name:
|
|
41
|
+
algos += asyncio.run(wf.list_algorithms(algorithm_name=algorithm_name))
|
|
42
|
+
|
|
43
|
+
data = []
|
|
44
|
+
for algo in algos:
|
|
45
|
+
row = [algo.name, algo.id, algo.author]
|
|
46
|
+
if truncate:
|
|
47
|
+
row = [v[:truncate] for v in row]
|
|
48
|
+
data.append(row)
|
|
49
|
+
|
|
50
|
+
df = pd.DataFrame(data=data, columns=['name', 'algorithm_id', 'author'])
|
|
51
|
+
tsu.set_pandas_display()
|
|
52
|
+
click.echo(df)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@algorithm.command('create', help="Create an algorithm object (no manifest)")
|
|
56
|
+
@click.pass_context
|
|
57
|
+
@click.option('-na', '--algorithm_name', type=str)
|
|
58
|
+
@click.option('-a', '--author', type=str, default='TERRASCOPE_AUTHOR')
|
|
59
|
+
@click.option('-dn', '--display_name', type=str)
|
|
60
|
+
@click.option('-v', '--verbose', is_flag=True, default=False)
|
|
61
|
+
@click.option('--dry_run', is_flag=True, default=False)
|
|
62
|
+
def algorithm_create(
|
|
63
|
+
ctx,
|
|
64
|
+
algorithm_name,
|
|
65
|
+
author,
|
|
66
|
+
display_name,
|
|
67
|
+
verbose=False,
|
|
68
|
+
dry_run=False,
|
|
69
|
+
):
|
|
70
|
+
|
|
71
|
+
wf.check_environment_complete(raise_on_failure=True, verbose=verbose)
|
|
72
|
+
|
|
73
|
+
author = tsu.get_author(author, raise_on_failure=True)
|
|
74
|
+
click.echo("Using the following information:")
|
|
75
|
+
click.echo(f"--> name: {algorithm_name}")
|
|
76
|
+
click.echo(f"--> author: {author}")
|
|
77
|
+
click.echo(f"--> display_name: {display_name}")
|
|
78
|
+
|
|
79
|
+
# create the manifest
|
|
80
|
+
if not dry_run:
|
|
81
|
+
algorithm_id = asyncio.run(wf.create_algorithm(
|
|
82
|
+
algorithm_name,
|
|
83
|
+
author,
|
|
84
|
+
display_name,
|
|
85
|
+
))
|
|
86
|
+
tsu.echo_highlight_suffix("You're new algorithm_id is: ", algorithm_id, 'green')
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@algorithm.command('register', help="Create an algorithm, and register it. (with manifest)")
|
|
90
|
+
@click.pass_context
|
|
91
|
+
@click.option('-m', '--manifest_yaml', type=str)
|
|
92
|
+
@click.option('-om', '--output_manifest', type=str, help="Can be json or yaml file")
|
|
93
|
+
@click.option('-na', '--algorithm_name', type=str)
|
|
94
|
+
@click.option('-a', '--author', type=str, default='TERRASCOPE_AUTHOR')
|
|
95
|
+
@click.option('-dn', '--display_name', type=str)
|
|
96
|
+
@click.option('-d', '--docker_version_hash', type=str)
|
|
97
|
+
@click.option('-pv', '--value_price', default=wf.VALUE_PRICE_DEFAULT, type=float)
|
|
98
|
+
@click.option('-pe', '--execution_price', default=wf.EXECUTION_PRICE_DEFAULT, type=float)
|
|
99
|
+
@click.option('-nc', '--config_name', default=None, type=str,
|
|
100
|
+
help="Specify this to create an initial algorithm config.")
|
|
101
|
+
@click.option('--dry_run', is_flag=True, default=False)
|
|
102
|
+
@click.option('-V', '--version', type=str, default=None)
|
|
103
|
+
@click.option('-v', '--verbose', is_flag=True, default=False)
|
|
104
|
+
def algorithm_register(
|
|
105
|
+
ctx,
|
|
106
|
+
manifest_yaml,
|
|
107
|
+
output_manifest=None,
|
|
108
|
+
algorithm_name=None,
|
|
109
|
+
author=None,
|
|
110
|
+
display_name=None,
|
|
111
|
+
docker_version_hash=None,
|
|
112
|
+
value_price=wf.VALUE_PRICE_DEFAULT,
|
|
113
|
+
execution_price=wf.EXECUTION_PRICE_DEFAULT,
|
|
114
|
+
config_name=None,
|
|
115
|
+
dry_run=False,
|
|
116
|
+
version=None,
|
|
117
|
+
verbose=False,
|
|
118
|
+
):
|
|
119
|
+
|
|
120
|
+
wf.check_environment_complete(raise_on_failure=True, verbose=verbose)
|
|
121
|
+
# create the manifest
|
|
122
|
+
input_manifest = None
|
|
123
|
+
with open(manifest_yaml, 'r') as fp:
|
|
124
|
+
input_manifest = yaml.safe_load(fp)
|
|
125
|
+
algorithm_name = tsu.override_manifest_param('name', algorithm_name, input_manifest, do_overwrite=True)
|
|
126
|
+
display_name = tsu.override_manifest_param('display_name', display_name, input_manifest, do_overwrite=True)
|
|
127
|
+
author = tsu.get_author(author, raise_on_failure=True)
|
|
128
|
+
# if the author is in the manifest, overwrite it with the command line / env-var value.
|
|
129
|
+
# This is only done in case the user wants to write the manifest to a file,
|
|
130
|
+
# ... we want that file to contain what was actually used.
|
|
131
|
+
if 'author' in input_manifest:
|
|
132
|
+
input_manifest['author'] = author
|
|
133
|
+
new_version = input_manifest['metadata']['version']
|
|
134
|
+
if version:
|
|
135
|
+
new_version = tsu.set_version(version, input_manifest, do_overwrite=True)
|
|
136
|
+
|
|
137
|
+
visualizer_config_names = input_manifest.get('visualizer_config_names', None)
|
|
138
|
+
image = wf.update_manifest_docker_hash(input_manifest, docker_version_hash)
|
|
139
|
+
manifest = wf.create_algorithm_manifest(input_manifest)
|
|
140
|
+
|
|
141
|
+
click.echo("Using the following information:")
|
|
142
|
+
click.echo(f"--> name: {algorithm_name}")
|
|
143
|
+
click.echo(f"--> version: {new_version}")
|
|
144
|
+
click.echo(f"--> author: {author}")
|
|
145
|
+
click.echo(f"--> display_name: {display_name}")
|
|
146
|
+
click.echo(f"--> image: {image}")
|
|
147
|
+
click.echo(f"--> prices: {value_price} / {execution_price}")
|
|
148
|
+
click.echo(f"--> vis-names: {visualizer_config_names}")
|
|
149
|
+
|
|
150
|
+
# create the manifest
|
|
151
|
+
if not dry_run:
|
|
152
|
+
algorithm_id, algorithm_version_id = asyncio.run(wf.new_algorithm(
|
|
153
|
+
algorithm_name,
|
|
154
|
+
author,
|
|
155
|
+
display_name,
|
|
156
|
+
manifest,
|
|
157
|
+
value_price=value_price,
|
|
158
|
+
execution_price=execution_price,
|
|
159
|
+
visualizer_config_names=visualizer_config_names,
|
|
160
|
+
))
|
|
161
|
+
tsu.echo_highlight_suffix("You're new algorithm_id is: ", algorithm_id, 'green')
|
|
162
|
+
tsu.echo_highlight_suffix("You're new algorithm_version_id is: ", algorithm_version_id, 'green')
|
|
163
|
+
|
|
164
|
+
if config_name:
|
|
165
|
+
algorithm_config_id = create_config(algorithm_version_id, config_name, input_manifest)
|
|
166
|
+
tsu.echo_highlight_suffix("You're new algorithm_config_id is: ", algorithm_config_id, 'green')
|
|
167
|
+
|
|
168
|
+
if output_manifest:
|
|
169
|
+
with open(output_manifest, 'w') as fp:
|
|
170
|
+
if output_manifest.endswith('json'):
|
|
171
|
+
json.dump(input_manifest, fp, indent=4)
|
|
172
|
+
else:
|
|
173
|
+
yaml.dump(input_manifest, fp)
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@algorithm.command('update', help="Update an existing algorithm with manifest or pricing.")
|
|
177
|
+
@click.pass_context
|
|
178
|
+
@click.option('-m', '--manifest_yaml', type=str, required=True)
|
|
179
|
+
@click.option('-ia', '--algorithm_id', type=str, required=True)
|
|
180
|
+
@click.option('-om', '--output_manifest', type=str)
|
|
181
|
+
@click.option('-d', '--docker_version_hash', type=str, default=None)
|
|
182
|
+
@click.option('-pv', '--value_price', default=wf.VALUE_PRICE_DEFAULT, type=float)
|
|
183
|
+
@click.option('-pe', '--execution_price', default=wf.EXECUTION_PRICE_DEFAULT, type=float)
|
|
184
|
+
@click.option('--dry_run', is_flag=True, default=False)
|
|
185
|
+
@click.option('-nc', '--config_name', default=None, type=str,
|
|
186
|
+
help="Specify this to create an initial algorithm config.")
|
|
187
|
+
@click.option('-V', '--version', type=str, default=None)
|
|
188
|
+
@click.option('-v', '--verbose', is_flag=True, default=False)
|
|
189
|
+
def algorithm_update(
|
|
190
|
+
ctx,
|
|
191
|
+
manifest_yaml,
|
|
192
|
+
algorithm_id,
|
|
193
|
+
output_manifest=None,
|
|
194
|
+
docker_version_hash=None,
|
|
195
|
+
value_price=wf.VALUE_PRICE_DEFAULT,
|
|
196
|
+
execution_price=wf.EXECUTION_PRICE_DEFAULT,
|
|
197
|
+
config_name=None,
|
|
198
|
+
dry_run=False,
|
|
199
|
+
version=None,
|
|
200
|
+
verbose=False,
|
|
201
|
+
):
|
|
202
|
+
|
|
203
|
+
wf.check_environment_complete(raise_on_failure=True, verbose=verbose)
|
|
204
|
+
command_line_version = version
|
|
205
|
+
|
|
206
|
+
# create the manifest
|
|
207
|
+
input_manifest = None
|
|
208
|
+
with open(manifest_yaml, 'r') as fp:
|
|
209
|
+
input_manifest = yaml.safe_load(fp)
|
|
210
|
+
algorithm_version = input_manifest['metadata']['version']
|
|
211
|
+
visualizer_config_names = input_manifest.get('visualizer_config_names', None)
|
|
212
|
+
if command_line_version:
|
|
213
|
+
if command_line_version in ['patch', 'minor', 'major']:
|
|
214
|
+
level = command_line_version
|
|
215
|
+
current_algorithm_version = asyncio.run(wf.get_current_algorithm_version(algorithm_id=algorithm_id))
|
|
216
|
+
new_algorithm_version = tsu.increment_version(current_algorithm_version, level=level)
|
|
217
|
+
click.echo(f"The current algorithm version is: {current_algorithm_version}.")
|
|
218
|
+
click.echo(f"Auto-incrementing at {level}-level to: {new_algorithm_version}")
|
|
219
|
+
else:
|
|
220
|
+
new_algorithm_version = command_line_version
|
|
221
|
+
algorithm_version = tsu.set_version(new_algorithm_version, input_manifest, do_overwrite=True)
|
|
222
|
+
|
|
223
|
+
image = wf.update_manifest_docker_hash(input_manifest, docker_version_hash)
|
|
224
|
+
manifest = wf.create_algorithm_manifest(input_manifest)
|
|
225
|
+
|
|
226
|
+
click.echo("Using the following information:")
|
|
227
|
+
click.echo(f"--> algorithm_id: {algorithm_id}")
|
|
228
|
+
click.echo(f"--> image: {image}")
|
|
229
|
+
click.echo(f"--> prices: {value_price} / {execution_price}")
|
|
230
|
+
click.echo(f"--> version: {algorithm_version}")
|
|
231
|
+
click.echo(f"--> viz-names: {visualizer_config_names}")
|
|
232
|
+
|
|
233
|
+
# create the manifest
|
|
234
|
+
if not dry_run:
|
|
235
|
+
algorithm_version_id = asyncio.run(wf.update_algorithm(
|
|
236
|
+
algorithm_id,
|
|
237
|
+
manifest,
|
|
238
|
+
value_price=value_price,
|
|
239
|
+
execution_price=execution_price,
|
|
240
|
+
visualizer_config_names=visualizer_config_names,
|
|
241
|
+
))
|
|
242
|
+
tsu.echo_highlight_suffix("Your updated algorithm_version_id is: ", algorithm_version_id, 'green')
|
|
243
|
+
|
|
244
|
+
if config_name:
|
|
245
|
+
algorithm_config_id = create_config(algorithm_version_id, config_name, input_manifest)
|
|
246
|
+
tsu.echo_highlight_suffix("You're new algorithm_config_id is: ", algorithm_config_id, 'green')
|
|
247
|
+
|
|
248
|
+
if output_manifest:
|
|
249
|
+
with open(output_manifest, 'w') as fp:
|
|
250
|
+
if output_manifest.endswith('json'):
|
|
251
|
+
json.dump(input_manifest, fp, indent=4)
|
|
252
|
+
else:
|
|
253
|
+
yaml.dump(input_manifest, fp)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def create_config(algorithm_version_id, config_name, input_manifest):
|
|
257
|
+
|
|
258
|
+
# use a canned description as this is the first config for this algo version
|
|
259
|
+
config_desc = f"Initial algorithm config for {config_name}"
|
|
260
|
+
|
|
261
|
+
# if a config_name is provided, then we'll create an initial config
|
|
262
|
+
# Get the necessary params from the manifest.
|
|
263
|
+
try:
|
|
264
|
+
data_source = input_manifest['inputs'][0]['data_source_name']
|
|
265
|
+
except Exception:
|
|
266
|
+
click.secho("Data source must be provided in manifest", fg='red')
|
|
267
|
+
raise
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
data_type = input_manifest['inputs'][0]['data_type_name']
|
|
271
|
+
except Exception:
|
|
272
|
+
click.secho("Data Type must be provided in manifest", fg='red')
|
|
273
|
+
raise
|
|
274
|
+
|
|
275
|
+
image_processing_spec = None
|
|
276
|
+
if 'parameters' in input_manifest['inputs'][0]:
|
|
277
|
+
image_processing_spec = input_manifest['inputs'][0]['parameters'].get('image_processing_spec', None)
|
|
278
|
+
data_parameters = {}
|
|
279
|
+
if image_processing_spec:
|
|
280
|
+
data_parameters['image_processing_spec'] = image_processing_spec
|
|
281
|
+
|
|
282
|
+
algorithm_config_id = asyncio.run(
|
|
283
|
+
wf.create_algorithm_config(
|
|
284
|
+
algorithm_version_id,
|
|
285
|
+
config_name,
|
|
286
|
+
config_desc,
|
|
287
|
+
tsu.FakeDataSource(data_source),
|
|
288
|
+
data_type,
|
|
289
|
+
data_parameters,
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
return algorithm_config_id
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import asyncio
|
|
5
|
+
import os
|
|
6
|
+
import elements.cli.lib.utils as tsu
|
|
7
|
+
from elements.cli.lib.aliased_group import AliasedGroup
|
|
8
|
+
import elements.cli.lib.workflow as wf
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@click.group(cls=AliasedGroup, help="Algorithm 'computation' command group")
|
|
12
|
+
@click.pass_context
|
|
13
|
+
def computation(ctx):
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@computation.command(name='get')
|
|
18
|
+
@click.pass_context
|
|
19
|
+
@click.option('-ip', '--algorithm_computation_id', type=str)
|
|
20
|
+
@click.option('-v', '--verbose', is_flag=True)
|
|
21
|
+
def algorithm_computation_get(ctx, algorithm_computation_id, verbose):
|
|
22
|
+
|
|
23
|
+
wf.check_environment_complete(raise_on_failure=True)
|
|
24
|
+
|
|
25
|
+
algorithm_computation_info = asyncio.run(
|
|
26
|
+
wf.get_algorithm_computation_info([algorithm_computation_id])
|
|
27
|
+
)[0]
|
|
28
|
+
info = tsu.protobuf_to_dict(algorithm_computation_info)
|
|
29
|
+
|
|
30
|
+
click.secho(algorithm_computation_id, fg='cyan')
|
|
31
|
+
for k, v in info.items():
|
|
32
|
+
click.echo(f"{k:20s} {v}")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@computation.command(name='create')
|
|
36
|
+
@click.pass_context
|
|
37
|
+
@click.option('-ic', '--algorithm_config_id', type=str)
|
|
38
|
+
@click.option('-iac', '--aoi_collection_id', type=str)
|
|
39
|
+
@click.option('-it', '--toi_id', type=str)
|
|
40
|
+
@click.option('-s', '--start_date', type=str)
|
|
41
|
+
@click.option('-e', '--end_date', type=str)
|
|
42
|
+
@click.option('-af', '--aoi_file', type=str)
|
|
43
|
+
@click.option('-d', '--date_format', type=str, default='%Y-%m-%d')
|
|
44
|
+
@click.option('-f', '--frequency', type=click.IntRange(min=2, max=3, clamp=False), default=3,
|
|
45
|
+
help="HOURLY=2, DAILY=3")
|
|
46
|
+
@click.option('--dry_run', is_flag=True)
|
|
47
|
+
@click.option('-v', '--verbose', is_flag=True)
|
|
48
|
+
def algorithm_computation_create(
|
|
49
|
+
ctx,
|
|
50
|
+
algorithm_config_id,
|
|
51
|
+
start_date,
|
|
52
|
+
end_date,
|
|
53
|
+
aoi_file,
|
|
54
|
+
date_format,
|
|
55
|
+
frequency,
|
|
56
|
+
dry_run,
|
|
57
|
+
verbose,
|
|
58
|
+
aoi_collection_id=None,
|
|
59
|
+
toi_id=None,
|
|
60
|
+
):
|
|
61
|
+
|
|
62
|
+
wf.check_environment_complete(raise_on_failure=True)
|
|
63
|
+
click.echo("Using the following information:")
|
|
64
|
+
click.echo(f"--> algorithm_config_id: {algorithm_config_id}")
|
|
65
|
+
click.echo(f"--> start_date: {start_date}")
|
|
66
|
+
click.echo(f"--> end_date: {end_date}")
|
|
67
|
+
click.echo(f"--> aoi_file: {aoi_file}")
|
|
68
|
+
click.echo(f"--> date_format: {date_format}")
|
|
69
|
+
click.echo(f"--> frequency: {frequency}")
|
|
70
|
+
click.echo(f"--> aoi_collectin_id: {aoi_collection_id}")
|
|
71
|
+
click.echo(f"--> toi_id: {toi_id}")
|
|
72
|
+
|
|
73
|
+
if not dry_run:
|
|
74
|
+
|
|
75
|
+
if aoi_collection_id and toi_id:
|
|
76
|
+
computation_id = asyncio.run(
|
|
77
|
+
wf.create_algorithm_computation(
|
|
78
|
+
algorithm_config_id,
|
|
79
|
+
toi_id,
|
|
80
|
+
aoi_collection_id,
|
|
81
|
+
)
|
|
82
|
+
)
|
|
83
|
+
else:
|
|
84
|
+
computation_id = asyncio.run(
|
|
85
|
+
wf.create_algorithm_computation_aoi_toi(
|
|
86
|
+
algorithm_config_id,
|
|
87
|
+
start_date,
|
|
88
|
+
end_date,
|
|
89
|
+
aoi_file,
|
|
90
|
+
date_format=date_format,
|
|
91
|
+
frequency=frequency,
|
|
92
|
+
)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
tsu.echo_highlight_suffix("computation_id: ", computation_id, 'green')
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@computation.command(name='run')
|
|
99
|
+
@click.pass_context
|
|
100
|
+
@click.option('-ip', '--algorithm_computation_id', type=str)
|
|
101
|
+
@click.option('--dry_run', is_flag=True)
|
|
102
|
+
@click.option('-v', '--verbose', is_flag=True)
|
|
103
|
+
def algorithm_computation_run(
|
|
104
|
+
ctx,
|
|
105
|
+
algorithm_computation_id,
|
|
106
|
+
dry_run,
|
|
107
|
+
verbose,
|
|
108
|
+
):
|
|
109
|
+
|
|
110
|
+
wf.check_environment_complete(raise_on_failure=True)
|
|
111
|
+
click.echo(f"Running algorithm_computation_id={algorithm_computation_id} (dry_run={dry_run})")
|
|
112
|
+
if not dry_run:
|
|
113
|
+
asyncio.run(wf.run_algorithm_computations([algorithm_computation_id]))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@computation.command(name='download')
|
|
117
|
+
@click.pass_context
|
|
118
|
+
@click.option('-ip', '--algorithm_computation_id', type=str)
|
|
119
|
+
@click.option('-a', '--source_aoi_version', type=str)
|
|
120
|
+
@click.option('-os', '--min_observation_start_ts', type=str)
|
|
121
|
+
@click.option('-oe', '--max_observation_start_ts', type=str)
|
|
122
|
+
@click.option('-d', '--download_dir', type=str)
|
|
123
|
+
@click.option('-c', '--clobber', is_flag=True, help="Overwrite existing output")
|
|
124
|
+
def algorithm_computation_download(
|
|
125
|
+
ctx,
|
|
126
|
+
algorithm_computation_id,
|
|
127
|
+
source_aoi_version=None,
|
|
128
|
+
min_observation_start_ts=None,
|
|
129
|
+
max_observation_start_ts=None,
|
|
130
|
+
download_dir=None,
|
|
131
|
+
clobber=False,
|
|
132
|
+
):
|
|
133
|
+
wf.check_environment_complete(raise_on_failure=True)
|
|
134
|
+
|
|
135
|
+
if os.path.exists(download_dir):
|
|
136
|
+
if not clobber:
|
|
137
|
+
click.secho(f"Directory: {download_dir} exists. Run with '-c' to overwrite. Exiting.", fg='red')
|
|
138
|
+
raise RuntimeError("Output file already exists.")
|
|
139
|
+
else:
|
|
140
|
+
click.secho(f"Directory: {download_dir} exists. I'm removing it.", fg='yellow')
|
|
141
|
+
os.rmdir(download_dir)
|
|
142
|
+
|
|
143
|
+
asyncio.run(
|
|
144
|
+
wf.download_algorithm_computation_results(
|
|
145
|
+
algorithm_computation_ids=[algorithm_computation_id], source_aoi_version=source_aoi_version,
|
|
146
|
+
min_observation_start_ts=min_observation_start_ts, max_observation_start_ts=max_observation_start_ts,
|
|
147
|
+
download_dir=download_dir
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
if not os.path.exists(download_dir):
|
|
152
|
+
click.secho("NOT written", fg='red')
|
|
153
|
+
else:
|
|
154
|
+
click.secho("written.", fg='green')
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
import asyncio
|
|
5
|
+
import pandas as pd
|
|
6
|
+
import yaml
|
|
7
|
+
import elements.cli.lib.utils as tsu
|
|
8
|
+
from elements.cli.lib.aliased_group import AliasedGroup
|
|
9
|
+
import elements.cli.lib.workflow as wf
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@click.group(cls=AliasedGroup, help="Algorithm 'config' command group")
|
|
13
|
+
@click.pass_context
|
|
14
|
+
def config(ctx):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@config.command('get')
|
|
19
|
+
@click.pass_context
|
|
20
|
+
@click.option('-ic', '--algorithm_config_id', type=str, default=None,
|
|
21
|
+
help="UUID of the algorithm config to look up.")
|
|
22
|
+
@click.option('-iv', '--algorithm_version_id', type=str, default=None,
|
|
23
|
+
help="UUID of an algorithm version to look up associated algorithm configs.")
|
|
24
|
+
@click.option('-n', '--algorithm_name', type=str, default=None,
|
|
25
|
+
help="Name of the algorithm to look up. All matching algo versions will be queried")
|
|
26
|
+
@click.option('-C', '--only_columns', multiple=True,
|
|
27
|
+
help="Include only the listed columns in output.")
|
|
28
|
+
@click.option('-c', '--append_columns', multiple=True,
|
|
29
|
+
help="Append these columns to those shown by default.")
|
|
30
|
+
@click.option('-T', '--transpose', is_flag=True,
|
|
31
|
+
help="Display the result in transpose (helpful to show algorithms with long string values).")
|
|
32
|
+
def algorithm_config_get(
|
|
33
|
+
ctx,
|
|
34
|
+
algorithm_config_id,
|
|
35
|
+
algorithm_version_id,
|
|
36
|
+
algorithm_name,
|
|
37
|
+
only_columns,
|
|
38
|
+
append_columns,
|
|
39
|
+
transpose,
|
|
40
|
+
):
|
|
41
|
+
algorithm_version_ids = []
|
|
42
|
+
if algorithm_version_id is not None:
|
|
43
|
+
algorithm_version_ids.append([algorithm_version_id, None, None])
|
|
44
|
+
|
|
45
|
+
# if requested by name, we'll look up the available version ids and run all of them.
|
|
46
|
+
if algorithm_name is not None:
|
|
47
|
+
algos = asyncio.run(wf.list_algorithms(algorithm_name))
|
|
48
|
+
for algo in algos:
|
|
49
|
+
algorithm_versions = asyncio.run(wf.get_algorithm_versions(algo.id))
|
|
50
|
+
for algorithm_version in algorithm_versions:
|
|
51
|
+
algorithm_version_ids.append([algorithm_version.id, algo.name, algo.id])
|
|
52
|
+
|
|
53
|
+
for algorithm_version_info in algorithm_version_ids:
|
|
54
|
+
algorithm_version_id = algorithm_version_info[0]
|
|
55
|
+
algorithm_configs = asyncio.run(wf.get_algorithm_configs(algorithm_version_id=algorithm_version_id))
|
|
56
|
+
_print_algorithm_configs(algorithm_version_info, algorithm_configs, only_columns, append_columns, transpose)
|
|
57
|
+
|
|
58
|
+
if algorithm_config_id:
|
|
59
|
+
algorithm_configs = asyncio.run(wf.get_algorithm_configs(algorithm_config_id=algorithm_config_id))
|
|
60
|
+
algorithm_version_info = [algorithm_version_id, None, None]
|
|
61
|
+
_print_algorithm_configs(algorithm_version_info, algorithm_configs, only_columns, append_columns, transpose)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _print_algorithm_configs(
|
|
65
|
+
algorithm_version_info,
|
|
66
|
+
algorithm_configs,
|
|
67
|
+
only_columns,
|
|
68
|
+
append_columns,
|
|
69
|
+
transpose
|
|
70
|
+
):
|
|
71
|
+
|
|
72
|
+
algo_version_id, algo_name, algo_id = algorithm_version_info
|
|
73
|
+
click.secho(f"name: {algo_name}", fg='magenta')
|
|
74
|
+
click.secho(f" algo_id: {algo_id}", fg='magenta')
|
|
75
|
+
click.secho(f" algo_version_id: {algo_version_id}", fg='magenta')
|
|
76
|
+
|
|
77
|
+
columns = ['name', 'id', 'description', 'created_on']
|
|
78
|
+
if only_columns:
|
|
79
|
+
columns = list(only_columns)
|
|
80
|
+
if append_columns:
|
|
81
|
+
columns = columns + list(append_columns)
|
|
82
|
+
|
|
83
|
+
algorithm_configs = tsu.protobuf_to_dict(algorithm_configs[0])
|
|
84
|
+
if 'algorithm_configs' in algorithm_configs:
|
|
85
|
+
algorithm_configs = algorithm_configs['algorithm_configs']
|
|
86
|
+
else:
|
|
87
|
+
algorithm_configs = [algorithm_configs]
|
|
88
|
+
|
|
89
|
+
data = []
|
|
90
|
+
for algorithm_config in algorithm_configs:
|
|
91
|
+
data.append(algorithm_config)
|
|
92
|
+
df = pd.DataFrame(data)
|
|
93
|
+
if 'all' not in columns:
|
|
94
|
+
df = df[tsu.match_columns(df.columns, columns)]
|
|
95
|
+
if transpose:
|
|
96
|
+
df = df.T.rename(columns={0: ""})
|
|
97
|
+
df = df.rename(columns={'id': 'algorithm_config_id'})
|
|
98
|
+
tsu.set_pandas_display()
|
|
99
|
+
click.secho(f"algorithm_version_id: {algo_version_id}", fg='cyan')
|
|
100
|
+
click.echo(df)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@config.command('create')
|
|
104
|
+
@click.pass_context
|
|
105
|
+
@click.option('-iv', '--algorithm_version_id', type=str)
|
|
106
|
+
@click.option('-m', '--manifest_yaml', type=str)
|
|
107
|
+
@click.option('-nc', '--config_name', type=str)
|
|
108
|
+
@click.option('-d', '--config_desc', type=str)
|
|
109
|
+
@click.option('-s', '--data_source', type=str)
|
|
110
|
+
@click.option('-t', '--data_type', type=str)
|
|
111
|
+
@click.option('-p', '--image_processing_spec', type=str, default=None)
|
|
112
|
+
@click.option('--dry_run', is_flag=True)
|
|
113
|
+
def algorithm_config_create(
|
|
114
|
+
ctx,
|
|
115
|
+
algorithm_version_id,
|
|
116
|
+
manifest_yaml,
|
|
117
|
+
config_name,
|
|
118
|
+
config_desc,
|
|
119
|
+
data_source,
|
|
120
|
+
data_type,
|
|
121
|
+
image_processing_spec=None,
|
|
122
|
+
dry_run=False,
|
|
123
|
+
):
|
|
124
|
+
|
|
125
|
+
wf.check_environment_complete(raise_on_failure=True)
|
|
126
|
+
input_manifest = None
|
|
127
|
+
with open(manifest_yaml, 'r') as fp:
|
|
128
|
+
input_manifest = yaml.safe_load(fp)
|
|
129
|
+
|
|
130
|
+
if not data_source:
|
|
131
|
+
try:
|
|
132
|
+
data_source = input_manifest['inputs'][0]['data_source_name']
|
|
133
|
+
except Exception:
|
|
134
|
+
click.secho("Data source must be provided in manifest or on commandline", fg='red')
|
|
135
|
+
raise
|
|
136
|
+
|
|
137
|
+
if not data_type:
|
|
138
|
+
try:
|
|
139
|
+
data_type = input_manifest['inputs'][0]['data_type_name']
|
|
140
|
+
except Exception:
|
|
141
|
+
click.secho("Data Type must be provided in manifest or on command line", fg='red')
|
|
142
|
+
raise
|
|
143
|
+
|
|
144
|
+
# image proc spec isn't always required. if not given, check the manifest. use it if it's provided.
|
|
145
|
+
if not image_processing_spec:
|
|
146
|
+
image_processing_spec = input_manifest['inputs'][0]['parameters'].get('image_processing_spec', None)
|
|
147
|
+
data_parameters = {}
|
|
148
|
+
if image_processing_spec:
|
|
149
|
+
data_parameters['image_processing_spec'] = image_processing_spec
|
|
150
|
+
|
|
151
|
+
click.echo("Using the following information:")
|
|
152
|
+
click.echo(f"--> algorithm_version_id: {algorithm_version_id}")
|
|
153
|
+
click.echo(f"--> config_name: {config_name}")
|
|
154
|
+
click.echo(f"--> config_desc: {config_desc}")
|
|
155
|
+
click.echo(f"--> data_source: {data_source}")
|
|
156
|
+
click.echo(f"--> data_type: {data_type}")
|
|
157
|
+
click.echo(f"--> image_processing_spec: {image_processing_spec}")
|
|
158
|
+
|
|
159
|
+
if not dry_run:
|
|
160
|
+
algorithm_config_id = asyncio.run(
|
|
161
|
+
wf.create_algorithm_config(
|
|
162
|
+
algorithm_version_id,
|
|
163
|
+
config_name,
|
|
164
|
+
config_desc,
|
|
165
|
+
data_source,
|
|
166
|
+
data_type,
|
|
167
|
+
data_parameters,
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
tsu.echo_highlight_suffix("You're new algorithm_config_id is: ", algorithm_config_id, 'green')
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@config.command('deactivate')
|
|
174
|
+
@click.pass_context
|
|
175
|
+
@click.option('-ic', '--algorithm_config_ids', type=str, multiple=True, required=True,
|
|
176
|
+
help="UUIDs of the algorithm_configs to deactivate")
|
|
177
|
+
def algorithm_config_deactivate(
|
|
178
|
+
ctx,
|
|
179
|
+
algorithm_config_ids,
|
|
180
|
+
):
|
|
181
|
+
|
|
182
|
+
response = asyncio.run(wf.deactivate_algorithm_configs(algorithm_config_ids=algorithm_config_ids))
|
|
183
|
+
|
|
184
|
+
click.echo("Deactivation response code: ", nl=False)
|
|
185
|
+
if response:
|
|
186
|
+
click.secho(f" {response} (FAILURE)", fg='red')
|
|
187
|
+
else:
|
|
188
|
+
click.secho(f" {response} (SUCCESS)", fg='green')
|