yellowdog-cli 9.2.2__tar.gz → 9.2.4__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.
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/PKG-INFO +3 -2
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/README.md +8 -3
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/pyproject.toml +3 -2
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_submit_utils.py +56 -2
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/__init__.py +2 -1
- yellowdog_cli-9.2.4/yellowdog_cli/_version.py +1 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/create.py +12 -43
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/help.py +1 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/list.py +2 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/submit.py +2 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/args.py +1 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/config_types.py +2 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/csv_data.py +1 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/load_config.py +2 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/property_names.py +2 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/submit_utils.py +33 -12
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/version.py +2 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/PKG-INFO +3 -2
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/SOURCES.txt +1 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/requires.txt +2 -1
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/LICENSE +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/PYPI_README.md +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/setup.cfg +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_add_to.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_arguments_assembly.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_build_dc_substitutions.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_compact_json.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_compare.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_create_remove.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_csv_data.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_dataclient_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_demos.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_dryruns.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_entrypoints.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_environment_merge.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_instance_pricing_preference.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_interactive.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_list.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_load_config_helpers.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_ls_formatting.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_misc_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_node_batching.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_nodeaction_args.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_nodeaction_parsing.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_printing.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_property_overrides.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_provision_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_rclone_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_resequence_resources.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_resolve_entity_type.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_select_dc_section.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_start_hold_common.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_submit_batching.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_submit_functions.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_cancel_hold_finish.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_csv_batch.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_dataclient.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_error_handling.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_lifecycle.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_resize.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_system_resources.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_type_check.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_validate_properties.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_variable_processing.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_variable_subs.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/tests/test_ydid_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/abort.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/application.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/boost.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/cancel.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/cloudwizard.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/compare.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/delete.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/download.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/finish.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/follow.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/format_json.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/hold.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/instantiate.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/jsonnet2json.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/ls.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/nodeaction.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/provision.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/remove.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/resize.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/show.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/shutdown.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/start.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/terminate.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/upload.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/__init__.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/check_imports.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/cloudwizard_aws.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/cloudwizard_aws_types.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/cloudwizard_azure.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/cloudwizard_common.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/cloudwizard_gcp.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/compact_json.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/dataclient_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/dataclient_wrapper.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/entity_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/follow_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/interactive.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/items.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/load_resources.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/misc_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/printing.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/provision_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/rclone_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/rich_console_input_fixed.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/settings.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/start_hold_common.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/type_check.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/validate_properties.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/variables.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/wrapper.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli/utils/ydid_utils.py +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/dependency_links.txt +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/entry_points.txt +0 -0
- {yellowdog_cli-9.2.2 → yellowdog_cli-9.2.4}/yellowdog_cli.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yellowdog-cli
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.4
|
|
4
4
|
Summary: Python-based CLI the YellowDog Platform
|
|
5
5
|
Author-email: YellowDog Limited <support@yellowdog.co>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -18,12 +18,13 @@ License-File: LICENSE
|
|
|
18
18
|
Requires-Dist: PyPAC>=0.16.4
|
|
19
19
|
Requires-Dist: dateparser
|
|
20
20
|
Requires-Dist: python-dotenv
|
|
21
|
+
Requires-Dist: jsons
|
|
21
22
|
Requires-Dist: requests
|
|
22
23
|
Requires-Dist: rclone-api
|
|
23
24
|
Requires-Dist: rich>=13.9.4
|
|
24
25
|
Requires-Dist: tabulate>=0.9.0
|
|
25
26
|
Requires-Dist: tomli>=2.4.1
|
|
26
|
-
Requires-Dist: yellowdog-sdk>=15.
|
|
27
|
+
Requires-Dist: yellowdog-sdk>=15.2.0
|
|
27
28
|
Provides-Extra: jsonnet
|
|
28
29
|
Requires-Dist: jsonnet; extra == "jsonnet"
|
|
29
30
|
Provides-Extra: cloudwizard
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
* [yd-upload](#yd-upload-1)
|
|
179
179
|
|
|
180
180
|
<!-- Created by https://github.com/ekalinin/github-markdown-toc -->
|
|
181
|
-
<!-- Added by: pwt, at: Wed Apr 22 11:
|
|
181
|
+
<!-- Added by: pwt, at: Wed Apr 22 11:51:22 BST 2026 -->
|
|
182
182
|
|
|
183
183
|
<!--te-->
|
|
184
184
|
|
|
@@ -900,12 +900,13 @@ The following table outlines all the properties available for defining Work Requ
|
|
|
900
900
|
| `taskCount` | The number of times to execute the Task. | Yes | Yes | Yes | |
|
|
901
901
|
| `taskData` | The data to be passed to the Worker when the Task is started. E.g., `"mydata"`. Becomes file `taskdata.txt` in the Task's working directory when the task executes. | Yes | Yes | Yes | Yes |
|
|
902
902
|
| `taskDataFile` | Populate the `taskData` property above with the contents of the specified file. E.g., `"my_task_data_file.txt"`. | Yes | Yes | Yes | Yes |
|
|
903
|
+
| `taskDataFiles` | Populate the `taskData` property above by concatenating the contents of a list of files. Mutually exclusive with `taskData` and `taskDataFile`. E.g., `["header.txt", "body.txt"]`. | Yes | Yes | Yes | Yes |
|
|
903
904
|
| `taskDataInputs` | A list of data inputs to be downloaded by the task E.g., JSON: `{"source": "src", "destination": "dest"}`, TOML: `{source = "src", destination = "dest"}`. | Yes | Yes | Yes | Yes |
|
|
904
905
|
| `taskDataOutputs` | A list of data outputs to be uploaded at the conclusion of a task E.g., JSON: `{"source": "src", "destination": "dest", "alwaysUpload": true}`, TOML: `{source = "src", destination = "dest", alwaysUpload = true}`. | Yes | Yes | Yes | Yes |
|
|
905
906
|
| `taskName` | The name to use for the Task. Only usable in the TOML file. Mostly useful in conjunction with CSV Task data. E.g., `"my_task_number_{{task_number}}"`. | Yes | | | |
|
|
906
907
|
| `taskGroupCount` | Create `taskGroupCount` duplicates of a single Task Group. | Yes | Yes | | |
|
|
907
908
|
| `taskGroupName` | The name to use for the Task Group. Only usable in the TOML file. E.g., `"my_tg_number_{{task_group_number}}"`. | Yes | | | |
|
|
908
|
-
| `taskTemplate` | Sets default `taskType`, `taskData` (or `taskDataFile`), and/or `environment` for all Tasks in a Task Group; applied by the platform, allowing Tasks to be more compact. E.g., `{"taskType": "docker", "environment": {"X": "1"}}`. | Yes | Yes | Yes | |
|
|
909
|
+
| `taskTemplate` | Sets default `taskType`, `taskData` (or `taskDataFile`/`taskDataFiles`), and/or `environment` for all Tasks in a Task Group; applied by the platform, allowing Tasks to be more compact. E.g., `{"taskType": "docker", "environment": {"X": "1"}}`. | Yes | Yes | Yes | |
|
|
909
910
|
| `taskTimeout` | The timeout in minutes after which an executing Task will be terminated and reported as `FAILED`. E.g. `120.0`. The default is no timeout. | Yes | Yes | Yes | |
|
|
910
911
|
| `timeout` | As above, but set at the individual Task level, which overrides the group level `taskTimeout` property (if present). | Yes | | | Yes |
|
|
911
912
|
| `taskType` | The Task Type of a Task. E.g., `"docker"`. | Yes | | | Yes |
|
|
@@ -1017,7 +1018,7 @@ The `taskTemplate` property on a Task Group optionally sets default values for `
|
|
|
1017
1018
|
|
|
1018
1019
|
Any combination of the three fields can be specified; omitted fields are simply not defaulted. Values specified directly on an individual Task take precedence over the template.
|
|
1019
1020
|
|
|
1020
|
-
`taskDataFile` can be used inside `taskTemplate` as an alternative to `taskData`, exactly as
|
|
1021
|
+
`taskDataFile` or `taskDataFiles` can be used inside `taskTemplate` as an alternative to `taskData`, exactly as they can at the Task level — the file contents are read client-side and used as the `taskData` value. `taskDataFiles` concatenates multiple files in order.
|
|
1021
1022
|
|
|
1022
1023
|
`taskTemplate` can be set in the TOML config (applying globally as a default), at the Work Requirement level, or at the Task Group level. More specific levels take precedence.
|
|
1023
1024
|
|
|
@@ -1136,6 +1137,7 @@ Here's an example of the `workRequirement` section of a TOML configuration file,
|
|
|
1136
1137
|
taskCount = 100
|
|
1137
1138
|
taskData = "my_data_string"
|
|
1138
1139
|
taskDataFile = "my_data_file.txt"
|
|
1140
|
+
taskDataFiles = ["header.txt", "body.txt"]
|
|
1139
1141
|
taskDataInputs = [
|
|
1140
1142
|
{source = "in_src_path_1", destination = "dest_path_1"},
|
|
1141
1143
|
{localPath = "local_file", uploadPath = "in_src_path_2", source = "in_src_path_2", destination = "dest_path_2"},
|
|
@@ -1194,6 +1196,7 @@ Showing all possible properties at the Work Requirement level:
|
|
|
1194
1196
|
"taskCount": 100,
|
|
1195
1197
|
"taskData": "my_task_data_string",
|
|
1196
1198
|
"taskDataFile": "my_data_file.txt",
|
|
1199
|
+
"taskDataFiles": ["header.txt", "body.txt"],
|
|
1197
1200
|
"taskDataInputs": [
|
|
1198
1201
|
{"destination": "dest_path_1", "source": "in_src_path_1"},
|
|
1199
1202
|
{"localPath": "local_file", "uploadPath": "in_src_path_2", "destination": "dest_path_2", "source": "in_src_path_2"}
|
|
@@ -1260,6 +1263,7 @@ Showing all possible properties at the Task Group level:
|
|
|
1260
1263
|
"taskCount": 5,
|
|
1261
1264
|
"taskData": "my_task_data_string",
|
|
1262
1265
|
"taskDataFile": "my_data_file.txt",
|
|
1266
|
+
"taskDataFiles": ["header.txt", "body.txt"],
|
|
1263
1267
|
"taskDataInputs": [
|
|
1264
1268
|
{"destination": "dest_path_1", "source": "in_src_path_1"},
|
|
1265
1269
|
{"localPath": "local_file", "uploadPath": "in_src_path_2", "destination": "dest_path_2", "source": "in_src_path_2"}
|
|
@@ -1307,6 +1311,7 @@ Showing all possible properties at the Task level:
|
|
|
1307
1311
|
"tag": "my_tag",
|
|
1308
1312
|
"taskData": "my_task_data_string",
|
|
1309
1313
|
"taskDataFile": "my_data_file.txt",
|
|
1314
|
+
"taskDataFiles": ["header.txt", "body.txt"],
|
|
1310
1315
|
"taskDataInputs": [
|
|
1311
1316
|
{"destination": "dest_path_1", "source": "in_src_path_1"},
|
|
1312
1317
|
{"localPath": "local_file", "uploadPath": "in_src_path_2", "destination": "dest_path_2", "source": "in_src_path_2"}
|
|
@@ -21,12 +21,13 @@
|
|
|
21
21
|
"PyPAC >= 0.16.4",
|
|
22
22
|
"dateparser",
|
|
23
23
|
"python-dotenv",
|
|
24
|
+
"jsons",
|
|
24
25
|
"requests",
|
|
25
26
|
"rclone-api",
|
|
26
27
|
"rich >= 13.9.4",
|
|
27
28
|
"tabulate >= 0.9.0",
|
|
28
29
|
"tomli >= 2.4.1",
|
|
29
|
-
"yellowdog-sdk >= 15.
|
|
30
|
+
"yellowdog-sdk >= 15.2.0",
|
|
30
31
|
]
|
|
31
32
|
|
|
32
33
|
[[project.authors]]
|
|
@@ -102,7 +103,7 @@
|
|
|
102
103
|
packages = ["yellowdog_cli", "yellowdog_cli.utils"]
|
|
103
104
|
|
|
104
105
|
[tool.setuptools.dynamic.version]
|
|
105
|
-
attr = "yellowdog_cli.
|
|
106
|
+
attr = "yellowdog_cli._version.__version__"
|
|
106
107
|
|
|
107
108
|
[tool.ruff]
|
|
108
109
|
target-version = "py310"
|
|
@@ -15,6 +15,7 @@ from yellowdog_cli.utils.config_types import ConfigWorkRequirement
|
|
|
15
15
|
from yellowdog_cli.utils.property_names import (
|
|
16
16
|
TASK_DATA,
|
|
17
17
|
TASK_DATA_FILE,
|
|
18
|
+
TASK_DATA_FILES,
|
|
18
19
|
TASK_GROUPS,
|
|
19
20
|
TASK_TAG,
|
|
20
21
|
TASKS,
|
|
@@ -166,9 +167,40 @@ class TestResolveTaskData:
|
|
|
166
167
|
assert su.resolve_task_data({TASK_DATA_FILE: str(f)}) == "from-file"
|
|
167
168
|
|
|
168
169
|
def test_raises_when_both_set(self):
|
|
169
|
-
with pytest.raises(ValueError, match="
|
|
170
|
+
with pytest.raises(ValueError, match="Only one of"):
|
|
170
171
|
su.resolve_task_data({TASK_DATA: "x", TASK_DATA_FILE: "f.txt"})
|
|
171
172
|
|
|
173
|
+
def test_raises_when_task_data_and_files_both_set(self):
|
|
174
|
+
with pytest.raises(ValueError, match="Only one of"):
|
|
175
|
+
su.resolve_task_data({TASK_DATA: "x", TASK_DATA_FILES: ["f.txt"]})
|
|
176
|
+
|
|
177
|
+
def test_raises_when_task_data_file_and_files_both_set(self, tmp_path):
|
|
178
|
+
f = tmp_path / "a.txt"
|
|
179
|
+
f.write_text("a")
|
|
180
|
+
with pytest.raises(ValueError, match="Only one of"):
|
|
181
|
+
su.resolve_task_data({TASK_DATA_FILE: str(f), TASK_DATA_FILES: [str(f)]})
|
|
182
|
+
|
|
183
|
+
def test_concatenates_task_data_files(self, tmp_path):
|
|
184
|
+
f1 = tmp_path / "a.txt"
|
|
185
|
+
f1.write_text("hello")
|
|
186
|
+
f2 = tmp_path / "b.txt"
|
|
187
|
+
f2.write_text("world")
|
|
188
|
+
result = su.resolve_task_data({TASK_DATA_FILES: [str(f1), str(f2)]})
|
|
189
|
+
assert result == "hello\nworld\n"
|
|
190
|
+
|
|
191
|
+
def test_task_data_files_single_file(self, tmp_path):
|
|
192
|
+
f = tmp_path / "only.txt"
|
|
193
|
+
f.write_text("content")
|
|
194
|
+
result = su.resolve_task_data({TASK_DATA_FILES: [str(f)]})
|
|
195
|
+
assert result == "content\n"
|
|
196
|
+
|
|
197
|
+
def test_task_data_files_variable_substitution(self, tmp_path, monkeypatch):
|
|
198
|
+
monkeypatch.setenv("_YD_TEST_TDF_VAR", "sub")
|
|
199
|
+
f = tmp_path / "t.txt"
|
|
200
|
+
f.write_text("{{env:_YD_TEST_TDF_VAR}}")
|
|
201
|
+
result = su.resolve_task_data({TASK_DATA_FILES: [str(f)]})
|
|
202
|
+
assert result == "sub\n"
|
|
203
|
+
|
|
172
204
|
def test_variable_substitution_applied_to_file_contents(
|
|
173
205
|
self, tmp_path, monkeypatch
|
|
174
206
|
):
|
|
@@ -218,7 +250,7 @@ class TestGetTaskDataProperty:
|
|
|
218
250
|
self, empty_config_wr
|
|
219
251
|
):
|
|
220
252
|
task = {TASK_DATA: "inline", TASK_DATA_FILE: "file.txt"}
|
|
221
|
-
with pytest.raises(ValueError, match="
|
|
253
|
+
with pytest.raises(ValueError, match="Only one of"):
|
|
222
254
|
su.get_task_data_property(empty_config_wr, {}, {}, task, "t1")
|
|
223
255
|
|
|
224
256
|
def test_task_data_file_read_from_disk(self, empty_config_wr, tmp_path):
|
|
@@ -235,6 +267,28 @@ class TestGetTaskDataProperty:
|
|
|
235
267
|
result = su.get_task_data_property(config, {}, {}, {}, "t1")
|
|
236
268
|
assert result == "cfg-file-contents"
|
|
237
269
|
|
|
270
|
+
def test_task_level_task_data_files_wins_over_wr(self, empty_config_wr, tmp_path):
|
|
271
|
+
f = tmp_path / "t.txt"
|
|
272
|
+
f.write_text("task-files")
|
|
273
|
+
task = {TASK_DATA_FILES: [str(f)]}
|
|
274
|
+
wr_data = {TASK_DATA: "wr-level"}
|
|
275
|
+
result = su.get_task_data_property(empty_config_wr, wr_data, {}, task, "t1")
|
|
276
|
+
assert result == "task-files\n"
|
|
277
|
+
|
|
278
|
+
def test_config_wr_task_data_files_used_as_final_fallback(self, tmp_path):
|
|
279
|
+
f1 = tmp_path / "a.txt"
|
|
280
|
+
f1.write_text("part1")
|
|
281
|
+
f2 = tmp_path / "b.txt"
|
|
282
|
+
f2.write_text("part2")
|
|
283
|
+
config = ConfigWorkRequirement(task_data_files=[str(f1), str(f2)])
|
|
284
|
+
result = su.get_task_data_property(config, {}, {}, {}, "t1")
|
|
285
|
+
assert result == "part1\npart2\n"
|
|
286
|
+
|
|
287
|
+
def test_raises_when_task_data_and_files_set_at_task_level(self, empty_config_wr):
|
|
288
|
+
task = {TASK_DATA: "inline", TASK_DATA_FILES: ["f.txt"]}
|
|
289
|
+
with pytest.raises(ValueError, match="Only one of"):
|
|
290
|
+
su.get_task_data_property(empty_config_wr, {}, {}, task, "t1")
|
|
291
|
+
|
|
238
292
|
|
|
239
293
|
# ---------------------------------------------------------------------------
|
|
240
294
|
# create_task
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "9.2.4"
|
|
@@ -14,32 +14,24 @@ import yellowdog_client.model as model
|
|
|
14
14
|
from dateparser import parse as date_parse
|
|
15
15
|
from requests import post, put
|
|
16
16
|
from requests.exceptions import HTTPError
|
|
17
|
+
from yellowdog_client.common.json import Json
|
|
17
18
|
from yellowdog_client.model import (
|
|
18
|
-
AccountAllowance,
|
|
19
19
|
AddApplicationResponse,
|
|
20
20
|
AddConfiguredWorkerPoolResponse,
|
|
21
21
|
AddGroupRequest,
|
|
22
|
-
AllowanceLimitEnforcement,
|
|
23
|
-
AllowanceResetType,
|
|
24
22
|
ApiKey,
|
|
25
23
|
Application,
|
|
26
|
-
AwsFleetComputeSource,
|
|
27
|
-
AwsFleetPurchaseOption,
|
|
28
24
|
CloudProvider,
|
|
29
25
|
CreateNamespaceRequest,
|
|
30
26
|
Group,
|
|
31
27
|
GroupRole,
|
|
32
28
|
ImageOsType,
|
|
33
|
-
InstanceStatus,
|
|
34
29
|
InternalUser,
|
|
35
30
|
MachineImage,
|
|
36
31
|
MachineImageFamily,
|
|
37
32
|
MachineImageGroup,
|
|
38
33
|
NamespacePolicy,
|
|
39
|
-
RequirementsAllowance,
|
|
40
34
|
RoleScope,
|
|
41
|
-
SourceAllowance,
|
|
42
|
-
SourcesAllowance,
|
|
43
35
|
UpdateGroupRequest,
|
|
44
36
|
User,
|
|
45
37
|
)
|
|
@@ -1328,40 +1320,17 @@ def _get_model_object(class_name: str, resource: dict, **kwargs):
|
|
|
1328
1320
|
if missing:
|
|
1329
1321
|
raise KeyError(f"Missing expected property '{missing[0]}'")
|
|
1330
1322
|
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
]
|
|
1343
|
-
except KeyError:
|
|
1344
|
-
raise ValueError(
|
|
1345
|
-
"Invalid AWS Fleet Compute Source Purchase Option property: "
|
|
1346
|
-
f"'{model_object.purchaseOption!s}'"
|
|
1347
|
-
)
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
def _patch_allowance_enums(model_object) -> None:
|
|
1351
|
-
if isinstance(
|
|
1352
|
-
model_object,
|
|
1353
|
-
(SourceAllowance, SourcesAllowance, RequirementsAllowance, AccountAllowance),
|
|
1354
|
-
):
|
|
1355
|
-
try:
|
|
1356
|
-
model_object.limitEnforcement = AllowanceLimitEnforcement(
|
|
1357
|
-
model_object.limitEnforcement
|
|
1358
|
-
)
|
|
1359
|
-
model_object.resetType = AllowanceResetType(model_object.resetType)
|
|
1360
|
-
model_object.monitoredStatuses = [
|
|
1361
|
-
InstanceStatus(status) for status in model_object.monitoredStatuses
|
|
1362
|
-
]
|
|
1363
|
-
except KeyError as e:
|
|
1364
|
-
raise KeyError(f"Invalid Allowance property: {e}")
|
|
1323
|
+
# Normalize all values to their JSON-compatible representations so that
|
|
1324
|
+
# Json.load can properly structure nested typed fields (e.g. enums,
|
|
1325
|
+
# timedeltas, and nested model objects) — necessary because the SDK's
|
|
1326
|
+
# proxy now calls Json.dump on every outbound request.
|
|
1327
|
+
merged = {}
|
|
1328
|
+
for k, v in {**resource, **kwargs}.items():
|
|
1329
|
+
if isinstance(v, (str, int, float, bool, type(None))):
|
|
1330
|
+
merged[k] = v
|
|
1331
|
+
else:
|
|
1332
|
+
merged[k] = Json.dump(v)
|
|
1333
|
+
return Json.load(merged, cls)
|
|
1365
1334
|
|
|
1366
1335
|
|
|
1367
1336
|
def _get_model_class(class_name: str):
|
|
@@ -10,6 +10,7 @@ from typing import cast
|
|
|
10
10
|
|
|
11
11
|
from requests import get
|
|
12
12
|
from yellowdog_client.common import SearchClient
|
|
13
|
+
from yellowdog_client.common.json import Json
|
|
13
14
|
from yellowdog_client.model import (
|
|
14
15
|
Allowance,
|
|
15
16
|
AllowanceSearch,
|
|
@@ -620,7 +621,7 @@ def get_keyring(name: str) -> Keyring:
|
|
|
620
621
|
headers={"Authorization": f"yd-key {CONFIG_COMMON.key}:{CONFIG_COMMON.secret}"},
|
|
621
622
|
)
|
|
622
623
|
if response.status_code == 200:
|
|
623
|
-
return
|
|
624
|
+
return Json.load(response.json(), Keyring)
|
|
624
625
|
else:
|
|
625
626
|
raise RuntimeError(f"Failed to get Keyring '{name}' ({response.text})")
|
|
626
627
|
|
|
@@ -79,6 +79,7 @@ from yellowdog_cli.utils.property_names import (
|
|
|
79
79
|
TASK_COUNT,
|
|
80
80
|
TASK_DATA,
|
|
81
81
|
TASK_DATA_FILE,
|
|
82
|
+
TASK_DATA_FILES,
|
|
82
83
|
TASK_DATA_INPUTS,
|
|
83
84
|
TASK_DATA_OUTPUTS,
|
|
84
85
|
TASK_GROUP_COUNT,
|
|
@@ -651,6 +652,7 @@ def create_task_group(
|
|
|
651
652
|
except ValueError as e:
|
|
652
653
|
raise ValueError(f"taskTemplate: {e}") from e
|
|
653
654
|
tt.pop(TASK_DATA_FILE, None)
|
|
655
|
+
tt.pop(TASK_DATA_FILES, None)
|
|
654
656
|
if task_data is not None:
|
|
655
657
|
tt[TASK_DATA] = task_data
|
|
656
658
|
task_template = TaskTemplate(**tt)
|
|
@@ -5,7 +5,7 @@ Class to parse command line arguments for all commands.
|
|
|
5
5
|
import argparse
|
|
6
6
|
import sys
|
|
7
7
|
|
|
8
|
-
from yellowdog_cli.
|
|
8
|
+
from yellowdog_cli._version import __version__
|
|
9
9
|
from yellowdog_cli.utils.settings import (
|
|
10
10
|
DEFAULT_PARALLEL_TASK_BATCH_UPLOAD_THREADS,
|
|
11
11
|
DEFAULT_URL,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Configuration classes
|
|
2
|
+
Configuration classes.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from dataclasses import dataclass, field
|
|
@@ -54,6 +54,7 @@ class ConfigWorkRequirement:
|
|
|
54
54
|
task_count: int = 1
|
|
55
55
|
task_data: str | None = None
|
|
56
56
|
task_data_file: str | None = None
|
|
57
|
+
task_data_files: list[str] | None = None
|
|
57
58
|
task_data_inputs: list[dict] | None = None
|
|
58
59
|
task_data_outputs: list[dict] | None = None
|
|
59
60
|
task_group_count: int = 1
|
|
@@ -380,6 +380,7 @@ def csv_expand_toml_tasks(
|
|
|
380
380
|
(config_wr.set_task_names, SET_TASK_NAMES),
|
|
381
381
|
(config_wr.task_data, TASK_DATA),
|
|
382
382
|
(config_wr.task_data_file, TASK_DATA_FILE),
|
|
383
|
+
(config_wr.task_data_files, TASK_DATA_FILES),
|
|
383
384
|
(config_wr.task_data_inputs, TASK_DATA_INPUTS),
|
|
384
385
|
(config_wr.task_data_outputs, TASK_DATA_OUTPUTS),
|
|
385
386
|
(config_wr.task_group_name, TASK_GROUP_NAME), # Note: oddity
|
|
@@ -622,8 +622,9 @@ def load_config_work_requirement() -> ConfigWorkRequirement:
|
|
|
622
622
|
task_batch_size=task_batch_size,
|
|
623
623
|
task_count=task_count,
|
|
624
624
|
task_data=wr_section.get(TASK_DATA),
|
|
625
|
-
task_data_inputs=wr_section.get(TASK_DATA_INPUTS),
|
|
626
625
|
task_data_file=wr_section.get(TASK_DATA_FILE),
|
|
626
|
+
task_data_files=wr_section.get(TASK_DATA_FILES),
|
|
627
|
+
task_data_inputs=wr_section.get(TASK_DATA_INPUTS),
|
|
627
628
|
task_data_outputs=wr_section.get(TASK_DATA_OUTPUTS),
|
|
628
629
|
task_group_count=task_group_count,
|
|
629
630
|
task_group_name=wr_section.get(TASK_GROUP_NAME),
|
|
@@ -84,6 +84,7 @@ TASK_COUNT = "taskCount" # Integer
|
|
|
84
84
|
TASK_DATA = "taskData" # String
|
|
85
85
|
TASK_DATA_DESTINATION = "destination" # String
|
|
86
86
|
TASK_DATA_FILE = "taskDataFile" # String
|
|
87
|
+
TASK_DATA_FILES = "taskDataFiles" # List of Strings
|
|
87
88
|
TASK_DATA_INPUTS = "taskDataInputs" # List of dictionaries
|
|
88
89
|
TASK_DATA_OUTPUTS = "taskDataOutputs" # List of dictionaries
|
|
89
90
|
TASK_DATA_SOURCE = "source" # String
|
|
@@ -200,6 +201,7 @@ ALL_KEYS = [
|
|
|
200
201
|
TASK_DATA,
|
|
201
202
|
TASK_DATA_DESTINATION,
|
|
202
203
|
TASK_DATA_FILE,
|
|
204
|
+
TASK_DATA_FILES,
|
|
203
205
|
TASK_DATA_INPUTS,
|
|
204
206
|
TASK_DATA_OUTPUTS,
|
|
205
207
|
TASK_DATA_SOURCE,
|
|
@@ -34,6 +34,7 @@ from yellowdog_cli.utils.property_names import (
|
|
|
34
34
|
STATUSES_AT_FAILURE,
|
|
35
35
|
TASK_DATA,
|
|
36
36
|
TASK_DATA_FILE,
|
|
37
|
+
TASK_DATA_FILES,
|
|
37
38
|
TASK_DATA_SOURCE,
|
|
38
39
|
TASK_GROUPS,
|
|
39
40
|
TASK_TAG,
|
|
@@ -582,25 +583,36 @@ def resolve_task_data(
|
|
|
582
583
|
files_directory: str = "",
|
|
583
584
|
task_data_default: str | None = None,
|
|
584
585
|
task_data_file_default: str | None = None,
|
|
586
|
+
task_data_files_default: list[str] | None = None,
|
|
585
587
|
) -> str | None:
|
|
586
588
|
"""
|
|
587
589
|
Resolve 'taskData' from a single dict level.
|
|
588
590
|
|
|
589
|
-
Returns the task data string
|
|
590
|
-
|
|
591
|
-
|
|
591
|
+
Returns the task data string — inline, read from a single file, or
|
|
592
|
+
concatenated from a list of files. Returns None if none of the three
|
|
593
|
+
properties are present at this level. Raises ValueError if more than
|
|
594
|
+
one of 'taskData', 'taskDataFile', 'taskDataFiles' is set.
|
|
592
595
|
"""
|
|
593
596
|
task_data = data.get(TASK_DATA, task_data_default)
|
|
594
597
|
task_data_file = data.get(TASK_DATA_FILE, task_data_file_default)
|
|
595
|
-
|
|
598
|
+
task_data_files = data.get(TASK_DATA_FILES, task_data_files_default)
|
|
599
|
+
if sum(bool(x) for x in [task_data, task_data_file, task_data_files]) > 1:
|
|
596
600
|
raise ValueError(
|
|
597
|
-
f"
|
|
601
|
+
f"Only one of '{TASK_DATA}', '{TASK_DATA_FILE}' or "
|
|
602
|
+
f"'{TASK_DATA_FILES}' should be set"
|
|
598
603
|
)
|
|
599
604
|
if task_data:
|
|
600
605
|
return task_data
|
|
601
606
|
if task_data_file:
|
|
602
607
|
with open(resolve_filename(files_directory, task_data_file)) as f:
|
|
603
608
|
return process_variable_substitutions_in_file_contents(f.read())
|
|
609
|
+
if task_data_files:
|
|
610
|
+
result = ""
|
|
611
|
+
for filename in task_data_files:
|
|
612
|
+
with open(resolve_filename(files_directory, filename)) as f:
|
|
613
|
+
result += process_variable_substitutions_in_file_contents(f.read())
|
|
614
|
+
result += "\n"
|
|
615
|
+
return result
|
|
604
616
|
return None
|
|
605
617
|
|
|
606
618
|
|
|
@@ -617,19 +629,28 @@ def get_task_data_property(
|
|
|
617
629
|
level in order. 'taskDataFile' is resolved to its file contents at whichever
|
|
618
630
|
level it is found.
|
|
619
631
|
"""
|
|
620
|
-
for data, task_data_default, task_data_file_default in [
|
|
621
|
-
(task, None, None),
|
|
622
|
-
(task_group_data, None, None),
|
|
623
|
-
(
|
|
632
|
+
for data, task_data_default, task_data_file_default, task_data_files_default in [
|
|
633
|
+
(task, None, None, None),
|
|
634
|
+
(task_group_data, None, None, None),
|
|
635
|
+
(
|
|
636
|
+
wr_data,
|
|
637
|
+
config_wr.task_data,
|
|
638
|
+
config_wr.task_data_file,
|
|
639
|
+
config_wr.task_data_files,
|
|
640
|
+
),
|
|
624
641
|
]:
|
|
625
642
|
try:
|
|
626
643
|
result = resolve_task_data(
|
|
627
|
-
data,
|
|
644
|
+
data,
|
|
645
|
+
files_directory,
|
|
646
|
+
task_data_default,
|
|
647
|
+
task_data_file_default,
|
|
648
|
+
task_data_files_default,
|
|
628
649
|
)
|
|
629
650
|
except ValueError:
|
|
630
651
|
raise ValueError(
|
|
631
|
-
f"Task '{task_name}':
|
|
632
|
-
f"'{TASK_DATA_FILE}'
|
|
652
|
+
f"Task '{task_name}': Only one of '{TASK_DATA}', "
|
|
653
|
+
f"'{TASK_DATA_FILE}' or '{TASK_DATA_FILES}' should be set"
|
|
633
654
|
)
|
|
634
655
|
if result is not None:
|
|
635
656
|
return result
|
|
@@ -10,7 +10,8 @@ from sys import version as py_version
|
|
|
10
10
|
|
|
11
11
|
from yellowdog_client._version import __version__ as yd_sdk_version
|
|
12
12
|
|
|
13
|
-
from yellowdog_cli
|
|
13
|
+
from yellowdog_cli import __author__, __email__
|
|
14
|
+
from yellowdog_cli._version import __version__
|
|
14
15
|
|
|
15
16
|
DOCS_URL = f"https://github.com/yellowdog/yellowdog-cli/blob/v{__version__}/README.md"
|
|
16
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yellowdog-cli
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.4
|
|
4
4
|
Summary: Python-based CLI the YellowDog Platform
|
|
5
5
|
Author-email: YellowDog Limited <support@yellowdog.co>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -18,12 +18,13 @@ License-File: LICENSE
|
|
|
18
18
|
Requires-Dist: PyPAC>=0.16.4
|
|
19
19
|
Requires-Dist: dateparser
|
|
20
20
|
Requires-Dist: python-dotenv
|
|
21
|
+
Requires-Dist: jsons
|
|
21
22
|
Requires-Dist: requests
|
|
22
23
|
Requires-Dist: rclone-api
|
|
23
24
|
Requires-Dist: rich>=13.9.4
|
|
24
25
|
Requires-Dist: tabulate>=0.9.0
|
|
25
26
|
Requires-Dist: tomli>=2.4.1
|
|
26
|
-
Requires-Dist: yellowdog-sdk>=15.
|
|
27
|
+
Requires-Dist: yellowdog-sdk>=15.2.0
|
|
27
28
|
Provides-Extra: jsonnet
|
|
28
29
|
Requires-Dist: jsonnet; extra == "jsonnet"
|
|
29
30
|
Provides-Extra: cloudwizard
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|