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.
Files changed (67) hide show
  1. elements/__init__.py +0 -0
  2. elements/cli/__init__.py +0 -0
  3. elements/cli/commands/__init__.py +0 -0
  4. elements/cli/commands/algorithm.py +292 -0
  5. elements/cli/commands/algorithm_computation.py +154 -0
  6. elements/cli/commands/algorithm_config.py +188 -0
  7. elements/cli/commands/algorithm_version.py +157 -0
  8. elements/cli/commands/analysis.py +353 -0
  9. elements/cli/commands/analysis_computation.py +172 -0
  10. elements/cli/commands/analysis_config.py +174 -0
  11. elements/cli/commands/analysis_version.py +145 -0
  12. elements/cli/commands/aoi.py +79 -0
  13. elements/cli/commands/credit.py +51 -0
  14. elements/cli/commands/data.py +146 -0
  15. elements/cli/commands/environment.py +27 -0
  16. elements/cli/commands/imagery.py +145 -0
  17. elements/cli/commands/manifest.py +86 -0
  18. elements/cli/commands/permission.py +59 -0
  19. elements/cli/commands/tasks.py +515 -0
  20. elements/cli/commands/toi.py +59 -0
  21. elements/cli/commands/visualization.py +44 -0
  22. elements/cli/lib/__init__.py +0 -0
  23. elements/cli/lib/aliased_group.py +98 -0
  24. elements/cli/lib/utils.py +134 -0
  25. elements/cli/lib/workflow.py +1808 -0
  26. elements/cli/ts.py +40 -0
  27. elements/sdk/__init__.py +0 -0
  28. elements/sdk/api/__init__.py +0 -0
  29. elements/sdk/api/algorithm.py +666 -0
  30. elements/sdk/api/analysis.py +692 -0
  31. elements/sdk/api/aoi.py +342 -0
  32. elements/sdk/api/credit.py +168 -0
  33. elements/sdk/api/data.py +118 -0
  34. elements/sdk/api/filter.py +77 -0
  35. elements/sdk/api/order.py +71 -0
  36. elements/sdk/api/permission.py +124 -0
  37. elements/sdk/api/result.py +323 -0
  38. elements/sdk/api/tasking_order.py +68 -0
  39. elements/sdk/api/toi.py +79 -0
  40. elements/sdk/api/user.py +140 -0
  41. elements/sdk/api/visualization.py +51 -0
  42. elements/sdk/builder/__init__.py +0 -0
  43. elements/sdk/builder/algorithm.py +461 -0
  44. elements/sdk/builder/analysis.py +179 -0
  45. elements/sdk/builder/toi.py +181 -0
  46. elements/sdk/elements_sdk.py +156 -0
  47. elements/sdk/tools/__init__.py +0 -0
  48. elements/sdk/tools/io.py +128 -0
  49. elements/sdk/tools/sdk_support.py +38 -0
  50. privateer_elements_sdk-2025.11.5.dist-info/METADATA +470 -0
  51. privateer_elements_sdk-2025.11.5.dist-info/RECORD +67 -0
  52. privateer_elements_sdk-2025.11.5.dist-info/WHEEL +5 -0
  53. privateer_elements_sdk-2025.11.5.dist-info/entry_points.txt +2 -0
  54. privateer_elements_sdk-2025.11.5.dist-info/licenses/LICENSE +7 -0
  55. privateer_elements_sdk-2025.11.5.dist-info/top_level.txt +2 -0
  56. tests/integration/test_algorithm.py +867 -0
  57. tests/integration/test_algorithm_builder.py +43 -0
  58. tests/integration/test_analysis.py +481 -0
  59. tests/integration/test_analysis_builder.py +28 -0
  60. tests/integration/test_aoi.py +160 -0
  61. tests/integration/test_credit.py +186 -0
  62. tests/integration/test_data.py +43 -0
  63. tests/integration/test_permission.py +120 -0
  64. tests/integration/test_result.py +138 -0
  65. tests/integration/test_sdk_support.py +28 -0
  66. tests/integration/test_toi.py +245 -0
  67. tests/integration/test_visualization.py +9 -0
elements/__init__.py ADDED
File without changes
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')