fusion-platform-python-sdk 1.16.6__tar.gz → 1.17.5__tar.gz
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.
- {fusion_platform_python_sdk-1.16.6/fusion_platform_python_sdk.egg-info → fusion_platform_python_sdk-1.17.5}/PKG-INFO +3 -3
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/README.md +1 -1
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/__init__.py +2 -2
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/command.py +79 -34
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/fusion_platform_sdk.pdf +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/model.py +3 -1
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process.py +14 -3
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_service_execution.md +3 -1
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_service_execution.py +2 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/translations.py +15 -1
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5/fusion_platform_python_sdk.egg-info}/PKG-INFO +3 -3
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/setup.py +2 -2
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/LICENSE.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/MANIFEST.in +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/__main__.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/base.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/common/__init__.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/common/raise_thread.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/common/utilities.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/detailed_example.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/documentation.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/glasgow.geojson +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/lake_district.geojson +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/localisations.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/localise.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/__init__.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/credit.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/credit.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/data.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/data.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/data_file.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/data_file.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/fields.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/organisation.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/organisation.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_execution.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_execution.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_service_execution_log.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/process_service_execution_log.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/service.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/service.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/user.md +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/models/user.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/quick_example.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/session.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform_python_sdk.egg-info/SOURCES.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform_python_sdk.egg-info/dependency_links.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform_python_sdk.egg-info/entry_points.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform_python_sdk.egg-info/requires.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform_python_sdk.egg-info/top_level.txt +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/setup.cfg +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_base.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_command.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_init.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_localise.py +0 -0
- {fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_session.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fusion-platform-python-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.5
|
|
4
4
|
Summary: Python SDK used to interact with the Fusion Platform(r)
|
|
5
5
|
Home-page: https://github.com/d-cat-support/fusion-platform-python-sdk
|
|
6
6
|
Author: Digital Content Analysis Technology Ltd
|
|
@@ -8,11 +8,11 @@ Author-email: support@d-cat.co.uk
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.txt
|
|
18
18
|
Requires-Dist: marshmallow
|
|
@@ -48,7 +48,7 @@ API, and this is defined within the corresponding OpenAPI 3.0 specification, whi
|
|
|
48
48
|
|
|
49
49
|
## Installation
|
|
50
50
|
|
|
51
|
-
The SDK has been built for Python 3, and is tested against Python 3.
|
|
51
|
+
The SDK has been built for Python 3, and is tested against Python 3.9, 3.10, 3.11, 3.12 and 3.13. To install the SDK into a suitable Python environment containing
|
|
52
52
|
`pip`, execute the following:
|
|
53
53
|
|
|
54
54
|
```shell
|
|
@@ -12,7 +12,7 @@ API, and this is defined within the corresponding OpenAPI 3.0 specification, whi
|
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
The SDK has been built for Python 3, and is tested against Python 3.
|
|
15
|
+
The SDK has been built for Python 3, and is tested against Python 3.9, 3.10, 3.11, 3.12 and 3.13. To install the SDK into a suitable Python environment containing
|
|
16
16
|
`pip`, execute the following:
|
|
17
17
|
|
|
18
18
|
```shell
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/__init__.py
RENAMED
|
@@ -11,8 +11,8 @@ API, and this is defined within the corresponding OpenAPI 3.0 specification, whi
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
# Do not modify the following two lines as they are maintained by the version.sh script.
|
|
14
|
-
__version__ = '1.
|
|
15
|
-
__version_date__ = '2025-
|
|
14
|
+
__version__ = '1.17.5'
|
|
15
|
+
__version_date__ = '2025-03-18T06:52:14Z'
|
|
16
16
|
|
|
17
17
|
# Exclude certain sub-modules from documentation.
|
|
18
18
|
# @formatter:off
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/command.py
RENAMED
|
@@ -39,7 +39,7 @@ Localise.setup()
|
|
|
39
39
|
|
|
40
40
|
import fusion_platform
|
|
41
41
|
from fusion_platform.base import Base
|
|
42
|
-
from fusion_platform.common.utilities import json_default
|
|
42
|
+
from fusion_platform.common.utilities import json_default, string_blank
|
|
43
43
|
from fusion_platform.models.data import Data
|
|
44
44
|
from fusion_platform.models.model import Model
|
|
45
45
|
from fusion_platform.session import RequestError
|
|
@@ -103,7 +103,9 @@ class Command(Base):
|
|
|
103
103
|
_METRIC_S3_INPUT_SIZE = 'input_size'
|
|
104
104
|
_METRIC_S3_OUTPUT_SIZE = 'output_size'
|
|
105
105
|
_METRIC_S3_TRANSFER_BYTES = 's3_transfer_bytes'
|
|
106
|
+
_METRIC_GCS_TRANSFER_BYTES = 'gcs_transfer_bytes'
|
|
106
107
|
_METRIC_EXTERNAL_TRANSFER_BYTES = 'external_transfer_bytes'
|
|
108
|
+
_METRIC_INTERNAL_TRANSFER_BYTES = 'internal_transfer_bytes'
|
|
107
109
|
|
|
108
110
|
# Process other field constants.
|
|
109
111
|
_MODEL_FIELDS = ['output_storage_period', 'run_type', 'repeat_count', 'repeat_start', 'repeat_end', 'repeat_gap', 'repeat_offset']
|
|
@@ -193,6 +195,7 @@ class Command(Base):
|
|
|
193
195
|
while not finished:
|
|
194
196
|
# Either find the dispatchers from what has been loaded from the YAML file or prompt the user.
|
|
195
197
|
add = False
|
|
198
|
+
dispatch_intermediate = False
|
|
196
199
|
dispatcher_options = {}
|
|
197
200
|
|
|
198
201
|
if dispatchers is not None:
|
|
@@ -204,6 +207,8 @@ class Command(Base):
|
|
|
204
207
|
selected_dispatcher = filtered_dispatchers[0]
|
|
205
208
|
selected_dispatcher[Model._FIELD_USED] = True
|
|
206
209
|
add = True
|
|
210
|
+
dispatch_intermediate = selected_dispatcher.get(Model._FIELD_DISPATCH_INTERMEDIATE) if selected_dispatcher.get(
|
|
211
|
+
Model._FIELD_DISPATCH_INTERMEDIATE) is not None else False
|
|
207
212
|
dispatcher_options = selected_dispatcher.get(Model._FIELD_OPTIONS) if selected_dispatcher.get(Model._FIELD_OPTIONS) is not None else {}
|
|
208
213
|
|
|
209
214
|
else:
|
|
@@ -213,8 +218,29 @@ class Command(Base):
|
|
|
213
218
|
if (response is not None) and response.lower().startswith(i18n.t('command.prompt_yes').lower()[0]):
|
|
214
219
|
add = True
|
|
215
220
|
|
|
221
|
+
if hasattr(dispatcher, Model._FIELD_DISPATCH_INTERMEDIATE):
|
|
222
|
+
response = self.__get_input(i18n.t('command.dispatch_intermediate'),
|
|
223
|
+
constrained_values=[i18n.t('command.prompt_no'), i18n.t('command.prompt_yes')])
|
|
224
|
+
|
|
225
|
+
if (response is not None) and response.lower().startswith(i18n.t('command.prompt_yes').lower()[0]):
|
|
226
|
+
dispatch_intermediate = True
|
|
227
|
+
|
|
216
228
|
for option in dispatcher.options:
|
|
217
|
-
|
|
229
|
+
finished_options = False
|
|
230
|
+
option_value = None
|
|
231
|
+
|
|
232
|
+
while not finished_options:
|
|
233
|
+
constrained_values = option.constrained_values if option.data_type == fusion_platform.DATA_TYPE_CONSTRAINED else None
|
|
234
|
+
|
|
235
|
+
prompt_constrained_values = i18n.t('models.process.option.representation_constrained_values',
|
|
236
|
+
constrained_values=constrained_values) if constrained_values is not None else ''
|
|
237
|
+
prompt_required = i18n.t('models.process.option.representation_required') if option.required else ''
|
|
238
|
+
prompt = i18n.t('command.prompt_option', title=option.title, name=option.name, data_type=option.data_type,
|
|
239
|
+
constrained_values=prompt_constrained_values, required=prompt_required)
|
|
240
|
+
|
|
241
|
+
option_value = self.__get_input(prompt, default=option.value, constrained_values=constrained_values)
|
|
242
|
+
finished_options = (not option.required) or (
|
|
243
|
+
option.required and (option_value is not None) and (not string_blank(str(option_value))))
|
|
218
244
|
|
|
219
245
|
if option_value is not None:
|
|
220
246
|
dispatcher_options[option.name] = option_value
|
|
@@ -224,7 +250,8 @@ class Command(Base):
|
|
|
224
250
|
dispatchers_added += 1
|
|
225
251
|
|
|
226
252
|
for option_name, option_value in dispatcher_options.items():
|
|
227
|
-
process.update(dispatcher_number=dispatchers_added, option_name=option_name, value=option_value
|
|
253
|
+
process.update(dispatcher_number=dispatchers_added, option_name=option_name, value=option_value, coerce_value=True,
|
|
254
|
+
dispatch_intermediate=dispatch_intermediate)
|
|
228
255
|
else:
|
|
229
256
|
finished = True
|
|
230
257
|
|
|
@@ -254,12 +281,19 @@ class Command(Base):
|
|
|
254
281
|
# Get the underlying service name.
|
|
255
282
|
service, _ = organisation.find_services(ssd_id=process.ssd_id)
|
|
256
283
|
|
|
257
|
-
# Get the options and dispatchers.
|
|
284
|
+
# Get the options and dispatchers, optionally add in whether intermediate services are being dispatched.
|
|
258
285
|
options = {option.name: self.__format_value(option.value, data_type=option.data_type) for option in process.options}
|
|
259
|
-
dispatchers = [
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
286
|
+
dispatchers = []
|
|
287
|
+
|
|
288
|
+
for dispatcher in process.dispatchers:
|
|
289
|
+
found_dispatcher = {Model._FIELD_NAME: dispatcher.name}
|
|
290
|
+
|
|
291
|
+
if hasattr(dispatcher, Model._FIELD_DISPATCH_INTERMEDIATE):
|
|
292
|
+
found_dispatcher[Model._FIELD_DISPATCH_INTERMEDIATE] = dispatcher.dispatch_intermediate
|
|
293
|
+
|
|
294
|
+
found_dispatcher[Model._FIELD_OPTIONS] = {option.name: self.__format_value(option.value, data_type=option.data_type) for option in dispatcher.options}
|
|
295
|
+
|
|
296
|
+
dispatchers.append(found_dispatcher)
|
|
263
297
|
|
|
264
298
|
# Add in the standard options.
|
|
265
299
|
for field in Command._MODEL_FIELDS:
|
|
@@ -418,7 +452,8 @@ class Command(Base):
|
|
|
418
452
|
|
|
419
453
|
return found
|
|
420
454
|
|
|
421
|
-
def __download_execution(self, process, download_inputs, download_outputs, download_storage, download_intermediate, download_components, output_dir,
|
|
455
|
+
def __download_execution(self, process, download_inputs, download_outputs, download_storage, download_intermediate, download_components, output_dir, wait,
|
|
456
|
+
execution):
|
|
422
457
|
"""
|
|
423
458
|
Downloads an execution.
|
|
424
459
|
|
|
@@ -430,6 +465,7 @@ class Command(Base):
|
|
|
430
465
|
download_intermediate: Should intermediate components be downloaded?
|
|
431
466
|
download_components: The names of the components that should be downloaded? If None or [], then all components are downloaded.
|
|
432
467
|
output_dir: The output directory.
|
|
468
|
+
wait: Wait for the execution to complete?
|
|
433
469
|
execution: The execution to be downloaded.
|
|
434
470
|
|
|
435
471
|
Returns:
|
|
@@ -441,10 +477,10 @@ class Command(Base):
|
|
|
441
477
|
metrics = []
|
|
442
478
|
downloads = []
|
|
443
479
|
|
|
444
|
-
#
|
|
480
|
+
# Optionally wait for the execution to complete. We explicitly wait in this method to keep the SDK free.
|
|
445
481
|
complete = False
|
|
446
482
|
|
|
447
|
-
while not complete:
|
|
483
|
+
while wait and (not complete):
|
|
448
484
|
try:
|
|
449
485
|
complete = execution.check_complete()
|
|
450
486
|
except:
|
|
@@ -480,15 +516,20 @@ class Command(Base):
|
|
|
480
516
|
if (started_at is None) or (execution.started_at < started_at):
|
|
481
517
|
started_at = execution.started_at
|
|
482
518
|
|
|
483
|
-
if (
|
|
484
|
-
|
|
519
|
+
execution_ended_at = execution.ended_at if hasattr(execution, Model._FIELD_ENDED_AT) and (execution.ended_at is not None) else datetime.now(timezone.utc)
|
|
520
|
+
|
|
521
|
+
if (ended_at is None) or (execution_ended_at > ended_at):
|
|
522
|
+
ended_at = execution_ended_at
|
|
485
523
|
|
|
486
524
|
for j, component in enumerate(components):
|
|
487
525
|
# Download the component.
|
|
488
526
|
component_name = '_'.join([item for item in re.sub(r'[\W]', '_', component.name).split('_') if len(item) > 0])
|
|
489
527
|
component_dir = f"{str(j + 1)}_{component_name[:25]}"
|
|
490
528
|
component_options = {item.get(Model._FIELD_NAME): item.get(Model._FIELD_VALUE) for item in component.options} if hasattr(component,
|
|
491
|
-
Model._FIELD_OPTIONS)
|
|
529
|
+
Model._FIELD_OPTIONS) and (
|
|
530
|
+
component.options is not None) else {}
|
|
531
|
+
component_success = component.success if hasattr(component, Model._FIELD_SUCCESS) and (component.success is not None) else False
|
|
532
|
+
component_runtime = component.runtime if hasattr(component, Model._FIELD_RUNTIME) and (component.runtime is not None) else 0
|
|
492
533
|
|
|
493
534
|
# Save the metrics for each component in the execution.
|
|
494
535
|
# @formatter:off
|
|
@@ -497,25 +538,22 @@ class Command(Base):
|
|
|
497
538
|
Command._METRICS_PROCESS: process.name,
|
|
498
539
|
Command._METRICS_DURATION: ended_at - started_at if (started_at is not None) and (ended_at is not None) else 0,
|
|
499
540
|
Command._METRICS_COMPONENT: component.name,
|
|
500
|
-
Command._METRICS_SUCCESS:
|
|
541
|
+
Command._METRICS_SUCCESS: component_success,
|
|
501
542
|
Command._METRICS_CPU: component.cpu,
|
|
502
543
|
Command._METRICS_MEMORY: component.memory,
|
|
503
|
-
Command._METRICS_RUNTIME:
|
|
544
|
+
Command._METRICS_RUNTIME: component_runtime
|
|
504
545
|
}
|
|
505
546
|
# @formatter:on
|
|
506
547
|
|
|
507
548
|
# Only D-CAT services have metrics.
|
|
508
|
-
s3_transfer_bytes = 0
|
|
509
|
-
external_transfer_bytes = 0
|
|
510
|
-
|
|
511
549
|
if hasattr(component, Command._METRICS_METRICS) and (component.metrics is not None):
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
550
|
+
for key in [
|
|
551
|
+
Command._METRIC_S3_TRANSFER_BYTES,
|
|
552
|
+
Command._METRIC_GCS_TRANSFER_BYTES,
|
|
553
|
+
Command._METRIC_EXTERNAL_TRANSFER_BYTES,
|
|
554
|
+
Command._METRIC_INTERNAL_TRANSFER_BYTES
|
|
555
|
+
]:
|
|
556
|
+
metric[key] = sum([metric[key] for metric in component.metrics if metric.get(key) is not None])
|
|
519
557
|
|
|
520
558
|
# Find each input, output and storage to download. While traversing each, save the input and output size. The size might not be immediately available
|
|
521
559
|
# for every file, so wait for all items to be analysed.
|
|
@@ -574,8 +612,8 @@ class Command(Base):
|
|
|
574
612
|
with open(os.path.join(download_dir, stac_file_name), 'w') as stac_file:
|
|
575
613
|
stac_file.write(json.dumps(stac_definition, default=json_default))
|
|
576
614
|
|
|
577
|
-
metric[Command._METRIC_S3_INPUT_SIZE] = sum(input_sizes)
|
|
578
|
-
metric[Command._METRIC_S3_OUTPUT_SIZE] = sum(output_sizes)
|
|
615
|
+
metric[Command._METRIC_S3_INPUT_SIZE] = sum(input_sizes) if len(input_sizes) > 0 else ''
|
|
616
|
+
metric[Command._METRIC_S3_OUTPUT_SIZE] = sum(output_sizes) if len(output_sizes) > 0 else ''
|
|
579
617
|
metrics.append(metric)
|
|
580
618
|
|
|
581
619
|
return downloads, metrics
|
|
@@ -649,7 +687,7 @@ class Command(Base):
|
|
|
649
687
|
progress_bar.close()
|
|
650
688
|
|
|
651
689
|
def download_process_execution(self, organisation, process_name, download_inputs, download_outputs, download_storage, download_intermediate,
|
|
652
|
-
download_components, save_metrics):
|
|
690
|
+
download_components, save_metrics, wait_for_execution_to_complete):
|
|
653
691
|
"""
|
|
654
692
|
Downloads the inputs and/or outputs from a process or execution(s).
|
|
655
693
|
|
|
@@ -662,6 +700,7 @@ class Command(Base):
|
|
|
662
700
|
download_intermediate: Should intermediate components be downloaded?
|
|
663
701
|
download_components: The names of the components that should be downloaded? If None or [], then all components are downloaded.
|
|
664
702
|
save_metrics: Save process metrics to file?
|
|
703
|
+
wait_for_execution_to_complete: Optionally wait for completion of the execution?
|
|
665
704
|
|
|
666
705
|
Returns:
|
|
667
706
|
The process model.
|
|
@@ -707,7 +746,8 @@ class Command(Base):
|
|
|
707
746
|
|
|
708
747
|
# Do all the downloads in batches. We use small batches so that we do not swamp memory.
|
|
709
748
|
batch_size = 2 * os.cpu_count() # Downloads don't swamp CPU.
|
|
710
|
-
|
|
749
|
+
wait = i18n.t('command.wait_for_completion') if wait_for_execution_to_complete else ''
|
|
750
|
+
self.__print(logging.INFO, i18n.t('command.download_executions', wait=wait, executions=len(executions)))
|
|
711
751
|
progress_bar = tqdm(total=len(executions), bar_format=Command.__PROGRESS_BAR_FORMAT, colour=Command.__PROGRESS_BAR_COLOUR_ACTIVE,
|
|
712
752
|
unit='execution') # Unit matches keyword argument.
|
|
713
753
|
progress_bar.set_postfix(execution=1)
|
|
@@ -715,7 +755,7 @@ class Command(Base):
|
|
|
715
755
|
try:
|
|
716
756
|
# Now download each execution in batches.
|
|
717
757
|
partial_download_execution = partial(self.__download_execution, process, download_inputs, download_outputs, download_storage, download_intermediate,
|
|
718
|
-
download_components, output_dir)
|
|
758
|
+
download_components, output_dir, wait_for_execution_to_complete)
|
|
719
759
|
results = []
|
|
720
760
|
|
|
721
761
|
with Pool(nodes=batch_size) as pool:
|
|
@@ -855,7 +895,7 @@ class Command(Base):
|
|
|
855
895
|
The user response.
|
|
856
896
|
"""
|
|
857
897
|
default = constrained_values[0] if (default is None) and (constrained_values is not None) and (len(constrained_values) > 0) else default
|
|
858
|
-
input_prompt = f"{input_prompt}{' [' + default + ']' if default is not None else ''}: "
|
|
898
|
+
input_prompt = f"{input_prompt}{' [' + str(default) + ']' if default is not None else ''}: "
|
|
859
899
|
constrained_values = [''] + constrained_values if constrained_values is not None else constrained_values
|
|
860
900
|
|
|
861
901
|
# Set up any validation against constrained values.
|
|
@@ -1089,7 +1129,8 @@ class Command(Base):
|
|
|
1089
1129
|
# Also perform the download, if required.
|
|
1090
1130
|
if arguments.download:
|
|
1091
1131
|
process = self.download_process_execution(organisation, process_name, arguments.inputs, arguments.outputs, arguments.storage,
|
|
1092
|
-
arguments.intermediate, arguments.component, arguments.metrics
|
|
1132
|
+
arguments.intermediate, arguments.component, arguments.metrics,
|
|
1133
|
+
not arguments.no_wait_for_completion)
|
|
1093
1134
|
|
|
1094
1135
|
# And optionally remove the process and its inputs.
|
|
1095
1136
|
if arguments.remove:
|
|
@@ -1112,7 +1153,7 @@ class Command(Base):
|
|
|
1112
1153
|
for process_name in arguments.process:
|
|
1113
1154
|
# Download the process.
|
|
1114
1155
|
process = self.download_process_execution(organisation, process_name, arguments.inputs, arguments.outputs, arguments.storage,
|
|
1115
|
-
arguments.intermediate, arguments.component, arguments.metrics)
|
|
1156
|
+
arguments.intermediate, arguments.component, arguments.metrics, not arguments.no_wait_for_completion)
|
|
1116
1157
|
|
|
1117
1158
|
# And optionally remove the process and its inputs.
|
|
1118
1159
|
if arguments.remove:
|
|
@@ -1189,6 +1230,8 @@ class Command(Base):
|
|
|
1189
1230
|
default=False, action="store_true")
|
|
1190
1231
|
parser_start.add_argument(i18n.t('command.start.component_short'), i18n.t('command.start.component_long'), help=i18n.t('command.start.component_help'),
|
|
1191
1232
|
nargs='*')
|
|
1233
|
+
parser_start.add_argument(i18n.t('command.start.no_wait_for_completion_short'), i18n.t('command.start.no_wait_for_completion_long'),
|
|
1234
|
+
help=i18n.t('command.start.no_wait_for_completion_help'), default=False, action="store_true")
|
|
1192
1235
|
|
|
1193
1236
|
# Define arguments.
|
|
1194
1237
|
parser_define.add_argument(i18n.t('command.define.process_long'), help=i18n.t('command.define.process_help'), nargs='+')
|
|
@@ -1213,6 +1256,8 @@ class Command(Base):
|
|
|
1213
1256
|
default=False, action="store_true")
|
|
1214
1257
|
parser_download.add_argument(i18n.t('command.start.component_short'), i18n.t('command.start.component_long'), help=i18n.t('command.start.component_help'),
|
|
1215
1258
|
nargs='*')
|
|
1259
|
+
parser_download.add_argument(i18n.t('command.start.no_wait_for_completion_short'), i18n.t('command.start.no_wait_for_completion_long'),
|
|
1260
|
+
help=i18n.t('command.start.no_wait_for_completion_help'), default=False, action="store_true")
|
|
1216
1261
|
|
|
1217
1262
|
return parser.parse_args()
|
|
1218
1263
|
|
|
Binary file
|
|
@@ -92,6 +92,7 @@ class Model(Base):
|
|
|
92
92
|
_FIELD_OUTPUTS = 'outputs'
|
|
93
93
|
_FIELD_PROCESS_STATUS = 'process_status'
|
|
94
94
|
_FIELD_RESOLUTION = 'resolution'
|
|
95
|
+
_FIELD_RUNTIME = 'runtime'
|
|
95
96
|
_FIELD_SD = 'sd'
|
|
96
97
|
_FIELD_SELECTOR = 'selector'
|
|
97
98
|
_FIELD_SELECTORS = 'selectors'
|
|
@@ -99,6 +100,7 @@ class Model(Base):
|
|
|
99
100
|
_FIELD_STAC_ITEM = 'stac_item'
|
|
100
101
|
_FIELD_STAC_ITEM_FILE = 'stac_item_file'
|
|
101
102
|
_FIELD_STARTED_AT = 'started_at'
|
|
103
|
+
_FIELD_SUCCESS = 'success'
|
|
102
104
|
_FIELD_PUBLISHABLE = 'publishable'
|
|
103
105
|
_FIELD_SIZE = 'size'
|
|
104
106
|
_FIELD_UNIT = 'unit'
|
|
@@ -770,7 +772,7 @@ class Model(Base):
|
|
|
770
772
|
Returns:
|
|
771
773
|
A string representation of the object.
|
|
772
774
|
"""
|
|
773
|
-
return
|
|
775
|
+
return i18n.t('models.model.representation', name=self.__class__.__name__, attributes=self.attributes)
|
|
774
776
|
|
|
775
777
|
def to_csv(self, exclude=None):
|
|
776
778
|
"""
|
|
@@ -228,7 +228,12 @@ class Option(Model):
|
|
|
228
228
|
Returns:
|
|
229
229
|
A string representation of the object.
|
|
230
230
|
"""
|
|
231
|
-
|
|
231
|
+
constrained_values = i18n.t('models.process.option.representation_constrained_values',
|
|
232
|
+
constrained_values=self.constrained_values) if self.data_type == fusion_platform.DATA_TYPE_CONSTRAINED else ''
|
|
233
|
+
required = i18n.t('models.process.option.representation_required') if self.required else ''
|
|
234
|
+
|
|
235
|
+
return i18n.t('models.process.option.representation', title=self.title, name=self.name, data_type=self.data_type, constrained_values=constrained_values,
|
|
236
|
+
required=required, value=self.value, description=self.description)
|
|
232
237
|
|
|
233
238
|
|
|
234
239
|
# Define a model class for an input which overrides the representation to display more relevant information.
|
|
@@ -243,7 +248,10 @@ class Input(Model):
|
|
|
243
248
|
Returns:
|
|
244
249
|
A string representation of the object.
|
|
245
250
|
"""
|
|
246
|
-
|
|
251
|
+
name = i18n.t('models.process.input.representation_name', name=self.name) if hasattr(self, self.__class__._FIELD_NAME) else ''
|
|
252
|
+
id = i18n.t('models.process.input.representation_id', id=self.id) if hasattr(self, self.__class__._FIELD_ID) else ''
|
|
253
|
+
|
|
254
|
+
return i18n.t('models.process.input.representation', title=self.title, file_type=self.file_type, name=name, id=id, description=self.description)
|
|
247
255
|
|
|
248
256
|
|
|
249
257
|
# Define a model class for a dispatcher which overrides the representation to display more relevant information.
|
|
@@ -268,7 +276,10 @@ class Dispatcher(Model):
|
|
|
268
276
|
Returns:
|
|
269
277
|
A string representation of the object.
|
|
270
278
|
"""
|
|
271
|
-
|
|
279
|
+
dispatch_intermediate = self.dispatch_intermediate if hasattr(self, self.__class__._FIELD_DISPATCH_INTERMEDIATE) else False
|
|
280
|
+
|
|
281
|
+
return i18n.t('models.process.dispatcher.representation', name=self.name, ssd_id=self.ssd_id, dispatch_intermediate=dispatch_intermediate,
|
|
282
|
+
documentation_summary=self.documentation_summary)
|
|
272
283
|
|
|
273
284
|
|
|
274
285
|
# Define the model schema classes. These are maintained from the API definitions.
|
|
@@ -51,5 +51,7 @@
|
|
|
51
51
|
* **tmp_total_bytes**: The total temporary disk space in bytes.
|
|
52
52
|
* **tmp_free_bytes**: The free temporary disk space in bytes.
|
|
53
53
|
* **s3_transfer_bytes**: The number of bytes transferred in from S3.
|
|
54
|
-
* **
|
|
54
|
+
* **gcs_transfer_bytes**: The number of bytes transferred in from Google Cloud Storage.
|
|
55
|
+
* **external_transfer_bytes**: The number of bytes transferred in externally.
|
|
56
|
+
* **internal_transfer_bytes**: The number of bytes transferred in internally.
|
|
55
57
|
* **comment**: Any comment recorded with the metric.
|
|
@@ -93,7 +93,9 @@ class ProcessServiceExecutionMetricSchema(Schema):
|
|
|
93
93
|
tmp_total_bytes = fields.Integer(allow_none=True)
|
|
94
94
|
tmp_free_bytes = fields.Integer(allow_none=True)
|
|
95
95
|
s3_transfer_bytes = fields.Integer(allow_none=True)
|
|
96
|
+
gcs_transfer_bytes = fields.Integer(allow_none=True)
|
|
96
97
|
external_transfer_bytes = fields.Integer(allow_none=True)
|
|
98
|
+
internal_transfer_bytes = fields.Integer(allow_none=True)
|
|
97
99
|
comment = fields.String(allow_none=True)
|
|
98
100
|
|
|
99
101
|
class Meta:
|
|
@@ -46,6 +46,7 @@ i18n.add_translation('command.log_field', '%{field}: %{value}', 'en')
|
|
|
46
46
|
i18n.add_translation('command.log_subdivider', '................................................................................................', 'en')
|
|
47
47
|
i18n.add_translation('command.log_divider', '------------------------------------------------------------------------------------------------', 'en')
|
|
48
48
|
i18n.add_translation('command.log_bookend', '************************************************************************************************', 'en')
|
|
49
|
+
i18n.add_translation('command.wait_for_completion', ' and waiting for completion', 'en')
|
|
49
50
|
i18n.add_translation('command.wait_for_next', 'Waiting for next execution...', 'en')
|
|
50
51
|
i18n.add_translation('command.using_storage', 'Uploading storage \'%{filename}\' with id %{storage_id} to \'%{storage_name}\'', 'en')
|
|
51
52
|
i18n.add_translation('command.using_service', 'Using service \'%{service}\'', 'en')
|
|
@@ -58,6 +59,7 @@ i18n.add_translation('command.remove_process', 'Removing input \'%{process}\'',
|
|
|
58
59
|
i18n.add_translation('command.remove_input', 'Removing input \'%{input}\'', 'en')
|
|
59
60
|
i18n.add_translation('command.prompt_yes', 'Yes', 'en')
|
|
60
61
|
i18n.add_translation('command.prompt_no', 'No', 'en')
|
|
62
|
+
i18n.add_translation('command.prompt_option', '%{title} (\'%{name}\', %{data_type}%{constrained_values}%{required})', 'en')
|
|
61
63
|
i18n.add_translation('command.password', 'Password', 'en')
|
|
62
64
|
i18n.add_translation('command.organisation', 'Organisation', 'en')
|
|
63
65
|
i18n.add_translation('command.find_inputs', 'Finding %{inputs} input file(s)...', 'en')
|
|
@@ -66,11 +68,12 @@ i18n.add_translation('command.email', 'Email', 'en')
|
|
|
66
68
|
i18n.add_translation('command.download_process_execution', 'Downloading \'%{process}\' (inputs %{inputs}, outputs %{outputs}, storage %{storage}, intermediate %{intermediate}, metrics %{metrics}, components %{components})', 'en')
|
|
67
69
|
i18n.add_translation('command.download_process', 'Downloading process \'%{process}\' to %{output}', 'en')
|
|
68
70
|
i18n.add_translation('command.download_files', 'Downloading %{files} file(s)...', 'en')
|
|
69
|
-
i18n.add_translation('command.download_executions', 'Gathering files for %{executions} execution(s)...', 'en')
|
|
71
|
+
i18n.add_translation('command.download_executions', 'Gathering files%{wait} for %{executions} execution(s)...', 'en')
|
|
70
72
|
i18n.add_translation('command.download_execution', 'Downloading execution %{execution} to %{output}', 'en')
|
|
71
73
|
i18n.add_translation('command.define_storage', 'Defining storage file(s) for %{slices} slice(s)...', 'en')
|
|
72
74
|
i18n.add_translation('command.define_process', 'Defining \'%{process}\' (inputs %{inputs}, storage %{storage})', 'en')
|
|
73
75
|
i18n.add_translation('command.define_inputs', 'Defining %{files} input file(s)...', 'en')
|
|
76
|
+
i18n.add_translation('command.dispatch_intermediate', 'Dispatch intermediate components?', 'en')
|
|
74
77
|
i18n.add_translation('command.add_dispatcher', 'Add %{dispatcher} dispatcher?', 'en')
|
|
75
78
|
i18n.add_translation('command.download.process_help', 'the name of the process, the process id or execution id to download', 'en')
|
|
76
79
|
i18n.add_translation('command.download.process_long', 'process', 'en')
|
|
@@ -80,6 +83,9 @@ i18n.add_translation('command.define.process_help', 'the name of the process, th
|
|
|
80
83
|
i18n.add_translation('command.define.process_long', 'process', 'en')
|
|
81
84
|
i18n.add_translation('command.define.help', 'outputs a YAML file for each existing process', 'en')
|
|
82
85
|
i18n.add_translation('command.define.command', 'define', 'en')
|
|
86
|
+
i18n.add_translation('command.start.no_wait_for_completion_help', 'do not wait for the execution to complete (default %%(default)s)\'', 'en')
|
|
87
|
+
i18n.add_translation('command.start.no_wait_for_completion_long', '--no_wait_for_completion', 'en')
|
|
88
|
+
i18n.add_translation('command.start.no_wait_for_completion_short', '-n', 'en')
|
|
83
89
|
i18n.add_translation('command.start.metrics_help', 'save process metrics to file (default %%(default)s)', 'en')
|
|
84
90
|
i18n.add_translation('command.start.metrics_long', '--metrics', 'en')
|
|
85
91
|
i18n.add_translation('command.start.metrics_short', '-t', 'en')
|
|
@@ -280,6 +286,7 @@ i18n.add_translation('models.model.no_such_keys', 'No such keys %{keys}', 'en')
|
|
|
280
286
|
i18n.add_translation('models.model.readonly_property', 'Property %{property} is read-only and cannot be set', 'en')
|
|
281
287
|
i18n.add_translation('models.model.not_persisted', 'Model is not persisted in the Fusion Platform(r)', 'en')
|
|
282
288
|
i18n.add_translation('models.model.already_persisted', 'Model is already persisted in the Fusion Platform(r)', 'en')
|
|
289
|
+
i18n.add_translation('models.model.representation', '%{name}%{attributes}', 'en')
|
|
283
290
|
i18n.add_translation('models.process.failed_copy', 'Failed to get process from copy response', 'en')
|
|
284
291
|
i18n.add_translation('models.process.execution_should_have_started', 'Process execution should have started by now', 'en')
|
|
285
292
|
i18n.add_translation('models.process.execution_stopped', 'Process execution has been stopped', 'en')
|
|
@@ -298,4 +305,11 @@ i18n.add_translation('models.process.option.constrained_values.description', 'Th
|
|
|
298
305
|
i18n.add_translation('models.process.option.constrained_values.title', 'Constrained Values', 'en')
|
|
299
306
|
i18n.add_translation('models.process.option.constrained_names.description', 'The constrained value names for the option.', 'en')
|
|
300
307
|
i18n.add_translation('models.process.option.constrained_names.title', 'Constrained Names', 'en')
|
|
308
|
+
i18n.add_translation('models.process.option.representation_required', ', required', 'en')
|
|
309
|
+
i18n.add_translation('models.process.option.representation_constrained_values', ' %{constrained_values}', 'en')
|
|
310
|
+
i18n.add_translation('models.process.option.representation', '%{title} (\'%{name}\', %{data_type}%{constrained_values}%{required}) = %{value}: %{description}', 'en')
|
|
311
|
+
i18n.add_translation('models.process.input.representation_id', ' (%{id})', 'en')
|
|
312
|
+
i18n.add_translation('models.process.input.representation_name', ' %{name}', 'en')
|
|
313
|
+
i18n.add_translation('models.process.input.representation', '%{title} (%{file_type}) =%{name}%{id}: %{description}', 'en')
|
|
314
|
+
i18n.add_translation('models.process.dispatcher.representation', '%{name} (%{ssd_id}, intermediate %{dispatch_intermediate}): %{documentation_summary}', 'en')
|
|
301
315
|
# @formatter:on
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: fusion-platform-python-sdk
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.17.5
|
|
4
4
|
Summary: Python SDK used to interact with the Fusion Platform(r)
|
|
5
5
|
Home-page: https://github.com/d-cat-support/fusion-platform-python-sdk
|
|
6
6
|
Author: Digital Content Analysis Technology Ltd
|
|
@@ -8,11 +8,11 @@ Author-email: support@d-cat.co.uk
|
|
|
8
8
|
License: MIT
|
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
16
|
Description-Content-Type: text/markdown
|
|
17
17
|
License-File: LICENSE.txt
|
|
18
18
|
Requires-Dist: marshmallow
|
|
@@ -48,7 +48,7 @@ API, and this is defined within the corresponding OpenAPI 3.0 specification, whi
|
|
|
48
48
|
|
|
49
49
|
## Installation
|
|
50
50
|
|
|
51
|
-
The SDK has been built for Python 3, and is tested against Python 3.
|
|
51
|
+
The SDK has been built for Python 3, and is tested against Python 3.9, 3.10, 3.11, 3.12 and 3.13. To install the SDK into a suitable Python environment containing
|
|
52
52
|
`pip`, execute the following:
|
|
53
53
|
|
|
54
54
|
```shell
|
|
@@ -19,7 +19,7 @@ PACKAGE_DIR = pathlib.Path(__file__).parent
|
|
|
19
19
|
# @formatter:off
|
|
20
20
|
setup(
|
|
21
21
|
name='fusion-platform-python-sdk',
|
|
22
|
-
version='1.
|
|
22
|
+
version='1.17.5',
|
|
23
23
|
description='Python SDK used to interact with the Fusion Platform(r)',
|
|
24
24
|
long_description=(PACKAGE_DIR / 'README.md').read_text(),
|
|
25
25
|
long_description_content_type='text/markdown',
|
|
@@ -30,11 +30,11 @@ setup(
|
|
|
30
30
|
classifiers=[
|
|
31
31
|
'License :: OSI Approved :: MIT License',
|
|
32
32
|
'Programming Language :: Python :: 3',
|
|
33
|
-
'Programming Language :: Python :: 3.8',
|
|
34
33
|
'Programming Language :: Python :: 3.9',
|
|
35
34
|
'Programming Language :: Python :: 3.10',
|
|
36
35
|
'Programming Language :: Python :: 3.11',
|
|
37
36
|
'Programming Language :: Python :: 3.12',
|
|
37
|
+
'Programming Language :: Python :: 3.13',
|
|
38
38
|
],
|
|
39
39
|
packages=find_packages(exclude='tests'),
|
|
40
40
|
include_package_data=True,
|
|
File without changes
|
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/__main__.py
RENAMED
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/localise.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/fusion_platform/session.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_command.py
RENAMED
|
File without changes
|
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_localise.py
RENAMED
|
File without changes
|
{fusion_platform_python_sdk-1.16.6 → fusion_platform_python_sdk-1.17.5}/tests/test_session.py
RENAMED
|
File without changes
|