latch 2.45.2__tar.gz → 2.45.2.dev2__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.
Files changed (186) hide show
  1. latch-2.45.2.dev2/PKG-INFO +39 -0
  2. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/type.py +7 -1
  3. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/tasks.py +43 -0
  4. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/directory.py +2 -0
  5. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/file.py +2 -0
  6. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/metadata.py +176 -20
  7. latch-2.45.2.dev2/latch.egg-info/PKG-INFO +39 -0
  8. {latch-2.45.2 → latch-2.45.2.dev2}/latch.egg-info/SOURCES.txt +4 -11
  9. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/centromere/ctx.py +45 -8
  10. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/docker_utils/__init__.py +16 -1
  11. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/main.py +46 -2
  12. latch-2.45.2.dev2/latch_cli/nextflow/dependencies.py +81 -0
  13. latch-2.45.2.dev2/latch_cli/nextflow/utils.py +27 -0
  14. latch-2.45.2.dev2/latch_cli/nextflow/workflow.py +255 -0
  15. latch-2.45.2.dev2/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  16. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
  17. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/register/register.py +66 -24
  18. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/config/utils.py +20 -6
  19. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/utils/__init__.py +1 -0
  20. {latch-2.45.2 → latch-2.45.2.dev2}/setup.py +1 -1
  21. latch-2.45.2.dev2/tests/__init__.py +0 -0
  22. latch-2.45.2/PKG-INFO +0 -13
  23. latch-2.45.2/latch.egg-info/PKG-INFO +0 -13
  24. latch-2.45.2/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  25. latch-2.45.2/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  26. latch-2.45.2/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
  27. latch-2.45.2/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
  28. latch-2.45.2/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
  29. latch-2.45.2/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
  30. latch-2.45.2/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
  31. latch-2.45.2/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
  32. latch-2.45.2/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
  33. latch-2.45.2/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
  34. latch-2.45.2/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
  35. latch-2.45.2/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
  36. {latch-2.45.2 → latch-2.45.2.dev2}/LICENSE +0 -0
  37. {latch-2.45.2 → latch-2.45.2.dev2}/MANIFEST.in +0 -0
  38. {latch-2.45.2 → latch-2.45.2.dev2}/README.md +0 -0
  39. {latch-2.45.2 → latch-2.45.2.dev2}/latch/__init__.py +0 -0
  40. {latch-2.45.2 → latch-2.45.2.dev2}/latch/account.py +0 -0
  41. {latch-2.45.2 → latch-2.45.2.dev2}/latch/executions.py +0 -0
  42. {latch-2.45.2 → latch-2.45.2.dev2}/latch/functions/__init__.py +0 -0
  43. {latch-2.45.2 → latch-2.45.2.dev2}/latch/functions/messages.py +0 -0
  44. {latch-2.45.2 → latch-2.45.2.dev2}/latch/functions/operators.py +0 -0
  45. {latch-2.45.2 → latch-2.45.2.dev2}/latch/functions/secrets.py +0 -0
  46. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/__init__.py +0 -0
  47. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/__init__.py +0 -0
  48. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/download.py +0 -0
  49. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/manager.py +0 -0
  50. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/node.py +0 -0
  51. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/progress.py +0 -0
  52. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/remote_copy.py +0 -0
  53. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/throttle.py +0 -0
  54. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/upload.py +0 -0
  55. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/_transfer/utils.py +0 -0
  56. {latch-2.45.2 → latch-2.45.2.dev2}/latch/ldata/path.py +0 -0
  57. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/__init__.py +0 -0
  58. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/project.py +0 -0
  59. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/record.py +0 -0
  60. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/table.py +0 -0
  61. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/types.py +0 -0
  62. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/upstream_types/__init__.py +0 -0
  63. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/upstream_types/types.py +0 -0
  64. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/upstream_types/values.py +0 -0
  65. {latch-2.45.2 → latch-2.45.2.dev2}/latch/registry/utils.py +0 -0
  66. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/__init__.py +0 -0
  67. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/conditional.py +0 -0
  68. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/dynamic.py +0 -0
  69. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/launch_plan.py +0 -0
  70. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/map_tasks.py +0 -0
  71. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/reference_workflow.py +0 -0
  72. {latch-2.45.2 → latch-2.45.2.dev2}/latch/resources/workflow.py +0 -0
  73. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/__init__.py +0 -0
  74. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/glob.py +0 -0
  75. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/json.py +0 -0
  76. {latch-2.45.2 → latch-2.45.2.dev2}/latch/types/utils.py +0 -0
  77. {latch-2.45.2 → latch-2.45.2.dev2}/latch/utils.py +0 -0
  78. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/__init__.py +0 -0
  79. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/deseq2.py +0 -0
  80. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/mafft.py +0 -0
  81. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/pathway.py +0 -0
  82. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/rnaseq.py +0 -0
  83. {latch-2.45.2 → latch-2.45.2.dev2}/latch/verified/trim_galore.py +0 -0
  84. {latch-2.45.2 → latch-2.45.2.dev2}/latch.egg-info/dependency_links.txt +0 -0
  85. {latch-2.45.2 → latch-2.45.2.dev2}/latch.egg-info/entry_points.txt +0 -0
  86. {latch-2.45.2 → latch-2.45.2.dev2}/latch.egg-info/requires.txt +0 -0
  87. {latch-2.45.2 → latch-2.45.2.dev2}/latch.egg-info/top_level.txt +0 -0
  88. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/__init__.py +0 -0
  89. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/auth/__init__.py +0 -0
  90. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/auth/csrf.py +0 -0
  91. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/auth/oauth2.py +0 -0
  92. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/auth/pkce.py +0 -0
  93. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/auth/utils.py +0 -0
  94. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/centromere/__init__.py +0 -0
  95. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/centromere/utils.py +0 -0
  96. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/click_utils.py +0 -0
  97. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/constants.py +0 -0
  98. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/exceptions/__init__.py +0 -0
  99. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/exceptions/cache.py +0 -0
  100. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/exceptions/errors.py +0 -0
  101. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/exceptions/handler.py +0 -0
  102. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/exceptions/traceback.py +0 -0
  103. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/menus.py +0 -0
  104. {latch-2.45.2/latch_cli/services/cp → latch-2.45.2.dev2/latch_cli/nextflow}/__init__.py +0 -0
  105. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/__init__.py +0 -0
  106. {latch-2.45.2/latch_cli/services/execute → latch-2.45.2.dev2/latch_cli/services/cp}/__init__.py +0 -0
  107. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/cp/autocomplete.py +0 -0
  108. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/cp/glob.py +0 -0
  109. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/cp/main.py +0 -0
  110. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/cp/utils.py +0 -0
  111. {latch-2.45.2/latch_cli/services/test_data → latch-2.45.2.dev2/latch_cli/services/execute}/__init__.py +0 -0
  112. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/execute/main.py +0 -0
  113. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/execute/utils.py +0 -0
  114. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/get.py +0 -0
  115. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/get_executions.py +0 -0
  116. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/get_params.py +0 -0
  117. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/__init__.py +0 -0
  118. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/.env +0 -0
  119. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
  120. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
  121. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
  122. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
  123. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
  124. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
  125. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/common/.dockerignore +0 -0
  126. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_conda/__init__.py +0 -0
  127. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_conda/conda_task.py +0 -0
  128. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_conda/environment.yaml +0 -0
  129. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_docker/__init__.py +0 -0
  130. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_docker/task.py +0 -0
  131. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
  132. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
  133. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_nfcore/task.py +0 -0
  134. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_r/__init__.py +0 -0
  135. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_r/environment.R +0 -0
  136. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_r/r_task.py +0 -0
  137. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
  138. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
  139. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
  140. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
  141. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
  142. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
  143. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
  144. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/example_snakemake/version +0 -0
  145. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/init.py +0 -0
  146. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/template/LICENSE +0 -0
  147. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/template/README.md +0 -0
  148. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/template/__init__.py +0 -0
  149. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/init/template/task.py +0 -0
  150. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/launch.py +0 -0
  151. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/local_dev.py +0 -0
  152. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/local_dev_old.py +0 -0
  153. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/login.py +0 -0
  154. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/ls.py +0 -0
  155. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/mkdir.py +0 -0
  156. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/move.py +0 -0
  157. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/preview.py +0 -0
  158. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/register/__init__.py +0 -0
  159. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/register/constants.py +0 -0
  160. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/register/utils.py +0 -0
  161. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/rm.py +0 -0
  162. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/stop_pod.py +0 -0
  163. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/sync.py +0 -0
  164. {latch-2.45.2/latch_cli/snakemake → latch-2.45.2.dev2/latch_cli/services/test_data}/__init__.py +0 -0
  165. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/test_data/ls.py +0 -0
  166. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/test_data/remove.py +0 -0
  167. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/test_data/upload.py +0 -0
  168. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/test_data/utils.py +0 -0
  169. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/services/workspace.py +0 -0
  170. {latch-2.45.2/latch_cli/snakemake/config → latch-2.45.2.dev2/latch_cli/snakemake}/__init__.py +0 -0
  171. {latch-2.45.2/latch_cli/tui → latch-2.45.2.dev2/latch_cli/snakemake/config}/__init__.py +0 -0
  172. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/config/parser.py +0 -0
  173. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/serialize.py +0 -0
  174. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/serialize_utils.py +0 -0
  175. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/single_task_snakemake.py +0 -0
  176. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/utils.py +0 -0
  177. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/snakemake/workflow.py +0 -0
  178. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/tinyrequests.py +0 -0
  179. {latch-2.45.2/tests → latch-2.45.2.dev2/latch_cli/tui}/__init__.py +0 -0
  180. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/utils/path.py +0 -0
  181. {latch-2.45.2 → latch-2.45.2.dev2}/latch_cli/workflow_config.py +0 -0
  182. {latch-2.45.2 → latch-2.45.2.dev2}/pyproject.toml +0 -0
  183. {latch-2.45.2 → latch-2.45.2.dev2}/setup.cfg +0 -0
  184. {latch-2.45.2 → latch-2.45.2.dev2}/tests/cp/__init__.py +0 -0
  185. {latch-2.45.2 → latch-2.45.2.dev2}/tests/fixtures.py +0 -0
  186. {latch-2.45.2 → latch-2.45.2.dev2}/tests/test_ls.py +0 -0
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.45.2.dev2
4
+ Summary: The Latch SDK
5
+ Author-email: kenny@latch.bio
6
+ Classifier: Programming Language :: Python :: 3.8
7
+ Classifier: Programming Language :: Python :: 3.9
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Requires-Python: >=3.8,<3.12
11
+ License-File: LICENSE
12
+ Requires-Dist: kubernetes>=24.2.0
13
+ Requires-Dist: pyjwt>=0.2.0
14
+ Requires-Dist: requests>=2.28.1
15
+ Requires-Dist: click>=8.0
16
+ Requires-Dist: docker>=7.1.0
17
+ Requires-Dist: paramiko>=3.2.0
18
+ Requires-Dist: scp>=0.14.0
19
+ Requires-Dist: boto3>=1.26.0
20
+ Requires-Dist: tqdm>=4.63.0
21
+ Requires-Dist: lytekit==0.15.8
22
+ Requires-Dist: lytekitplugins-pods==0.6.2
23
+ Requires-Dist: typing-extensions==4.7.1
24
+ Requires-Dist: apscheduler==3.9.1
25
+ Requires-Dist: gql==3.4.0
26
+ Requires-Dist: graphql-core==3.2.3
27
+ Requires-Dist: requests-toolbelt==0.10.1
28
+ Requires-Dist: latch-sdk-gql==0.0.6
29
+ Requires-Dist: latch-sdk-config==0.0.4
30
+ Requires-Dist: python-dateutil>=2.8
31
+ Requires-Dist: aioconsole==0.6.1
32
+ Requires-Dist: asyncssh==2.13.2
33
+ Requires-Dist: websockets==11.0.3
34
+ Requires-Dist: watchfiles==0.19.0
35
+ Provides-Extra: snakemake
36
+ Requires-Dist: snakemake<7.30.2,>=7.18.0; extra == "snakemake"
37
+ Requires-Dist: pulp<2.8,>=2.0; extra == "snakemake"
38
+ Provides-Extra: pandas
39
+ Requires-Dist: pandas>=2.0.0; extra == "pandas"
@@ -1,8 +1,14 @@
1
1
  from enum import Enum
2
+ from typing import Optional
2
3
 
3
4
 
4
5
  class LatchPathError(RuntimeError):
5
- def __init__(self, message: str, remote_path: str = None, acc_id: str = None):
6
+ def __init__(
7
+ self,
8
+ message: str,
9
+ remote_path: Optional[str] = None,
10
+ acc_id: Optional[str] = None,
11
+ ):
6
12
  super().__init__(message)
7
13
  self.message = message
8
14
  self.remote_path = remote_path
@@ -34,9 +34,12 @@ from flytekit import task
34
34
  from flytekitplugins.pod import Pod
35
35
  from kubernetes.client.models import (
36
36
  V1Container,
37
+ V1PersistentVolumeClaimVolumeSource,
37
38
  V1PodSpec,
38
39
  V1ResourceRequirements,
39
40
  V1Toleration,
41
+ V1Volume,
42
+ V1VolumeMount,
40
43
  )
41
44
 
42
45
  from latch_cli.constants import Units
@@ -474,3 +477,43 @@ def custom_task(
474
477
  return functools.partial(
475
478
  task, task_config=_custom_task_config(cpu, memory, storage_gib), timeout=timeout
476
479
  )
480
+
481
+
482
+ def nextflow_runtime_task(cpu: int, memory: int):
483
+ primary_container = V1Container(name="primary")
484
+ resources = V1ResourceRequirements(
485
+ requests={
486
+ "cpu": str(cpu),
487
+ "memory": f"{memory}Gi",
488
+ "ephemeral-storage": "20Gi",
489
+ },
490
+ limits={"cpu": str(cpu), "memory": f"{memory}Gi", "ephemeral-storage": "20Gi"},
491
+ )
492
+ primary_container.resources = resources
493
+ volume_mounts = [V1VolumeMount(mount_path="/nf-workdir", name="nextflow-workdir")]
494
+ primary_container.volume_mounts = volume_mounts
495
+
496
+ task_config = Pod(
497
+ annotations={
498
+ "io.kubernetes.cri-o.userns-mode": (
499
+ "private:uidmapping=0:1048576:65536;gidmapping=0:1048576:65536"
500
+ )
501
+ },
502
+ pod_spec=V1PodSpec(
503
+ runtime_class_name="sysbox-runc",
504
+ automount_service_account_token=True,
505
+ containers=[primary_container],
506
+ volumes=[
507
+ V1Volume(
508
+ name="nextflow-workdir",
509
+ persistent_volume_claim=V1PersistentVolumeClaimVolumeSource(
510
+ # this value will be injected by flytepropeller
511
+ claim_name="nextflow-pvc-placeholder"
512
+ ),
513
+ )
514
+ ],
515
+ ),
516
+ primary_container_name="primary",
517
+ )
518
+
519
+ return functools.partial(task, task_config=task_config)
@@ -114,8 +114,10 @@ class LatchDir(FlyteDirectory):
114
114
  self._path_generated = False
115
115
 
116
116
  if is_valid_url(self.path) and remote_path is None:
117
+ self._raw_remote_path = str(path)
117
118
  self._remote_directory = self.path
118
119
  else:
120
+ self._raw_remote_path = str(remote_path)
119
121
  self._remote_directory = None if remote_path is None else str(remote_path)
120
122
 
121
123
  if kwargs.get("downloader") is not None:
@@ -77,8 +77,10 @@ class LatchFile(FlyteFile):
77
77
  self._path_generated = False
78
78
 
79
79
  if is_valid_url(self.path) and remote_path is None:
80
+ self._raw_remote_path = str(path)
80
81
  self._remote_path = str(path)
81
82
  else:
83
+ self._raw_remote_path = str(remote_path)
82
84
  self._remote_path = None if remote_path is None else str(remote_path)
83
85
 
84
86
  if kwargs.get("downloader") is not None:
@@ -1,13 +1,32 @@
1
+ import csv
2
+ import functools
1
3
  import re
2
- from dataclasses import Field, asdict, dataclass, field
4
+ from dataclasses import Field, asdict, dataclass, field, fields, is_dataclass
3
5
  from enum import Enum
4
6
  from pathlib import Path
5
- from textwrap import indent
6
- from typing import Any, ClassVar, Dict, List, Optional, Protocol, Tuple, Type, Union
7
+ from textwrap import dedent, indent
8
+ from typing import (
9
+ Any,
10
+ Callable,
11
+ ClassVar,
12
+ Collection,
13
+ Dict,
14
+ Generic,
15
+ List,
16
+ Literal,
17
+ Optional,
18
+ Protocol,
19
+ Tuple,
20
+ Type,
21
+ TypeVar,
22
+ Union,
23
+ get_args,
24
+ get_origin,
25
+ )
7
26
 
8
27
  import click
9
28
  import yaml
10
- from typing_extensions import TypeAlias
29
+ from typing_extensions import Annotated, TypeAlias
11
30
 
12
31
  from latch_cli.snakemake.config.utils import validate_snakemake_type
13
32
  from latch_cli.utils import identifier_suffix_from_str
@@ -16,7 +35,6 @@ from .directory import LatchDir
16
35
  from .file import LatchFile
17
36
 
18
37
 
19
- @dataclass
20
38
  class LatchRule:
21
39
  """Class describing a rule that a parameter input must follow"""
22
40
 
@@ -388,31 +406,33 @@ class _IsDataclass(Protocol):
388
406
 
389
407
 
390
408
  ParameterType: TypeAlias = Union[
391
- Type[None],
392
- Type[int],
393
- Type[float],
394
- Type[str],
395
- Type[bool],
396
- Type[Enum],
397
- Type[_IsDataclass],
398
- Type[List["ParameterType"]],
399
- Type[LatchFile],
400
- Type[LatchDir],
409
+ None,
410
+ int,
411
+ float,
412
+ str,
413
+ bool,
414
+ LatchFile,
415
+ LatchDir,
416
+ Enum,
417
+ _IsDataclass,
418
+ Collection["ParameterType"],
401
419
  ]
402
420
 
403
421
 
422
+ T = TypeVar("T", bound=ParameterType)
423
+
424
+
404
425
  @dataclass
405
- class SnakemakeParameter(LatchParameter):
406
- type: Optional[ParameterType] = None
426
+ class SnakemakeParameter(Generic[T], LatchParameter):
427
+ type: Optional[Type[T]] = None
407
428
  """
408
429
  The python type of the parameter.
409
430
  """
410
- # todo(ayush): needs to be typed properly
411
- default: Optional[Any] = None
431
+ default: Optional[T] = None
412
432
 
413
433
 
414
434
  @dataclass
415
- class SnakemakeFileParameter(SnakemakeParameter):
435
+ class SnakemakeFileParameter(SnakemakeParameter[Union[LatchFile, LatchDir]]):
416
436
  """
417
437
  Deprecated: use `file_metadata` keyword in `SnakemakeMetadata` instead
418
438
  """
@@ -456,6 +476,108 @@ class SnakemakeFileMetadata:
456
476
  """
457
477
 
458
478
 
479
+ @dataclass
480
+ class NextflowParameter(Generic[T], LatchParameter):
481
+ type: Optional[Type[T]] = None
482
+ """
483
+ The python type of the parameter.
484
+ """
485
+ default: Optional[T] = None
486
+ """
487
+ Default value of the parameter
488
+ """
489
+
490
+ samplesheet_type: Literal["csv", "tsv", None] = None
491
+ """
492
+ The type of samplesheet to construct from the input parameter.
493
+
494
+ Only used if the provided parameter is a samplesheet (samplesheet=True)
495
+ """
496
+ samplesheet_constructor: Optional[Callable[[T], Path]] = None
497
+ """
498
+ A custom samplesheet constructor.
499
+
500
+ Should return the path of the constructed samplesheet. If samplesheet_type is also specified, this takes precedence.
501
+ Only used if the provided parameter is a samplesheet (samplesheet=True)
502
+ """
503
+
504
+ def __post_init__(self):
505
+ if not self.samplesheet or self.samplesheet_constructor is not None:
506
+ return
507
+
508
+ t = self.type
509
+ if get_origin(t) is not list or not is_dataclass(get_args(t)[0]):
510
+ click.secho(
511
+ dedent("""\
512
+ Samplesheets must be a list of dataclasses.
513
+ """),
514
+ fg="red",
515
+ )
516
+ raise click.exceptions.Exit(1)
517
+
518
+ if self.samplesheet_type is not None:
519
+ delim = "," if self.samplesheet_type == "csv" else "\t"
520
+ self.samplesheet_constructor = functools.partial(
521
+ _samplesheet_constructor, t=get_args(self.type)[0], delim=delim
522
+ )
523
+ return
524
+
525
+ click.secho(
526
+ dedent("""\
527
+ A Samplesheet constructor is required for a samplesheet parameter. Please either provide a value for
528
+ `samplesheet_type` or provide a custom callable to the `samplesheet_constructor` argument.
529
+ """),
530
+ fg="red",
531
+ )
532
+ raise click.exceptions.Exit(1)
533
+
534
+
535
+ DC = TypeVar("DC", bound=_IsDataclass)
536
+
537
+
538
+ def _samplesheet_repr(v: Any) -> str:
539
+ if v is None:
540
+ return ""
541
+ if isinstance(v, LatchFile) or isinstance(v, LatchDir):
542
+ return v.remote_path
543
+ if isinstance(v, Enum):
544
+ return getattr(v, "value")
545
+
546
+ return str(v)
547
+
548
+
549
+ def _samplesheet_constructor(samples: List[DC], t: DC, delim: str = ",") -> Path:
550
+ samplesheet = Path("samplesheet.csv")
551
+
552
+ with open(samplesheet, "w") as f:
553
+ writer = csv.DictWriter(f, [f.name for f in fields(t)], delimiter=delim)
554
+ writer.writeheader()
555
+
556
+ for sample in samples:
557
+ row_data = {
558
+ f.name: _samplesheet_repr(getattr(sample, f.name))
559
+ for f in fields(sample)
560
+ }
561
+ writer.writerow(row_data)
562
+
563
+ return samplesheet
564
+
565
+
566
+ @dataclass(frozen=True)
567
+ class NextflowRuntimeResources:
568
+ """Resources for Nextflow runtime tasks"""
569
+
570
+ cpus: Optional[int] = 4
571
+ """
572
+ Number of CPUs required for the task
573
+ """
574
+ memory: Optional[str] = 8
575
+ """
576
+ Memory required for the task (e.g. "1 GB")
577
+ """
578
+ storage_gib: Optional[int] = 100
579
+
580
+
459
581
  @dataclass
460
582
  class LatchMetadata:
461
583
  """Class for organizing workflow metadata
@@ -651,3 +773,37 @@ class SnakemakeMetadata(LatchMetadata):
651
773
 
652
774
 
653
775
  _snakemake_metadata: Optional[SnakemakeMetadata] = None
776
+
777
+
778
+ @dataclass
779
+ class NextflowMetadata(LatchMetadata):
780
+ name: Optional[str] = None
781
+ """
782
+ Name of the workflow
783
+ """
784
+ parameters: Dict[str, NextflowParameter] = field(default_factory=dict)
785
+ """
786
+ A dictionary mapping parameter names (strings) to `NextflowParameter` objects
787
+ """
788
+ runtime_resources: NextflowRuntimeResources = field(
789
+ default_factory=NextflowRuntimeResources
790
+ )
791
+ """
792
+ Resources (cpu/memory/storage) for Nextflow runtime task
793
+ """
794
+ output_dir: Optional[LatchDir] = None
795
+ """
796
+ Directory to dump Nextflow logs
797
+ """
798
+
799
+ def __post_init__(self):
800
+ if self.name is None:
801
+ self.name = f"nf_{identifier_suffix_from_str(self.display_name.lower())}"
802
+ else:
803
+ self.name = identifier_suffix_from_str(self.name)
804
+
805
+ global _nextflow_metadata
806
+ _nextflow_metadata = self
807
+
808
+
809
+ _nextflow_metadata: Optional[NextflowMetadata] = None
@@ -0,0 +1,39 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.45.2.dev2
4
+ Summary: The Latch SDK
5
+ Author-email: kenny@latch.bio
6
+ Classifier: Programming Language :: Python :: 3.8
7
+ Classifier: Programming Language :: Python :: 3.9
8
+ Classifier: Programming Language :: Python :: 3.10
9
+ Classifier: Programming Language :: Python :: 3.11
10
+ Requires-Python: >=3.8,<3.12
11
+ License-File: LICENSE
12
+ Requires-Dist: kubernetes>=24.2.0
13
+ Requires-Dist: pyjwt>=0.2.0
14
+ Requires-Dist: requests>=2.28.1
15
+ Requires-Dist: click>=8.0
16
+ Requires-Dist: docker>=7.1.0
17
+ Requires-Dist: paramiko>=3.2.0
18
+ Requires-Dist: scp>=0.14.0
19
+ Requires-Dist: boto3>=1.26.0
20
+ Requires-Dist: tqdm>=4.63.0
21
+ Requires-Dist: lytekit==0.15.8
22
+ Requires-Dist: lytekitplugins-pods==0.6.2
23
+ Requires-Dist: typing-extensions==4.7.1
24
+ Requires-Dist: apscheduler==3.9.1
25
+ Requires-Dist: gql==3.4.0
26
+ Requires-Dist: graphql-core==3.2.3
27
+ Requires-Dist: requests-toolbelt==0.10.1
28
+ Requires-Dist: latch-sdk-gql==0.0.6
29
+ Requires-Dist: latch-sdk-config==0.0.4
30
+ Requires-Dist: python-dateutil>=2.8
31
+ Requires-Dist: aioconsole==0.6.1
32
+ Requires-Dist: asyncssh==2.13.2
33
+ Requires-Dist: websockets==11.0.3
34
+ Requires-Dist: watchfiles==0.19.0
35
+ Provides-Extra: snakemake
36
+ Requires-Dist: snakemake<7.30.2,>=7.18.0; extra == "snakemake"
37
+ Requires-Dist: pulp<2.8,>=2.0; extra == "snakemake"
38
+ Provides-Extra: pandas
39
+ Requires-Dist: pandas>=2.0.0; extra == "pandas"
@@ -80,6 +80,10 @@ latch_cli/exceptions/cache.py
80
80
  latch_cli/exceptions/errors.py
81
81
  latch_cli/exceptions/handler.py
82
82
  latch_cli/exceptions/traceback.py
83
+ latch_cli/nextflow/__init__.py
84
+ latch_cli/nextflow/dependencies.py
85
+ latch_cli/nextflow/utils.py
86
+ latch_cli/nextflow/workflow.py
83
87
  latch_cli/services/__init__.py
84
88
  latch_cli/services/get.py
85
89
  latch_cli/services/get_executions.py
@@ -107,13 +111,7 @@ latch_cli/services/execute/utils.py
107
111
  latch_cli/services/init/__init__.py
108
112
  latch_cli/services/init/init.py
109
113
  latch_cli/services/init/__pycache__/__init__.cpython-310.pyc
110
- latch_cli/services/init/__pycache__/__init__.cpython-311.pyc
111
- latch_cli/services/init/__pycache__/__init__.cpython-38.pyc
112
- latch_cli/services/init/__pycache__/__init__.cpython-39.pyc
113
114
  latch_cli/services/init/__pycache__/init.cpython-310.pyc
114
- latch_cli/services/init/__pycache__/init.cpython-311.pyc
115
- latch_cli/services/init/__pycache__/init.cpython-38.pyc
116
- latch_cli/services/init/__pycache__/init.cpython-39.pyc
117
115
  latch_cli/services/init/assemble_and_sort/.env
118
116
  latch_cli/services/init/assemble_and_sort/LICENSE
119
117
  latch_cli/services/init/assemble_and_sort/README.md
@@ -121,22 +119,18 @@ latch_cli/services/init/assemble_and_sort/__init__.py
121
119
  latch_cli/services/init/assemble_and_sort/assemble.py
122
120
  latch_cli/services/init/assemble_and_sort/sort.py
123
121
  latch_cli/services/init/assemble_and_sort/system-requirements.txt
124
- latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc
125
122
  latch_cli/services/init/common/.dockerignore
126
123
  latch_cli/services/init/example_conda/__init__.py
127
124
  latch_cli/services/init/example_conda/conda_task.py
128
125
  latch_cli/services/init/example_conda/environment.yaml
129
- latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc
130
126
  latch_cli/services/init/example_docker/__init__.py
131
127
  latch_cli/services/init/example_docker/task.py
132
- latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc
133
128
  latch_cli/services/init/example_nfcore/Dockerfile
134
129
  latch_cli/services/init/example_nfcore/__init__.py
135
130
  latch_cli/services/init/example_nfcore/task.py
136
131
  latch_cli/services/init/example_r/__init__.py
137
132
  latch_cli/services/init/example_r/environment.R
138
133
  latch_cli/services/init/example_r/r_task.py
139
- latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc
140
134
  latch_cli/services/init/example_snakemake/Dockerfile
141
135
  latch_cli/services/init/example_snakemake/Snakefile
142
136
  latch_cli/services/init/example_snakemake/config.yaml
@@ -149,7 +143,6 @@ latch_cli/services/init/template/LICENSE
149
143
  latch_cli/services/init/template/README.md
150
144
  latch_cli/services/init/template/__init__.py
151
145
  latch_cli/services/init/template/task.py
152
- latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc
153
146
  latch_cli/services/register/__init__.py
154
147
  latch_cli/services/register/constants.py
155
148
  latch_cli/services/register/register.py
@@ -59,6 +59,7 @@ class _CentromereCtx:
59
59
  default_container: _Container
60
60
  workflow_type: WorkflowType
61
61
  snakefile: Optional[Path]
62
+ nf_script: Optional[Path]
62
63
 
63
64
  latch_register_api_url = config.api.workflow.register
64
65
  latch_image_api_url = config.api.workflow.upload_image
@@ -80,6 +81,7 @@ class _CentromereCtx:
80
81
  disable_auto_version: bool = False,
81
82
  remote: bool = False,
82
83
  snakefile: Optional[Path] = None,
84
+ nf_script: Optional[Path] = None,
83
85
  use_new_centromere: bool = False,
84
86
  ):
85
87
  self.use_new_centromere = use_new_centromere
@@ -93,13 +95,22 @@ class _CentromereCtx:
93
95
  self.dkr_repo = config.dkr_repo
94
96
  self.pkg_root = pkg_root.resolve()
95
97
 
96
- if snakefile is None:
97
- self.workflow_type = WorkflowType.latchbiosdk
98
- else:
98
+ if snakefile and nf_script:
99
+ raise ValueError(
100
+ "Cannot provide both a snakefile and nextflow script to the"
101
+ " register command."
102
+ )
103
+ if snakefile is not None:
99
104
  self.workflow_type = WorkflowType.snakemake
100
105
  self.snakefile = snakefile
106
+ elif nf_script is not None:
107
+ self.workflow_type = WorkflowType.nextflow
108
+ self.nf_script = nf_script
109
+ else:
110
+ self.workflow_type = WorkflowType.latchbiosdk
101
111
 
102
112
  self.container_map: Dict[str, _Container] = {}
113
+
103
114
  if self.workflow_type == WorkflowType.latchbiosdk:
104
115
  _import_flyte_objects([self.pkg_root])
105
116
  for entity in FlyteEntities.entities:
@@ -126,11 +137,7 @@ class _CentromereCtx:
126
137
  fg="red",
127
138
  )
128
139
  raise click.exceptions.Exit(1)
129
-
130
- name_path = pkg_root / latch_constants.pkg_workflow_name
131
- if name_path.exists():
132
- self.workflow_name = name_path.read_text().strip()
133
- else:
140
+ elif self.workflow_type == WorkflowType.snakemake:
134
141
  assert snakefile is not None
135
142
 
136
143
  import latch.types.metadata as metadata
@@ -142,6 +149,10 @@ class _CentromereCtx:
142
149
  )
143
150
  from ..snakemake.utils import load_snakemake_metadata
144
151
 
152
+ name_path = pkg_root / latch_constants.pkg_workflow_name
153
+ if name_path.exists():
154
+ self.workflow_name = name_path.read_text().strip()
155
+
145
156
  meta_file = load_snakemake_metadata(pkg_root)
146
157
  if meta_file is not None:
147
158
  click.echo(
@@ -235,6 +246,32 @@ class _CentromereCtx:
235
246
  # todo(kenny): support per container task and custom workflow
236
247
  # name for snakemake
237
248
  self.workflow_name = f"{metadata._snakemake_metadata.name}_jit_register"
249
+ else:
250
+ assert nf_script is not None
251
+
252
+ import latch.types.metadata as metadata
253
+
254
+ from ..services.register.utils import import_module_by_path
255
+
256
+ meta = pkg_root / "latch_metadata" / "__init__.py"
257
+ if meta.exists():
258
+ click.echo(f"Using metadata file {click.style(meta, italic=True)}")
259
+ import_module_by_path(meta)
260
+
261
+ if metadata._nextflow_metadata is None:
262
+ click.secho(
263
+ dedent("""
264
+ Failed to register Nextflow workflow.
265
+ Make sure the project root contains a `latch_metadata/__init__.py`
266
+ with a `NextflowMetadata` object defined.
267
+ """),
268
+ fg="red",
269
+ )
270
+ raise click.exceptions.Exit(1)
271
+
272
+ self.workflow_name = metadata._nextflow_metadata.name
273
+
274
+ assert self.workflow_name is not None
238
275
 
239
276
  version_file = self.pkg_root / "version"
240
277
  try:
@@ -39,7 +39,7 @@ def get_prologue(
39
39
  library_name = '"latch[snakemake]"'
40
40
  else:
41
41
  library_name = "latch"
42
- return [
42
+ directives = [
43
43
  "# DO NOT CHANGE",
44
44
  f"from {config.base_image}",
45
45
  "",
@@ -68,6 +68,11 @@ def get_prologue(
68
68
  f"run pip install {library_name}=={config.latch_version}",
69
69
  "run mkdir /opt/latch",
70
70
  ]
71
+ if wf_type == WorkflowType.nextflow:
72
+ directives.append(
73
+ "run apt-get update && apt-get install -y default-jre-headless"
74
+ )
75
+ return directives
71
76
 
72
77
 
73
78
  def get_epilogue(wf_type: WorkflowType = WorkflowType.latchbiosdk) -> List[str]:
@@ -78,8 +83,18 @@ def get_epilogue(wf_type: WorkflowType = WorkflowType.latchbiosdk) -> List[str]:
78
83
  "",
79
84
  "# Latch snakemake workflow entrypoint",
80
85
  "# DO NOT CHANGE",
86
+ "",
81
87
  "copy .latch/snakemake_jit_entrypoint.py /root/snakemake_jit_entrypoint.py",
82
88
  ]
89
+ elif wf_type == WorkflowType.nextflow:
90
+ cmds += [
91
+ "",
92
+ "# Latch nextflow workflow entrypoint",
93
+ "# DO NOT CHANGE",
94
+ "",
95
+ "copy .latch/bin/nextflow /root/nextflow",
96
+ "copy .latch/.nextflow /root/.nextflow",
97
+ ]
83
98
 
84
99
  cmds += [
85
100
  "",