toil 8.0.0__py3-none-any.whl → 8.2.0__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 (270) hide show
  1. toil/__init__.py +4 -39
  2. toil/batchSystems/abstractBatchSystem.py +1 -1
  3. toil/batchSystems/abstractGridEngineBatchSystem.py +1 -1
  4. toil/batchSystems/awsBatch.py +1 -1
  5. toil/batchSystems/cleanup_support.py +1 -1
  6. toil/batchSystems/kubernetes.py +53 -7
  7. toil/batchSystems/local_support.py +1 -1
  8. toil/batchSystems/mesos/batchSystem.py +13 -8
  9. toil/batchSystems/mesos/test/__init__.py +3 -2
  10. toil/batchSystems/options.py +1 -0
  11. toil/batchSystems/singleMachine.py +1 -1
  12. toil/batchSystems/slurm.py +229 -84
  13. toil/bus.py +5 -3
  14. toil/common.py +198 -54
  15. toil/cwl/cwltoil.py +32 -11
  16. toil/job.py +110 -86
  17. toil/jobStores/abstractJobStore.py +24 -3
  18. toil/jobStores/aws/jobStore.py +46 -10
  19. toil/jobStores/fileJobStore.py +25 -1
  20. toil/jobStores/googleJobStore.py +104 -30
  21. toil/leader.py +9 -0
  22. toil/lib/accelerators.py +3 -1
  23. toil/lib/aws/session.py +14 -3
  24. toil/lib/aws/utils.py +92 -35
  25. toil/lib/aws/utils.py.orig +504 -0
  26. toil/lib/bioio.py +1 -1
  27. toil/lib/docker.py +252 -91
  28. toil/lib/dockstore.py +387 -0
  29. toil/lib/ec2nodes.py +3 -2
  30. toil/lib/exceptions.py +5 -3
  31. toil/lib/history.py +1345 -0
  32. toil/lib/history_submission.py +695 -0
  33. toil/lib/io.py +56 -23
  34. toil/lib/misc.py +25 -1
  35. toil/lib/resources.py +2 -1
  36. toil/lib/retry.py +10 -10
  37. toil/lib/threading.py +11 -10
  38. toil/lib/{integration.py → trs.py} +95 -46
  39. toil/lib/web.py +38 -0
  40. toil/options/common.py +25 -2
  41. toil/options/cwl.py +10 -0
  42. toil/options/wdl.py +11 -0
  43. toil/provisioners/gceProvisioner.py +4 -4
  44. toil/server/api_spec/LICENSE +201 -0
  45. toil/server/api_spec/README.rst +5 -0
  46. toil/server/cli/wes_cwl_runner.py +5 -4
  47. toil/server/utils.py +2 -3
  48. toil/statsAndLogging.py +35 -1
  49. toil/test/__init__.py +275 -115
  50. toil/test/batchSystems/batchSystemTest.py +227 -205
  51. toil/test/batchSystems/test_slurm.py +199 -2
  52. toil/test/cactus/pestis.tar.gz +0 -0
  53. toil/test/conftest.py +7 -0
  54. toil/test/cwl/2.fasta +11 -0
  55. toil/test/cwl/2.fastq +12 -0
  56. toil/test/cwl/conftest.py +39 -0
  57. toil/test/cwl/cwlTest.py +1015 -780
  58. toil/test/cwl/directory/directory/file.txt +15 -0
  59. toil/test/cwl/download_directory_file.json +4 -0
  60. toil/test/cwl/download_directory_s3.json +4 -0
  61. toil/test/cwl/download_file.json +6 -0
  62. toil/test/cwl/download_http.json +6 -0
  63. toil/test/cwl/download_https.json +6 -0
  64. toil/test/cwl/download_s3.json +6 -0
  65. toil/test/cwl/download_subdirectory_file.json +5 -0
  66. toil/test/cwl/download_subdirectory_s3.json +5 -0
  67. toil/test/cwl/empty.json +1 -0
  68. toil/test/cwl/mock_mpi/fake_mpi.yml +8 -0
  69. toil/test/cwl/mock_mpi/fake_mpi_run.py +42 -0
  70. toil/test/cwl/optional-file-exists.json +6 -0
  71. toil/test/cwl/optional-file-missing.json +6 -0
  72. toil/test/cwl/optional-file.cwl +18 -0
  73. toil/test/cwl/preemptible_expression.json +1 -0
  74. toil/test/cwl/revsort-job-missing.json +6 -0
  75. toil/test/cwl/revsort-job.json +6 -0
  76. toil/test/cwl/s3_secondary_file.json +16 -0
  77. toil/test/cwl/seqtk_seq_job.json +6 -0
  78. toil/test/cwl/stream.json +6 -0
  79. toil/test/cwl/test_filename_conflict_resolution.ms/table.dat +0 -0
  80. toil/test/cwl/test_filename_conflict_resolution.ms/table.f0 +0 -0
  81. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1 +0 -0
  82. toil/test/cwl/test_filename_conflict_resolution.ms/table.f1i +0 -0
  83. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2 +0 -0
  84. toil/test/cwl/test_filename_conflict_resolution.ms/table.f2_TSM0 +0 -0
  85. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3 +0 -0
  86. toil/test/cwl/test_filename_conflict_resolution.ms/table.f3_TSM0 +0 -0
  87. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4 +0 -0
  88. toil/test/cwl/test_filename_conflict_resolution.ms/table.f4_TSM0 +0 -0
  89. toil/test/cwl/test_filename_conflict_resolution.ms/table.f5 +0 -0
  90. toil/test/cwl/test_filename_conflict_resolution.ms/table.info +0 -0
  91. toil/test/cwl/test_filename_conflict_resolution.ms/table.lock +0 -0
  92. toil/test/cwl/whale.txt +16 -0
  93. toil/test/docs/scripts/example_alwaysfail.py +38 -0
  94. toil/test/docs/scripts/example_alwaysfail_with_files.wdl +33 -0
  95. toil/test/docs/scripts/example_cachingbenchmark.py +117 -0
  96. toil/test/docs/scripts/stagingExampleFiles/in.txt +1 -0
  97. toil/test/docs/scripts/stagingExampleFiles/out.txt +2 -0
  98. toil/test/docs/scripts/tutorial_arguments.py +23 -0
  99. toil/test/docs/scripts/tutorial_debugging.patch +12 -0
  100. toil/test/docs/scripts/tutorial_debugging_hangs.wdl +126 -0
  101. toil/test/docs/scripts/tutorial_debugging_works.wdl +129 -0
  102. toil/test/docs/scripts/tutorial_docker.py +20 -0
  103. toil/test/docs/scripts/tutorial_dynamic.py +24 -0
  104. toil/test/docs/scripts/tutorial_encapsulation.py +28 -0
  105. toil/test/docs/scripts/tutorial_encapsulation2.py +29 -0
  106. toil/test/docs/scripts/tutorial_helloworld.py +15 -0
  107. toil/test/docs/scripts/tutorial_invokeworkflow.py +27 -0
  108. toil/test/docs/scripts/tutorial_invokeworkflow2.py +30 -0
  109. toil/test/docs/scripts/tutorial_jobfunctions.py +22 -0
  110. toil/test/docs/scripts/tutorial_managing.py +29 -0
  111. toil/test/docs/scripts/tutorial_managing2.py +56 -0
  112. toil/test/docs/scripts/tutorial_multiplejobs.py +25 -0
  113. toil/test/docs/scripts/tutorial_multiplejobs2.py +21 -0
  114. toil/test/docs/scripts/tutorial_multiplejobs3.py +22 -0
  115. toil/test/docs/scripts/tutorial_promises.py +25 -0
  116. toil/test/docs/scripts/tutorial_promises2.py +30 -0
  117. toil/test/docs/scripts/tutorial_quickstart.py +22 -0
  118. toil/test/docs/scripts/tutorial_requirements.py +44 -0
  119. toil/test/docs/scripts/tutorial_services.py +45 -0
  120. toil/test/docs/scripts/tutorial_staging.py +45 -0
  121. toil/test/docs/scripts/tutorial_stats.py +64 -0
  122. toil/test/lib/aws/test_iam.py +3 -1
  123. toil/test/lib/dockerTest.py +205 -122
  124. toil/test/lib/test_history.py +236 -0
  125. toil/test/lib/test_trs.py +161 -0
  126. toil/test/provisioners/aws/awsProvisionerTest.py +12 -9
  127. toil/test/provisioners/clusterTest.py +4 -4
  128. toil/test/provisioners/gceProvisionerTest.py +16 -14
  129. toil/test/sort/sort.py +4 -1
  130. toil/test/src/busTest.py +17 -17
  131. toil/test/src/deferredFunctionTest.py +145 -132
  132. toil/test/src/importExportFileTest.py +71 -63
  133. toil/test/src/jobEncapsulationTest.py +27 -28
  134. toil/test/src/jobServiceTest.py +149 -133
  135. toil/test/src/jobTest.py +219 -211
  136. toil/test/src/miscTests.py +66 -60
  137. toil/test/src/promisedRequirementTest.py +163 -169
  138. toil/test/src/regularLogTest.py +24 -24
  139. toil/test/src/resourceTest.py +82 -76
  140. toil/test/src/restartDAGTest.py +51 -47
  141. toil/test/src/resumabilityTest.py +24 -19
  142. toil/test/src/retainTempDirTest.py +60 -57
  143. toil/test/src/systemTest.py +17 -13
  144. toil/test/src/threadingTest.py +29 -32
  145. toil/test/utils/ABCWorkflowDebug/B_file.txt +1 -0
  146. toil/test/utils/ABCWorkflowDebug/debugWorkflow.py +204 -0
  147. toil/test/utils/ABCWorkflowDebug/mkFile.py +16 -0
  148. toil/test/utils/ABCWorkflowDebug/sleep.cwl +12 -0
  149. toil/test/utils/ABCWorkflowDebug/sleep.yaml +1 -0
  150. toil/test/utils/toilDebugTest.py +117 -102
  151. toil/test/utils/toilKillTest.py +54 -53
  152. toil/test/utils/utilsTest.py +303 -229
  153. toil/test/wdl/lint_error.wdl +9 -0
  154. toil/test/wdl/md5sum/empty_file.json +1 -0
  155. toil/test/wdl/md5sum/md5sum-gs.json +1 -0
  156. toil/test/wdl/md5sum/md5sum.1.0.wdl +32 -0
  157. toil/test/wdl/md5sum/md5sum.input +1 -0
  158. toil/test/wdl/md5sum/md5sum.json +1 -0
  159. toil/test/wdl/md5sum/md5sum.wdl +25 -0
  160. toil/test/wdl/miniwdl_self_test/inputs-namespaced.json +1 -0
  161. toil/test/wdl/miniwdl_self_test/inputs.json +1 -0
  162. toil/test/wdl/miniwdl_self_test/self_test.wdl +40 -0
  163. toil/test/wdl/standard_library/as_map.json +16 -0
  164. toil/test/wdl/standard_library/as_map_as_input.wdl +23 -0
  165. toil/test/wdl/standard_library/as_pairs.json +7 -0
  166. toil/test/wdl/standard_library/as_pairs_as_input.wdl +23 -0
  167. toil/test/wdl/standard_library/ceil.json +3 -0
  168. toil/test/wdl/standard_library/ceil_as_command.wdl +16 -0
  169. toil/test/wdl/standard_library/ceil_as_input.wdl +16 -0
  170. toil/test/wdl/standard_library/collect_by_key.json +1 -0
  171. toil/test/wdl/standard_library/collect_by_key_as_input.wdl +23 -0
  172. toil/test/wdl/standard_library/cross.json +11 -0
  173. toil/test/wdl/standard_library/cross_as_input.wdl +19 -0
  174. toil/test/wdl/standard_library/flatten.json +7 -0
  175. toil/test/wdl/standard_library/flatten_as_input.wdl +18 -0
  176. toil/test/wdl/standard_library/floor.json +3 -0
  177. toil/test/wdl/standard_library/floor_as_command.wdl +16 -0
  178. toil/test/wdl/standard_library/floor_as_input.wdl +16 -0
  179. toil/test/wdl/standard_library/keys.json +8 -0
  180. toil/test/wdl/standard_library/keys_as_input.wdl +24 -0
  181. toil/test/wdl/standard_library/length.json +7 -0
  182. toil/test/wdl/standard_library/length_as_input.wdl +16 -0
  183. toil/test/wdl/standard_library/length_as_input_with_map.json +7 -0
  184. toil/test/wdl/standard_library/length_as_input_with_map.wdl +17 -0
  185. toil/test/wdl/standard_library/length_invalid.json +3 -0
  186. toil/test/wdl/standard_library/range.json +3 -0
  187. toil/test/wdl/standard_library/range_0.json +3 -0
  188. toil/test/wdl/standard_library/range_as_input.wdl +17 -0
  189. toil/test/wdl/standard_library/range_invalid.json +3 -0
  190. toil/test/wdl/standard_library/read_boolean.json +3 -0
  191. toil/test/wdl/standard_library/read_boolean_as_command.wdl +17 -0
  192. toil/test/wdl/standard_library/read_float.json +3 -0
  193. toil/test/wdl/standard_library/read_float_as_command.wdl +17 -0
  194. toil/test/wdl/standard_library/read_int.json +3 -0
  195. toil/test/wdl/standard_library/read_int_as_command.wdl +17 -0
  196. toil/test/wdl/standard_library/read_json.json +3 -0
  197. toil/test/wdl/standard_library/read_json_as_output.wdl +31 -0
  198. toil/test/wdl/standard_library/read_lines.json +3 -0
  199. toil/test/wdl/standard_library/read_lines_as_output.wdl +31 -0
  200. toil/test/wdl/standard_library/read_map.json +3 -0
  201. toil/test/wdl/standard_library/read_map_as_output.wdl +31 -0
  202. toil/test/wdl/standard_library/read_string.json +3 -0
  203. toil/test/wdl/standard_library/read_string_as_command.wdl +17 -0
  204. toil/test/wdl/standard_library/read_tsv.json +3 -0
  205. toil/test/wdl/standard_library/read_tsv_as_output.wdl +31 -0
  206. toil/test/wdl/standard_library/round.json +3 -0
  207. toil/test/wdl/standard_library/round_as_command.wdl +16 -0
  208. toil/test/wdl/standard_library/round_as_input.wdl +16 -0
  209. toil/test/wdl/standard_library/size.json +3 -0
  210. toil/test/wdl/standard_library/size_as_command.wdl +17 -0
  211. toil/test/wdl/standard_library/size_as_output.wdl +36 -0
  212. toil/test/wdl/standard_library/stderr.json +3 -0
  213. toil/test/wdl/standard_library/stderr_as_output.wdl +30 -0
  214. toil/test/wdl/standard_library/stdout.json +3 -0
  215. toil/test/wdl/standard_library/stdout_as_output.wdl +30 -0
  216. toil/test/wdl/standard_library/sub.json +3 -0
  217. toil/test/wdl/standard_library/sub_as_input.wdl +17 -0
  218. toil/test/wdl/standard_library/sub_as_input_with_file.wdl +17 -0
  219. toil/test/wdl/standard_library/transpose.json +6 -0
  220. toil/test/wdl/standard_library/transpose_as_input.wdl +18 -0
  221. toil/test/wdl/standard_library/write_json.json +6 -0
  222. toil/test/wdl/standard_library/write_json_as_command.wdl +17 -0
  223. toil/test/wdl/standard_library/write_lines.json +7 -0
  224. toil/test/wdl/standard_library/write_lines_as_command.wdl +17 -0
  225. toil/test/wdl/standard_library/write_map.json +6 -0
  226. toil/test/wdl/standard_library/write_map_as_command.wdl +17 -0
  227. toil/test/wdl/standard_library/write_tsv.json +6 -0
  228. toil/test/wdl/standard_library/write_tsv_as_command.wdl +17 -0
  229. toil/test/wdl/standard_library/zip.json +12 -0
  230. toil/test/wdl/standard_library/zip_as_input.wdl +19 -0
  231. toil/test/wdl/test.csv +3 -0
  232. toil/test/wdl/test.tsv +3 -0
  233. toil/test/wdl/testfiles/croo.wdl +38 -0
  234. toil/test/wdl/testfiles/drop_files.wdl +62 -0
  235. toil/test/wdl/testfiles/drop_files_subworkflow.wdl +13 -0
  236. toil/test/wdl/testfiles/empty.txt +0 -0
  237. toil/test/wdl/testfiles/not_enough_outputs.wdl +33 -0
  238. toil/test/wdl/testfiles/random.wdl +66 -0
  239. toil/test/wdl/testfiles/string_file_coercion.json +1 -0
  240. toil/test/wdl/testfiles/string_file_coercion.wdl +35 -0
  241. toil/test/wdl/testfiles/test.json +4 -0
  242. toil/test/wdl/testfiles/test_boolean.txt +1 -0
  243. toil/test/wdl/testfiles/test_float.txt +1 -0
  244. toil/test/wdl/testfiles/test_int.txt +1 -0
  245. toil/test/wdl/testfiles/test_lines.txt +5 -0
  246. toil/test/wdl/testfiles/test_map.txt +2 -0
  247. toil/test/wdl/testfiles/test_string.txt +1 -0
  248. toil/test/wdl/testfiles/url_to_file.wdl +13 -0
  249. toil/test/wdl/testfiles/url_to_optional_file.wdl +13 -0
  250. toil/test/wdl/testfiles/vocab.json +1 -0
  251. toil/test/wdl/testfiles/vocab.wdl +66 -0
  252. toil/test/wdl/testfiles/wait.wdl +34 -0
  253. toil/test/wdl/wdl_specification/type_pair.json +23 -0
  254. toil/test/wdl/wdl_specification/type_pair_basic.wdl +36 -0
  255. toil/test/wdl/wdl_specification/type_pair_with_files.wdl +36 -0
  256. toil/test/wdl/wdl_specification/v1_spec.json +1 -0
  257. toil/test/wdl/wdl_specification/v1_spec_declaration.wdl +39 -0
  258. toil/test/wdl/wdltoil_test.py +681 -408
  259. toil/test/wdl/wdltoil_test_kubernetes.py +2 -2
  260. toil/version.py +10 -10
  261. toil/wdl/wdltoil.py +350 -123
  262. toil/worker.py +113 -33
  263. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/METADATA +13 -7
  264. toil-8.2.0.dist-info/RECORD +439 -0
  265. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/WHEEL +1 -1
  266. toil/test/lib/test_integration.py +0 -104
  267. toil-8.0.0.dist-info/RECORD +0 -253
  268. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/entry_points.txt +0 -0
  269. {toil-8.0.0.dist-info → toil-8.2.0.dist-info/licenses}/LICENSE +0 -0
  270. {toil-8.0.0.dist-info → toil-8.2.0.dist-info}/top_level.txt +0 -0
@@ -13,8 +13,8 @@
13
13
  # limitations under the License.
14
14
 
15
15
  """
16
- Contains functions for integrating Toil with external services such as
17
- Dockstore.
16
+ Contains functions for integrating Toil with GA4GH Tool Registry Service
17
+ servers, for fetching workflows.
18
18
  """
19
19
 
20
20
  import hashlib
@@ -24,35 +24,29 @@ import shutil
24
24
  import sys
25
25
  import tempfile
26
26
  import zipfile
27
- from typing import Any, Dict, List, Optional, Set, Tuple, cast
27
+ from typing import Any, Literal, Optional, Union, TypedDict, cast
28
28
 
29
29
  from urllib.parse import urlparse, unquote, quote
30
30
  import requests
31
31
 
32
32
  from toil.lib.retry import retry
33
33
  from toil.lib.io import file_digest, robust_rmtree
34
- from toil.version import baseVersion
34
+ from toil.lib.web import web_session
35
35
 
36
36
  logger = logging.getLogger(__name__)
37
37
 
38
- # We manage a Requests session at the module level in case we're supposed to be
39
- # doing cookies, and to send a sensible user agent.
40
- # We expect the Toil and Python version to not be personally identifiable even
41
- # in theory (someone might make a new Toil version first, buit there's no way
42
- # to know for sure that nobody else did the same thing).
43
- session = requests.Session()
44
- session.headers.update({"User-Agent": f"Toil {baseVersion} on Python {'.'.join([str(v) for v in sys.version_info])}"})
38
+ TRS_ROOT = "https://dockstore.org" if "TOIL_TRS_ROOT" not in os.environ else os.environ["TOIL_TRS_ROOT"]
45
39
 
46
- def is_dockstore_workflow(workflow: str) -> bool:
40
+ def is_trs_workflow(workflow: str) -> bool:
47
41
  """
48
- Returns True if a workflow string smells Dockstore-y.
42
+ Returns True if a workflow string smells like TRS.
49
43
 
50
44
  Detects Dockstore page URLs and strings that could be Dockstore TRS IDs.
51
45
  """
52
46
 
53
- return workflow.startswith("https://dockstore.org/workflows/") or workflow.startswith("#workflow/")
47
+ return workflow.startswith(f"{TRS_ROOT}/workflows/") or workflow.startswith(f"{TRS_ROOT}/my-workflows/") or workflow.startswith("#workflow/")
54
48
 
55
- def find_trs_spec(workflow: str) -> str:
49
+ def extract_trs_spec(workflow: str) -> str:
56
50
  """
57
51
  Parse a Dockstore workflow URL or TSR ID to a string that is definitely a TRS ID.
58
52
  """
@@ -63,13 +57,16 @@ def find_trs_spec(workflow: str) -> str:
63
57
  logger.debug("Workflow %s is a TRS specifier already", workflow)
64
58
  trs_spec = workflow
65
59
  else:
66
- # We need to get the right TRS ID from the Docstore URL
60
+ # We need to get the right TRS ID from the Dockstore URL
67
61
  parsed = urlparse(workflow)
68
- # TODO: We assume the Docksotre page URL structure and the TRS IDs are basically the same.
62
+ # TODO: We assume the Dockstore page URL structure and the TRS IDs are basically the same.
69
63
  page_path = unquote(parsed.path)
70
- if not page_path.startswith("/workflows/"):
64
+ if page_path.startswith("/workflows/"):
65
+ trs_spec = "#workflow/" + page_path[len("/workflows/"):]
66
+ elif page_path.startswith("/my-workflows/"):
67
+ trs_spec = "#workflow/" + page_path[len("/my-workflows/"):]
68
+ else:
71
69
  raise RuntimeError("Cannot parse Dockstore URL " + workflow)
72
- trs_spec = "#workflow/" + page_path[len("/workflows/"):]
73
70
  logger.debug("Translated %s to TRS: %s", workflow, trs_spec)
74
71
 
75
72
  return trs_spec
@@ -88,27 +85,36 @@ def parse_trs_spec(trs_spec: str) -> tuple[str, Optional[str]]:
88
85
  trs_version = None
89
86
  return trs_workflow_id, trs_version
90
87
 
88
+ def compose_trs_spec(trs_workflow_id: str, trs_version: str) -> str:
89
+ """
90
+ Compose a TRS ID from a workflow ID and version ID.
91
+ """
92
+ return f"{trs_workflow_id}:{trs_version}"
93
+
91
94
  @retry(errors=[requests.exceptions.ConnectionError])
92
- def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optional[set[str]] = None) -> str:
95
+ def find_workflow(workflow: str, supported_languages: Optional[set[str]] = None) -> tuple[str, str, str]:
93
96
  """
94
- Given a Dockstore URL or TRS identifier, get the root WDL or CWL URL for the workflow.
97
+ Given a Dockstore URL or TRS identifier, get the root WDL or CWL URL for the workflow, along with the TRS workflow ID and version.
95
98
 
96
99
  Accepts inputs like:
97
100
 
98
101
  - https://dockstore.org/workflows/github.com/dockstore-testing/md5sum-checker:master?tab=info
99
102
  - #workflow/github.com/dockstore-testing/md5sum-checker
100
103
 
101
- Assumes the input is actually one of the supported formats. See is_dockstore_workflow().
104
+ Assumes the input is actually one of the supported formats. See is_trs_workflow().
102
105
 
103
106
  TODO: Needs to handle multi-workflow files if Dockstore can.
104
107
 
108
+ :raises FileNotFoundError: if the workflow or version doesn't exist.
109
+ :raises ValueError: if the version is not specified but cannot be
110
+ automatically determined.
105
111
  """
106
112
 
107
113
  if supported_languages is not None and len(supported_languages) == 0:
108
114
  raise ValueError("Set of supported languages must be nonempty if provided.")
109
115
 
110
116
  # Get the TRS id[:version] string from what might be a Dockstore URL
111
- trs_spec = find_trs_spec(workflow)
117
+ trs_spec = extract_trs_spec(workflow)
112
118
  # Parse out workflow and possible version
113
119
  trs_workflow_id, trs_version = parse_trs_spec(trs_spec)
114
120
 
@@ -116,8 +122,14 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
116
122
 
117
123
  # Fetch the main TRS document.
118
124
  # See e.g. https://dockstore.org/api/ga4gh/trs/v2/tools/%23workflow%2Fgithub.com%2Fdockstore-testing%2Fmd5sum-checker
119
- trs_workflow_url = f"https://dockstore.org/api/ga4gh/trs/v2/tools/{quote(trs_workflow_id, safe='')}"
120
- trs_workflow_document = session.get(trs_workflow_url).json()
125
+ trs_workflow_url = f"{TRS_ROOT}/api/ga4gh/trs/v2/tools/{quote(trs_workflow_id, safe='')}"
126
+ logger.debug("Get versions: %s", trs_workflow_url)
127
+ trs_workflow_response = web_session.get(trs_workflow_url)
128
+ if trs_workflow_response.status_code in (400, 404):
129
+ # If the workflow ID isn't in Dockstore's accepted format (and also thus doesn't exist), we can get a 400
130
+ raise FileNotFoundError(f"Workflow {trs_workflow_id} does not exist.")
131
+ trs_workflow_response.raise_for_status()
132
+ trs_workflow_document = trs_workflow_response.json()
121
133
 
122
134
  # Make a map from version to version info. We will need the
123
135
  # "descriptor_type" array to find eligible languages, and the "url" field
@@ -146,12 +158,10 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
146
158
  continue
147
159
  eligible_workflow_versions.add(version_name)
148
160
 
149
- for default_version in ['main', 'master']:
150
- if trs_version is None and default_version in eligible_workflow_versions:
151
- # Fill in a version if the user didn't provide one.
152
- trs_version = default_version
153
- logger.debug("Defaulting to workflow version %s", default_version)
154
- break
161
+ # TODO: Dockstore has a concept of a "default version", but doesn't expose
162
+ # it over TRS. To avoid defaulting to something that *isn't* the Dockstore
163
+ # default version, we refuse to choose a version when there are multiple
164
+ # possibilities.
155
165
 
156
166
  if trs_version is None and len(eligible_workflow_versions) == 1:
157
167
  # If there's just one version use that.
@@ -161,26 +171,31 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
161
171
 
162
172
  # If we don't like what we found we compose a useful error message.
163
173
  problems: list[str] = []
174
+ problem_type: type[Exception] = RuntimeError
164
175
  if trs_version is None:
165
176
  problems.append(f"Workflow {workflow} does not specify a version")
177
+ problem_type = ValueError
166
178
  elif trs_version not in workflow_versions:
167
179
  problems.append(f"Workflow version {trs_version} from {workflow} does not exist")
180
+ problem_type = FileNotFoundError
168
181
  elif trs_version not in eligible_workflow_versions:
169
182
  message = f"Workflow version {trs_version} from {workflow} is not available"
170
183
  if supported_languages is not None:
171
184
  message += f" in any of: {', '.join(supported_languages)}"
172
185
  problems.append(message)
186
+ problem_type = FileNotFoundError
173
187
  if len(problems) > 0:
174
188
  if len(eligible_workflow_versions) == 0:
175
189
  message = "No versions of the workflow are available"
176
190
  if supported_languages is not None:
177
191
  message += f" in any of: {', '.join(supported_languages)}"
178
192
  problems.append(message)
193
+ problem_type = FileNotFoundError
179
194
  elif trs_version is None:
180
195
  problems.append(f"Add ':' and the name of a workflow version ({', '.join(eligible_workflow_versions)}) after '{trs_workflow_id}'")
181
196
  else:
182
197
  problems.append(f"Replace '{trs_version}' with one of ({', '.join(eligible_workflow_versions)})")
183
- raise RuntimeError("; ".join(problems))
198
+ raise problem_type("; ".join(problems))
184
199
 
185
200
  # Tell MyPy we now have a version, or we would have raised
186
201
  assert trs_version is not None
@@ -192,12 +207,35 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
192
207
  language = candidate_language
193
208
 
194
209
  logger.debug("Going to use %s version %s in %s", trs_workflow_id, trs_version, language)
195
- trs_version_url = workflow_versions[trs_version]["url"]
210
+
211
+ return trs_workflow_id, trs_version, language
212
+
213
+ @retry(errors=[requests.exceptions.ConnectionError])
214
+ def fetch_workflow(trs_workflow_id: str, trs_version: str, language: str) -> str:
215
+ """
216
+ Returns a URL or local path to a workflow's primary descriptor file.
217
+
218
+ The file will be in context with its required files so it can actually run.
219
+
220
+ :raises FileNotFoundError: if the workflow or version doesn't exist.
221
+ """
222
+
223
+ # TODO: We should probably use HATEOAS and pull this from the worflow
224
+ # document we probably already fetched but aren't passing.
225
+ trs_version_url = f"{TRS_ROOT}/api/ga4gh/trs/v2/tools/{quote(trs_workflow_id, safe='')}/versions/{quote(trs_version, safe='')}"
196
226
 
197
227
  # Fetch the list of all the files
198
228
  trs_files_url = f"{trs_version_url}/{language}/files"
199
229
  logger.debug("Workflow files URL: %s", trs_files_url)
200
- trs_files_document = session.get(trs_files_url).json()
230
+ trs_files_response = web_session.get(trs_files_url)
231
+ if trs_files_response.status_code in (204, 400, 404):
232
+ # We can get a 204 No Content response if the version doesn't exist.
233
+ # That's successful, so we need to handle it specifically. See
234
+ # <https://github.com/dockstore/dockstore/issues/6048>
235
+ # We can also get a 400 if the workflow ID is not in Dockstore's expected format (3 slash-separated segments).
236
+ raise FileNotFoundError(f"Workflow {trs_workflow_id} version {trs_version} in language {language} does not exist.")
237
+ trs_files_response.raise_for_status()
238
+ trs_files_document = trs_files_response.json()
201
239
 
202
240
  # Find the information we need to ID the primary descriptor file
203
241
  primary_descriptor_path: Optional[str] = None
@@ -210,7 +248,7 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
210
248
  primary_descriptor_hash = file_info["checksum"]["checksum"]
211
249
  break
212
250
  if primary_descriptor_path is None or primary_descriptor_hash is None or primary_descriptor_hash_algorithm is None:
213
- raise RuntimeError("Could not find a primary descriptor file for the workflow")
251
+ raise RuntimeError(f"Could not find a primary descriptor file for workflow {trs_workflow_id} version {trs_version} in language {language}")
214
252
  primary_descriptor_basename = os.path.basename(primary_descriptor_path)
215
253
 
216
254
  # Work out how to compute the hash we are looking for. See
@@ -263,7 +301,7 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
263
301
  }
264
302
  # If we don't set stream=True, we can't actually read anything from the
265
303
  # raw stream, since Requests will have done it already.
266
- with session.get(trs_zip_file_url, headers=headers, stream=True) as response:
304
+ with web_session.get(trs_zip_file_url, headers=headers, stream=True) as response:
267
305
  response_content_length = response.headers.get("Content-Length")
268
306
  logger.debug("Server reports content length: %s", response_content_length)
269
307
  shutil.copyfileobj(response.raw, zip_file)
@@ -308,27 +346,38 @@ def get_workflow_root_from_dockstore(workflow: str, supported_languages: Optiona
308
346
  logger.debug("Rejected %s because its %s hash %s is not %s", file_path, python_hash_name, file_hash, primary_descriptor_hash)
309
347
  if found_path is None:
310
348
  # We couldn't find the promised primary descriptor
311
- raise RuntimeError(f"Could not find a {primary_descriptor_basename} with {primary_descriptor_hash_algorithm} hash {primary_descriptor_hash}")
349
+ raise RuntimeError(f"Could not find a {primary_descriptor_basename} with {primary_descriptor_hash_algorithm} hash {primary_descriptor_hash} for workflow {trs_workflow_id} version {trs_version} in language {language}")
312
350
 
313
351
  return found_path
314
352
 
315
- def resolve_workflow(workflow: str, supported_languages: Optional[set[str]] = None) -> str:
353
+ def resolve_workflow(workflow: str, supported_languages: Optional[set[str]] = None) -> tuple[str, Optional[str]]:
316
354
  """
317
355
  Find the real workflow URL or filename from a command line argument.
318
356
 
319
357
  Transform a workflow URL or path that might actually be a Dockstore page
320
- URL or TRS specifier to an actual URL or path to a workflow document.
358
+ URL or TRS specifier to an actual URL or path to a workflow document, and
359
+ optional TRS specifier.
360
+
361
+ Accepts inputs like
362
+
363
+ - https://dockstore.org/workflows/github.com/dockstore-testing/md5sum-checker:master?tab=info
364
+ - #workflow/github.com/dockstore-testing/md5sum-checker
365
+ - ./local.cwl
366
+ - https://example.com/~myuser/workflow/main.cwl
367
+
368
+ :raises FileNotFoundError: if the workflow or version should be in Dockstore but doesn't seem to exist.
321
369
  """
322
370
 
323
- if is_dockstore_workflow(workflow):
324
- # Ask Dockstore where to find Dockstore-y things
325
- resolved = get_workflow_root_from_dockstore(workflow, supported_languages=supported_languages)
326
- logger.info("Resolved Dockstore workflow %s to %s", workflow, resolved)
327
- return resolved
371
+ if is_trs_workflow(workflow):
372
+ # Ask TRS host where to find TRS-looking things
373
+ trs_workflow_id, trs_version, language = find_workflow(workflow, supported_languages)
374
+ resolved = fetch_workflow(trs_workflow_id, trs_version, language)
375
+ logger.info("Resolved TRS workflow %s to %s", workflow, resolved)
376
+ return resolved, compose_trs_spec(trs_workflow_id, trs_version)
328
377
  else:
329
378
  # Pass other things through.
330
- return workflow
331
-
379
+ # TODO: Find out if they have TRS names.
380
+ return workflow, None
332
381
 
333
382
 
334
383
 
toil/lib/web.py ADDED
@@ -0,0 +1,38 @@
1
+ # Copyright (C) 2024 Regents of the University of California
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """
16
+ Contains functions for making web requests with Toil.
17
+
18
+ All web requests should go through this module, to make sure they use the right
19
+ user agent.
20
+
21
+ >>> from toil.lib.web import web_session
22
+ >>> web_session.get("https://example.com")
23
+
24
+ """
25
+
26
+ import logging
27
+ import requests
28
+ import sys
29
+
30
+ from toil.version import baseVersion
31
+
32
+ # We manage a Requests session at the module level in case we're supposed to be
33
+ # doing cookies, and to send a sensible user agent.
34
+ # We expect the Toil and Python version to not be personally identifiable even
35
+ # in theory (someone might make a new Toil version first, but there's no way
36
+ # to know for sure that nobody else did the same thing).
37
+ web_session = requests.Session()
38
+ web_session.headers.update({"User-Agent": f"Toil {baseVersion} on Python {'.'.join([str(v) for v in sys.version_info])}"})
toil/options/common.py CHANGED
@@ -362,12 +362,13 @@ def add_base_toil_options(
362
362
  action="store_true",
363
363
  help="Do not capture standard output and error from batch system jobs.",
364
364
  )
365
+ # TODO: Should this be deprecated since we always save stats now for history tracking?
365
366
  core_options.add_argument(
366
367
  "--stats",
367
368
  dest="stats",
368
369
  default=False,
369
370
  action="store_true",
370
- help="Records statistics about the toil workflow to be used by 'toil stats'.",
371
+ help="Keep statistics about the toil workflow to be used by 'toil stats'.",
371
372
  )
372
373
  clean_choices = ["always", "onError", "never", "onSuccess"]
373
374
  core_options.add_argument(
@@ -466,7 +467,8 @@ def add_base_toil_options(
466
467
  )
467
468
 
468
469
  caching = file_store_options.add_mutually_exclusive_group()
469
- caching_help = "Enable or disable caching for your workflow, specifying this overrides default from job store"
470
+ caching_help = ("Enable or disable worker level file caching for your workflow, specifying this overrides default from batch system. "
471
+ "Does not affect CWL or WDL task caching.")
470
472
  caching.add_argument(
471
473
  "--caching",
472
474
  dest="caching",
@@ -858,6 +860,14 @@ def add_base_toil_options(
858
860
  help=f"Number of times to retry a failing job before giving up and "
859
861
  f"labeling job failed. default={1}",
860
862
  )
863
+ job_options.add_argument(
864
+ "--stopOnFirstFailure",
865
+ dest="stop_on_first_failure",
866
+ type=strtobool,
867
+ default=False,
868
+ metavar="BOOL",
869
+ help="Stop the workflow at the first complete job failure.",
870
+ )
861
871
  job_options.add_argument(
862
872
  "--enableUnlimitedPreemptibleRetries",
863
873
  "--enableUnlimitedPreemptableRetries",
@@ -1102,6 +1112,19 @@ def add_base_toil_options(
1102
1112
  default=False,
1103
1113
  help="Disables the progress bar shown when standard error is a terminal.",
1104
1114
  )
1115
+ misc_options.add_argument(
1116
+ "--publishWorkflowMetrics",
1117
+ dest="publish_workflow_metrics",
1118
+ choices=["all", "current", "no"],
1119
+ default=None,
1120
+ help="Whether to publish workflow metrics reports (including unique workflow "
1121
+ "and task run IDs, job names, and version and Toil feature use information) to "
1122
+ "Dockstore when a workflow completes. Selecting \"current\" will publish metrics "
1123
+ "for the current workflow. Selecting \"all\" will also publish prior workflow "
1124
+ "runs from the Toil history database, even if they themselves were run with \"no\". "
1125
+ "Note that once published, workflow metrics CANNOT be deleted or un-published; they "
1126
+ "will stay published forever!"
1127
+ )
1105
1128
 
1106
1129
  # Debug options
1107
1130
  debug_options = parser.add_argument_group(
toil/options/cwl.py CHANGED
@@ -419,3 +419,13 @@ def add_cwl_options(parser: ArgumentParser, suppress: bool = True) -> None:
419
419
  type=str,
420
420
  help=suppress_help or "Specify a cloud bucket endpoint for output files.",
421
421
  )
422
+ parser.add_argument(
423
+ "--cachedir",
424
+ type=str,
425
+ help=suppress_help
426
+ or "Directory to cache intermediate workflow outputs to avoid "
427
+ "recomputing steps. Can be very helpful in the development and "
428
+ "troubleshooting of CWL documents. This automatically bypasses the file store."
429
+ " Not to be confused with --caching.",
430
+ dest="cachedir"
431
+ )
toil/options/wdl.py CHANGED
@@ -86,3 +86,14 @@ def add_wdl_options(parser: ArgumentParser, suppress: bool = True) -> None:
86
86
  default=None,
87
87
  help=suppress_help or "Keep and return all call outputs as workflow outputs"
88
88
  )
89
+
90
+ strict_arguments = ["--wdlStrict"] + (
91
+ ["--strict"] if not suppress else []
92
+ )
93
+ parser.add_argument(
94
+ *strict_arguments,
95
+ dest="strict",
96
+ type=strtobool,
97
+ default=False,
98
+ help=suppress_help or "Exit runner if workflow has any lint warnings"
99
+ )
@@ -19,7 +19,6 @@ import time
19
19
  import uuid
20
20
  from typing import Optional
21
21
 
22
- import requests
23
22
  from libcloud.compute.drivers.gce import GCEFailedNode
24
23
  from libcloud.compute.providers import get_driver
25
24
  from libcloud.compute.types import Provider
@@ -27,6 +26,7 @@ from libcloud.compute.types import Provider
27
26
  from toil.jobStores.googleJobStore import GoogleJobStore
28
27
  from toil.lib.compatibility import compat_bytes_recursive
29
28
  from toil.lib.conversions import human2bytes
29
+ from toil.lib.web import web_session
30
30
  from toil.provisioners import NoSuchClusterException
31
31
  from toil.provisioners.abstractProvisioner import AbstractProvisioner, Shape
32
32
  from toil.provisioners.node import Node
@@ -83,11 +83,11 @@ class GCEProvisioner(AbstractProvisioner):
83
83
  """
84
84
  metadata_server = "http://metadata/computeMetadata/v1/instance/"
85
85
  metadata_flavor = {"Metadata-Flavor": "Google"}
86
- zone = requests.get(metadata_server + "zone", headers=metadata_flavor).text
86
+ zone = web_session.get(metadata_server + "zone", headers=metadata_flavor).text
87
87
  self._zone = zone.split("/")[-1]
88
88
 
89
89
  project_metadata_server = "http://metadata/computeMetadata/v1/project/"
90
- self._projectId = requests.get(
90
+ self._projectId = web_session.get(
91
91
  project_metadata_server + "project-id", headers=metadata_flavor
92
92
  ).text
93
93
 
@@ -95,7 +95,7 @@ class GCEProvisioner(AbstractProvisioner):
95
95
  self._googleJson = ""
96
96
  self._clientEmail = ""
97
97
 
98
- self._tags = requests.get(
98
+ self._tags = web_session.get(
99
99
  metadata_server + "description", headers=metadata_flavor
100
100
  ).text
101
101
  tags = json.loads(self._tags)
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "{}"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2019 Global Alliance for Genomics and Health
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
@@ -0,0 +1,5 @@
1
+ This directory contains the OpenAPI/Swagger specification for the following GA4GH APIs:
2
+
3
+ - Workflow Execution Service (WES) API
4
+
5
+ Source: https://github.com/ga4gh/workflow-execution-service-schemas