latch 2.45.2.dev2__tar.gz → 2.45.3__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 (177) hide show
  1. latch-2.45.3/PKG-INFO +13 -0
  2. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/type.py +1 -7
  3. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/tasks.py +0 -43
  4. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/directory.py +0 -2
  5. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/file.py +0 -2
  6. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/metadata.py +20 -176
  7. latch-2.45.3/latch/utils.py +179 -0
  8. latch-2.45.3/latch.egg-info/PKG-INFO +13 -0
  9. {latch-2.45.2.dev2 → latch-2.45.3}/latch.egg-info/SOURCES.txt +2 -6
  10. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/centromere/ctx.py +8 -45
  11. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/docker_utils/__init__.py +1 -16
  12. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/main.py +2 -46
  13. latch-2.45.3/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  14. latch-2.45.3/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
  15. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/register/register.py +24 -66
  16. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/config/utils.py +6 -20
  17. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/utils/__init__.py +0 -1
  18. {latch-2.45.2.dev2 → latch-2.45.3}/setup.py +1 -1
  19. latch-2.45.2.dev2/PKG-INFO +0 -39
  20. latch-2.45.2.dev2/latch/utils.py +0 -122
  21. latch-2.45.2.dev2/latch.egg-info/PKG-INFO +0 -39
  22. latch-2.45.2.dev2/latch_cli/nextflow/dependencies.py +0 -81
  23. latch-2.45.2.dev2/latch_cli/nextflow/utils.py +0 -27
  24. latch-2.45.2.dev2/latch_cli/nextflow/workflow.py +0 -255
  25. latch-2.45.2.dev2/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  26. latch-2.45.2.dev2/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
  27. latch-2.45.2.dev2/tests/__init__.py +0 -0
  28. {latch-2.45.2.dev2 → latch-2.45.3}/LICENSE +0 -0
  29. {latch-2.45.2.dev2 → latch-2.45.3}/MANIFEST.in +0 -0
  30. {latch-2.45.2.dev2 → latch-2.45.3}/README.md +0 -0
  31. {latch-2.45.2.dev2 → latch-2.45.3}/latch/__init__.py +0 -0
  32. {latch-2.45.2.dev2 → latch-2.45.3}/latch/account.py +0 -0
  33. {latch-2.45.2.dev2 → latch-2.45.3}/latch/executions.py +0 -0
  34. {latch-2.45.2.dev2 → latch-2.45.3}/latch/functions/__init__.py +0 -0
  35. {latch-2.45.2.dev2 → latch-2.45.3}/latch/functions/messages.py +0 -0
  36. {latch-2.45.2.dev2 → latch-2.45.3}/latch/functions/operators.py +0 -0
  37. {latch-2.45.2.dev2 → latch-2.45.3}/latch/functions/secrets.py +0 -0
  38. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/__init__.py +0 -0
  39. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/__init__.py +0 -0
  40. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/download.py +0 -0
  41. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/manager.py +0 -0
  42. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/node.py +0 -0
  43. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/progress.py +0 -0
  44. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/remote_copy.py +0 -0
  45. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/throttle.py +0 -0
  46. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/upload.py +0 -0
  47. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/_transfer/utils.py +0 -0
  48. {latch-2.45.2.dev2 → latch-2.45.3}/latch/ldata/path.py +0 -0
  49. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/__init__.py +0 -0
  50. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/project.py +0 -0
  51. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/record.py +0 -0
  52. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/table.py +0 -0
  53. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/types.py +0 -0
  54. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/upstream_types/__init__.py +0 -0
  55. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/upstream_types/types.py +0 -0
  56. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/upstream_types/values.py +0 -0
  57. {latch-2.45.2.dev2 → latch-2.45.3}/latch/registry/utils.py +0 -0
  58. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/__init__.py +0 -0
  59. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/conditional.py +0 -0
  60. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/dynamic.py +0 -0
  61. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/launch_plan.py +0 -0
  62. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/map_tasks.py +0 -0
  63. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/reference_workflow.py +0 -0
  64. {latch-2.45.2.dev2 → latch-2.45.3}/latch/resources/workflow.py +0 -0
  65. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/__init__.py +0 -0
  66. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/glob.py +0 -0
  67. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/json.py +0 -0
  68. {latch-2.45.2.dev2 → latch-2.45.3}/latch/types/utils.py +0 -0
  69. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/__init__.py +0 -0
  70. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/deseq2.py +0 -0
  71. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/mafft.py +0 -0
  72. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/pathway.py +0 -0
  73. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/rnaseq.py +0 -0
  74. {latch-2.45.2.dev2 → latch-2.45.3}/latch/verified/trim_galore.py +0 -0
  75. {latch-2.45.2.dev2 → latch-2.45.3}/latch.egg-info/dependency_links.txt +0 -0
  76. {latch-2.45.2.dev2 → latch-2.45.3}/latch.egg-info/entry_points.txt +0 -0
  77. {latch-2.45.2.dev2 → latch-2.45.3}/latch.egg-info/requires.txt +0 -0
  78. {latch-2.45.2.dev2 → latch-2.45.3}/latch.egg-info/top_level.txt +0 -0
  79. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/__init__.py +0 -0
  80. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/auth/__init__.py +0 -0
  81. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/auth/csrf.py +0 -0
  82. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/auth/oauth2.py +0 -0
  83. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/auth/pkce.py +0 -0
  84. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/auth/utils.py +0 -0
  85. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/centromere/__init__.py +0 -0
  86. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/centromere/utils.py +0 -0
  87. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/click_utils.py +0 -0
  88. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/constants.py +0 -0
  89. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/exceptions/__init__.py +0 -0
  90. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/exceptions/cache.py +0 -0
  91. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/exceptions/errors.py +0 -0
  92. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/exceptions/handler.py +0 -0
  93. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/exceptions/traceback.py +0 -0
  94. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/menus.py +0 -0
  95. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/__init__.py +0 -0
  96. {latch-2.45.2.dev2/latch_cli/nextflow → latch-2.45.3/latch_cli/services/cp}/__init__.py +0 -0
  97. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/cp/autocomplete.py +0 -0
  98. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/cp/glob.py +0 -0
  99. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/cp/main.py +0 -0
  100. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/cp/utils.py +0 -0
  101. {latch-2.45.2.dev2/latch_cli/services/cp → latch-2.45.3/latch_cli/services/execute}/__init__.py +0 -0
  102. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/execute/main.py +0 -0
  103. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/execute/utils.py +0 -0
  104. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/get.py +0 -0
  105. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/get_executions.py +0 -0
  106. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/get_params.py +0 -0
  107. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/__init__.py +0 -0
  108. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/.env +0 -0
  109. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
  110. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
  111. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
  112. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
  113. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
  114. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
  115. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/common/.dockerignore +0 -0
  116. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_conda/__init__.py +0 -0
  117. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_conda/conda_task.py +0 -0
  118. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_conda/environment.yaml +0 -0
  119. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_docker/__init__.py +0 -0
  120. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_docker/task.py +0 -0
  121. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
  122. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
  123. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_nfcore/task.py +0 -0
  124. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_r/__init__.py +0 -0
  125. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_r/environment.R +0 -0
  126. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_r/r_task.py +0 -0
  127. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
  128. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
  129. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
  130. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
  131. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
  132. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
  133. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
  134. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/example_snakemake/version +0 -0
  135. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/init.py +0 -0
  136. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/template/LICENSE +0 -0
  137. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/template/README.md +0 -0
  138. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/template/__init__.py +0 -0
  139. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/init/template/task.py +0 -0
  140. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/launch.py +0 -0
  141. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/local_dev.py +0 -0
  142. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/local_dev_old.py +0 -0
  143. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/login.py +0 -0
  144. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/ls.py +0 -0
  145. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/mkdir.py +0 -0
  146. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/move.py +0 -0
  147. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/preview.py +0 -0
  148. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/register/__init__.py +0 -0
  149. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/register/constants.py +0 -0
  150. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/register/utils.py +0 -0
  151. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/rm.py +0 -0
  152. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/stop_pod.py +0 -0
  153. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/sync.py +0 -0
  154. {latch-2.45.2.dev2/latch_cli/services/execute → latch-2.45.3/latch_cli/services/test_data}/__init__.py +0 -0
  155. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/test_data/ls.py +0 -0
  156. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/test_data/remove.py +0 -0
  157. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/test_data/upload.py +0 -0
  158. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/test_data/utils.py +0 -0
  159. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/services/workspace.py +0 -0
  160. {latch-2.45.2.dev2/latch_cli/services/test_data → latch-2.45.3/latch_cli/snakemake}/__init__.py +0 -0
  161. {latch-2.45.2.dev2/latch_cli/snakemake → latch-2.45.3/latch_cli/snakemake/config}/__init__.py +0 -0
  162. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/config/parser.py +0 -0
  163. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/serialize.py +0 -0
  164. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/serialize_utils.py +0 -0
  165. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/single_task_snakemake.py +0 -0
  166. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/utils.py +0 -0
  167. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/snakemake/workflow.py +0 -0
  168. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/tinyrequests.py +0 -0
  169. {latch-2.45.2.dev2/latch_cli/snakemake/config → latch-2.45.3/latch_cli/tui}/__init__.py +0 -0
  170. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/utils/path.py +0 -0
  171. {latch-2.45.2.dev2 → latch-2.45.3}/latch_cli/workflow_config.py +0 -0
  172. {latch-2.45.2.dev2 → latch-2.45.3}/pyproject.toml +0 -0
  173. {latch-2.45.2.dev2 → latch-2.45.3}/setup.cfg +0 -0
  174. {latch-2.45.2.dev2/latch_cli/tui → latch-2.45.3/tests}/__init__.py +0 -0
  175. {latch-2.45.2.dev2 → latch-2.45.3}/tests/cp/__init__.py +0 -0
  176. {latch-2.45.2.dev2 → latch-2.45.3}/tests/fixtures.py +0 -0
  177. {latch-2.45.2.dev2 → latch-2.45.3}/tests/test_ls.py +0 -0
latch-2.45.3/PKG-INFO ADDED
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.45.3
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
+ Provides-Extra: snakemake
12
+ Provides-Extra: pandas
13
+ License-File: LICENSE
@@ -1,14 +1,8 @@
1
1
  from enum import Enum
2
- from typing import Optional
3
2
 
4
3
 
5
4
  class LatchPathError(RuntimeError):
6
- def __init__(
7
- self,
8
- message: str,
9
- remote_path: Optional[str] = None,
10
- acc_id: Optional[str] = None,
11
- ):
5
+ def __init__(self, message: str, remote_path: str = None, acc_id: str = None):
12
6
  super().__init__(message)
13
7
  self.message = message
14
8
  self.remote_path = remote_path
@@ -34,12 +34,9 @@ from flytekit import task
34
34
  from flytekitplugins.pod import Pod
35
35
  from kubernetes.client.models import (
36
36
  V1Container,
37
- V1PersistentVolumeClaimVolumeSource,
38
37
  V1PodSpec,
39
38
  V1ResourceRequirements,
40
39
  V1Toleration,
41
- V1Volume,
42
- V1VolumeMount,
43
40
  )
44
41
 
45
42
  from latch_cli.constants import Units
@@ -477,43 +474,3 @@ def custom_task(
477
474
  return functools.partial(
478
475
  task, task_config=_custom_task_config(cpu, memory, storage_gib), timeout=timeout
479
476
  )
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,10 +114,8 @@ 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)
118
117
  self._remote_directory = self.path
119
118
  else:
120
- self._raw_remote_path = str(remote_path)
121
119
  self._remote_directory = None if remote_path is None else str(remote_path)
122
120
 
123
121
  if kwargs.get("downloader") is not None:
@@ -77,10 +77,8 @@ 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)
81
80
  self._remote_path = str(path)
82
81
  else:
83
- self._raw_remote_path = str(remote_path)
84
82
  self._remote_path = None if remote_path is None else str(remote_path)
85
83
 
86
84
  if kwargs.get("downloader") is not None:
@@ -1,32 +1,13 @@
1
- import csv
2
- import functools
3
1
  import re
4
- from dataclasses import Field, asdict, dataclass, field, fields, is_dataclass
2
+ from dataclasses import Field, asdict, dataclass, field
5
3
  from enum import Enum
6
4
  from pathlib import Path
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
- )
5
+ from textwrap import indent
6
+ from typing import Any, ClassVar, Dict, List, Optional, Protocol, Tuple, Type, Union
26
7
 
27
8
  import click
28
9
  import yaml
29
- from typing_extensions import Annotated, TypeAlias
10
+ from typing_extensions import TypeAlias
30
11
 
31
12
  from latch_cli.snakemake.config.utils import validate_snakemake_type
32
13
  from latch_cli.utils import identifier_suffix_from_str
@@ -35,6 +16,7 @@ from .directory import LatchDir
35
16
  from .file import LatchFile
36
17
 
37
18
 
19
+ @dataclass
38
20
  class LatchRule:
39
21
  """Class describing a rule that a parameter input must follow"""
40
22
 
@@ -406,33 +388,31 @@ class _IsDataclass(Protocol):
406
388
 
407
389
 
408
390
  ParameterType: TypeAlias = Union[
409
- None,
410
- int,
411
- float,
412
- str,
413
- bool,
414
- LatchFile,
415
- LatchDir,
416
- Enum,
417
- _IsDataclass,
418
- Collection["ParameterType"],
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],
419
401
  ]
420
402
 
421
403
 
422
- T = TypeVar("T", bound=ParameterType)
423
-
424
-
425
404
  @dataclass
426
- class SnakemakeParameter(Generic[T], LatchParameter):
427
- type: Optional[Type[T]] = None
405
+ class SnakemakeParameter(LatchParameter):
406
+ type: Optional[ParameterType] = None
428
407
  """
429
408
  The python type of the parameter.
430
409
  """
431
- default: Optional[T] = None
410
+ # todo(ayush): needs to be typed properly
411
+ default: Optional[Any] = None
432
412
 
433
413
 
434
414
  @dataclass
435
- class SnakemakeFileParameter(SnakemakeParameter[Union[LatchFile, LatchDir]]):
415
+ class SnakemakeFileParameter(SnakemakeParameter):
436
416
  """
437
417
  Deprecated: use `file_metadata` keyword in `SnakemakeMetadata` instead
438
418
  """
@@ -476,108 +456,6 @@ class SnakemakeFileMetadata:
476
456
  """
477
457
 
478
458
 
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
-
581
459
  @dataclass
582
460
  class LatchMetadata:
583
461
  """Class for organizing workflow metadata
@@ -773,37 +651,3 @@ class SnakemakeMetadata(LatchMetadata):
773
651
 
774
652
 
775
653
  _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,179 @@
1
+ import itertools
2
+ import os
3
+ from typing import Dict, TypedDict
4
+
5
+ import gql
6
+ import jwt
7
+ from latch_sdk_config.user import user_config
8
+ from latch_sdk_gql.execute import execute
9
+
10
+
11
+ def account_id_from_token(token: str) -> str:
12
+ """Exchanges a valid JWT for a Latch account ID.
13
+
14
+ Latch account IDs are needed for any user-specific request, eg. register
15
+ workflows or copy files to Latch.
16
+
17
+ Args:
18
+ token: JWT
19
+
20
+ Returns:
21
+ A Latch account ID (UUID).
22
+ """
23
+ decoded_jwt = jwt.decode(token, options={"verify_signature": False})
24
+ try:
25
+ return decoded_jwt.get("id")
26
+ except KeyError as e:
27
+ raise ValueError("Your Latch access token is malformed") from e
28
+
29
+
30
+ def retrieve_or_login() -> str:
31
+ """Returns a valid JWT to access Latch, prompting a login flow if needed.
32
+
33
+ Returns:
34
+ A JWT
35
+ """
36
+ from latch_cli.services.login import login
37
+
38
+ token = user_config.token
39
+ if token == "":
40
+ token = login()
41
+ return token
42
+
43
+
44
+ class WSInfo(TypedDict):
45
+ workspace_id: str
46
+ name: str
47
+ default: bool
48
+
49
+
50
+ def get_workspaces() -> Dict[str, WSInfo]:
51
+ """Retrieve workspaces that user can access.
52
+
53
+ Returns:
54
+ A dictionary mapping workspace IDs to workspace display names.
55
+ """
56
+ account_id = account_id_from_token(retrieve_or_login())
57
+ res = execute(
58
+ gql.gql(
59
+ """
60
+ query GetWorkspaces($accountId: BigInt!) {
61
+ userInfoByAccountId(accountId: $accountId) {
62
+ id
63
+ defaultAccount
64
+ }
65
+ teamInfoByAccountId(accountId: $accountId) {
66
+ accountId
67
+ displayName
68
+ }
69
+ teamInfos(filter: {owner: {accountId: {equalTo: $accountId}}}) {
70
+ nodes {
71
+ accountId
72
+ displayName
73
+ }
74
+ }
75
+ teamMembers(filter: {user: {accountId: {equalTo: $accountId}}}) {
76
+ nodes {
77
+ team {
78
+ accountId
79
+ displayName
80
+ }
81
+ }
82
+ }
83
+ orgInfos(filter: { ownerAccountId: { equalTo: $accountId } }) {
84
+ nodes {
85
+ teamInfosByOrgId(filter: { account: { removed: { equalTo: false } } }) {
86
+ nodes {
87
+ accountId
88
+ displayName
89
+ }
90
+ }
91
+ }
92
+ }
93
+ orgMembers(filter: { userAccountId: { equalTo: $accountId } }) {
94
+ nodes {
95
+ org {
96
+ teamInfosByOrgId(filter: { account: { removed: { equalTo: false } } }) {
97
+ nodes {
98
+ accountId
99
+ displayName
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ """
107
+ ),
108
+ {"accountId": account_id},
109
+ )
110
+
111
+ owned_teams = res["teamInfos"]["nodes"]
112
+ member_teams = [x["team"] for x in res["teamMembers"]["nodes"]]
113
+
114
+ owned_org_teams = [x["teamInfosByOrgId"]["nodes"] for x in res["orgInfos"]["nodes"]]
115
+ owned_org_teams = list(itertools.chain(*owned_org_teams))
116
+
117
+ member_org_teams = [
118
+ x["org"]["teamInfosByOrgId"]["nodes"] for x in res["orgMembers"]["nodes"]
119
+ ]
120
+ member_org_teams = list(itertools.chain(*member_org_teams))
121
+
122
+ default_account = (
123
+ res["userInfoByAccountId"]["defaultAccount"]
124
+ if res["userInfoByAccountId"] is not None
125
+ else None
126
+ )
127
+ teams = {
128
+ x["accountId"]: WSInfo(
129
+ workspace_id=x["accountId"],
130
+ name=x["displayName"],
131
+ default=x["accountId"] == default_account,
132
+ )
133
+ for x in owned_teams
134
+ + member_teams
135
+ + (
136
+ [res["teamInfoByAccountId"]]
137
+ if res["teamInfoByAccountId"] is not None
138
+ else []
139
+ )
140
+ + owned_org_teams
141
+ + member_org_teams
142
+ }
143
+
144
+ return teams
145
+
146
+
147
+ def current_workspace() -> str:
148
+ """Retrieves the current workspace ID based on the user's configuration.
149
+
150
+ If the workspace ID is not set, it retrieves the default workspace ID from the user's account.
151
+ If the default workspace ID is not set, it raises a ValueError.
152
+ """
153
+ ws = user_config.workspace_id
154
+ if ws == "":
155
+ res = execute(
156
+ gql.gql(
157
+ """
158
+ query DefaultAccountQuery {
159
+ accountInfoCurrent {
160
+ id
161
+ user {
162
+ defaultAccount
163
+ }
164
+ }
165
+ }
166
+ """
167
+ ),
168
+ )["accountInfoCurrent"]
169
+
170
+ default_ws = res["id"]
171
+
172
+ is_local = os.environ.get("FLYTE_INTERNAL_EXECUTION_ID") is None
173
+ if is_local and res["user"] is not None:
174
+ default_ws = res["user"]["defaultAccount"]
175
+
176
+ if default_ws is not None:
177
+ ws = default_ws
178
+
179
+ return ws
@@ -0,0 +1,13 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.45.3
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
+ Provides-Extra: snakemake
12
+ Provides-Extra: pandas
13
+ License-File: LICENSE
@@ -80,10 +80,6 @@ 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
87
83
  latch_cli/services/__init__.py
88
84
  latch_cli/services/get.py
89
85
  latch_cli/services/get_executions.py
@@ -110,8 +106,8 @@ latch_cli/services/execute/main.py
110
106
  latch_cli/services/execute/utils.py
111
107
  latch_cli/services/init/__init__.py
112
108
  latch_cli/services/init/init.py
113
- latch_cli/services/init/__pycache__/__init__.cpython-310.pyc
114
- latch_cli/services/init/__pycache__/init.cpython-310.pyc
109
+ latch_cli/services/init/__pycache__/__init__.cpython-311.pyc
110
+ latch_cli/services/init/__pycache__/init.cpython-311.pyc
115
111
  latch_cli/services/init/assemble_and_sort/.env
116
112
  latch_cli/services/init/assemble_and_sort/LICENSE
117
113
  latch_cli/services/init/assemble_and_sort/README.md
@@ -59,7 +59,6 @@ class _CentromereCtx:
59
59
  default_container: _Container
60
60
  workflow_type: WorkflowType
61
61
  snakefile: Optional[Path]
62
- nf_script: Optional[Path]
63
62
 
64
63
  latch_register_api_url = config.api.workflow.register
65
64
  latch_image_api_url = config.api.workflow.upload_image
@@ -81,7 +80,6 @@ class _CentromereCtx:
81
80
  disable_auto_version: bool = False,
82
81
  remote: bool = False,
83
82
  snakefile: Optional[Path] = None,
84
- nf_script: Optional[Path] = None,
85
83
  use_new_centromere: bool = False,
86
84
  ):
87
85
  self.use_new_centromere = use_new_centromere
@@ -95,22 +93,13 @@ class _CentromereCtx:
95
93
  self.dkr_repo = config.dkr_repo
96
94
  self.pkg_root = pkg_root.resolve()
97
95
 
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:
96
+ if snakefile is None:
97
+ self.workflow_type = WorkflowType.latchbiosdk
98
+ else:
104
99
  self.workflow_type = WorkflowType.snakemake
105
100
  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
111
101
 
112
102
  self.container_map: Dict[str, _Container] = {}
113
-
114
103
  if self.workflow_type == WorkflowType.latchbiosdk:
115
104
  _import_flyte_objects([self.pkg_root])
116
105
  for entity in FlyteEntities.entities:
@@ -137,7 +126,11 @@ class _CentromereCtx:
137
126
  fg="red",
138
127
  )
139
128
  raise click.exceptions.Exit(1)
140
- elif self.workflow_type == WorkflowType.snakemake:
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:
141
134
  assert snakefile is not None
142
135
 
143
136
  import latch.types.metadata as metadata
@@ -149,10 +142,6 @@ class _CentromereCtx:
149
142
  )
150
143
  from ..snakemake.utils import load_snakemake_metadata
151
144
 
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
-
156
145
  meta_file = load_snakemake_metadata(pkg_root)
157
146
  if meta_file is not None:
158
147
  click.echo(
@@ -246,32 +235,6 @@ class _CentromereCtx:
246
235
  # todo(kenny): support per container task and custom workflow
247
236
  # name for snakemake
248
237
  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
275
238
 
276
239
  version_file = self.pkg_root / "version"
277
240
  try: