latch 2.53.7__tar.gz → 2.53.7.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 (194) hide show
  1. latch-2.53.7.dev2/PKG-INFO +43 -0
  2. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/upload.py +1 -1
  3. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/type.py +1 -1
  4. latch-2.53.7.dev2/latch.egg-info/PKG-INFO +43 -0
  5. {latch-2.53.7 → latch-2.53.7.dev2}/latch.egg-info/SOURCES.txt +18 -0
  6. {latch-2.53.7 → latch-2.53.7.dev2}/latch.egg-info/requires.txt +2 -0
  7. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/main.py +13 -5
  8. latch-2.53.7.dev2/latch_cli/services/cp/download/main.py +208 -0
  9. latch-2.53.7.dev2/latch_cli/services/cp/download/worker.py +121 -0
  10. latch-2.53.7.dev2/latch_cli/services/cp/http_utils.py +91 -0
  11. latch-2.53.7.dev2/latch_cli/services/cp/main.py +101 -0
  12. latch-2.53.7.dev2/latch_cli/services/cp/upload/main.py +124 -0
  13. latch-2.53.7.dev2/latch_cli/services/cp/upload/worker.py +223 -0
  14. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/cp/utils.py +22 -4
  15. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  16. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  17. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
  18. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
  19. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
  20. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
  21. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
  22. latch-2.53.7.dev2/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
  23. latch-2.53.7.dev2/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
  24. latch-2.53.7.dev2/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
  25. latch-2.53.7.dev2/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
  26. latch-2.53.7.dev2/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
  27. latch-2.53.7.dev2/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
  28. latch-2.53.7.dev2/latch_cli/tui/__init__.py +0 -0
  29. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/utils/__init__.py +2 -1
  30. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/utils/path.py +27 -21
  31. {latch-2.53.7 → latch-2.53.7.dev2}/setup.py +4 -1
  32. latch-2.53.7.dev2/tests/__init__.py +0 -0
  33. latch-2.53.7/PKG-INFO +0 -13
  34. latch-2.53.7/latch.egg-info/PKG-INFO +0 -13
  35. latch-2.53.7/latch_cli/services/cp/main.py +0 -106
  36. latch-2.53.7/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  37. {latch-2.53.7 → latch-2.53.7.dev2}/LICENSE +0 -0
  38. {latch-2.53.7 → latch-2.53.7.dev2}/MANIFEST.in +0 -0
  39. {latch-2.53.7 → latch-2.53.7.dev2}/README.md +0 -0
  40. {latch-2.53.7 → latch-2.53.7.dev2}/latch/__init__.py +0 -0
  41. {latch-2.53.7 → latch-2.53.7.dev2}/latch/account.py +0 -0
  42. {latch-2.53.7 → latch-2.53.7.dev2}/latch/executions.py +0 -0
  43. {latch-2.53.7 → latch-2.53.7.dev2}/latch/functions/__init__.py +0 -0
  44. {latch-2.53.7 → latch-2.53.7.dev2}/latch/functions/messages.py +0 -0
  45. {latch-2.53.7 → latch-2.53.7.dev2}/latch/functions/operators.py +0 -0
  46. {latch-2.53.7 → latch-2.53.7.dev2}/latch/functions/secrets.py +0 -0
  47. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/__init__.py +0 -0
  48. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/__init__.py +0 -0
  49. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/download.py +0 -0
  50. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/manager.py +0 -0
  51. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/node.py +0 -0
  52. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/progress.py +0 -0
  53. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/remote_copy.py +0 -0
  54. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/throttle.py +0 -0
  55. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/_transfer/utils.py +0 -0
  56. {latch-2.53.7 → latch-2.53.7.dev2}/latch/ldata/path.py +0 -0
  57. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/__init__.py +0 -0
  58. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/project.py +0 -0
  59. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/record.py +0 -0
  60. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/table.py +0 -0
  61. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/types.py +0 -0
  62. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/upstream_types/__init__.py +0 -0
  63. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/upstream_types/types.py +0 -0
  64. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/upstream_types/values.py +0 -0
  65. {latch-2.53.7 → latch-2.53.7.dev2}/latch/registry/utils.py +0 -0
  66. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/__init__.py +0 -0
  67. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/conditional.py +0 -0
  68. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/dynamic.py +0 -0
  69. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/launch_plan.py +0 -0
  70. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/map_tasks.py +0 -0
  71. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/reference_workflow.py +0 -0
  72. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/tasks.py +0 -0
  73. {latch-2.53.7 → latch-2.53.7.dev2}/latch/resources/workflow.py +0 -0
  74. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/__init__.py +0 -0
  75. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/directory.py +0 -0
  76. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/file.py +0 -0
  77. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/glob.py +0 -0
  78. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/json.py +0 -0
  79. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/metadata.py +0 -0
  80. {latch-2.53.7 → latch-2.53.7.dev2}/latch/types/utils.py +0 -0
  81. {latch-2.53.7 → latch-2.53.7.dev2}/latch/utils.py +0 -0
  82. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/__init__.py +0 -0
  83. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/deseq2.py +0 -0
  84. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/mafft.py +0 -0
  85. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/pathway.py +0 -0
  86. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/rnaseq.py +0 -0
  87. {latch-2.53.7 → latch-2.53.7.dev2}/latch/verified/trim_galore.py +0 -0
  88. {latch-2.53.7 → latch-2.53.7.dev2}/latch.egg-info/dependency_links.txt +0 -0
  89. {latch-2.53.7 → latch-2.53.7.dev2}/latch.egg-info/entry_points.txt +0 -0
  90. {latch-2.53.7 → latch-2.53.7.dev2}/latch.egg-info/top_level.txt +0 -0
  91. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/__init__.py +0 -0
  92. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/auth/__init__.py +0 -0
  93. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/auth/csrf.py +0 -0
  94. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/auth/oauth2.py +0 -0
  95. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/auth/pkce.py +0 -0
  96. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/auth/utils.py +0 -0
  97. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/centromere/__init__.py +0 -0
  98. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/centromere/ctx.py +0 -0
  99. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/centromere/utils.py +0 -0
  100. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/click_utils.py +0 -0
  101. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/constants.py +0 -0
  102. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/docker_utils/__init__.py +0 -0
  103. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/exceptions/__init__.py +0 -0
  104. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/exceptions/cache.py +0 -0
  105. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/exceptions/errors.py +0 -0
  106. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/exceptions/handler.py +0 -0
  107. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/exceptions/traceback.py +0 -0
  108. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/menus.py +0 -0
  109. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/nextflow/__init__.py +0 -0
  110. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/nextflow/config.py +0 -0
  111. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/nextflow/utils.py +0 -0
  112. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/nextflow/workflow.py +0 -0
  113. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/__init__.py +0 -0
  114. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/cp/__init__.py +0 -0
  115. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/cp/autocomplete.py +0 -0
  116. {latch-2.53.7/latch_cli/services/execute → latch-2.53.7.dev2/latch_cli/services/cp/download}/__init__.py +0 -0
  117. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/cp/glob.py +0 -0
  118. {latch-2.53.7/latch_cli/services/test_data → latch-2.53.7.dev2/latch_cli/services/cp/upload}/__init__.py +0 -0
  119. {latch-2.53.7/latch_cli/snakemake → latch-2.53.7.dev2/latch_cli/services/execute}/__init__.py +0 -0
  120. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/execute/main.py +0 -0
  121. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/execute/utils.py +0 -0
  122. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/get.py +0 -0
  123. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/get_executions.py +0 -0
  124. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/get_params.py +0 -0
  125. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/__init__.py +0 -0
  126. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/.env +0 -0
  127. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
  128. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
  129. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
  130. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
  131. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
  132. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
  133. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/common/.dockerignore +0 -0
  134. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_conda/__init__.py +0 -0
  135. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_conda/conda_task.py +0 -0
  136. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_conda/environment.yaml +0 -0
  137. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_docker/__init__.py +0 -0
  138. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_docker/task.py +0 -0
  139. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
  140. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
  141. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_nfcore/task.py +0 -0
  142. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_r/__init__.py +0 -0
  143. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_r/environment.R +0 -0
  144. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_r/r_task.py +0 -0
  145. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
  146. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
  147. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
  148. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
  149. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
  150. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
  151. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
  152. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/example_snakemake/version +0 -0
  153. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/init.py +0 -0
  154. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/template/LICENSE +0 -0
  155. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/template/README.md +0 -0
  156. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/template/__init__.py +0 -0
  157. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/init/template/task.py +0 -0
  158. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/launch.py +0 -0
  159. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/local_dev.py +0 -0
  160. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/local_dev_old.py +0 -0
  161. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/login.py +0 -0
  162. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/ls.py +0 -0
  163. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/mkdir.py +0 -0
  164. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/move.py +0 -0
  165. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/preview.py +0 -0
  166. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/register/__init__.py +0 -0
  167. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/register/constants.py +0 -0
  168. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/register/register.py +0 -0
  169. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/register/utils.py +0 -0
  170. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/rm.py +0 -0
  171. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/stop_pod.py +0 -0
  172. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/sync.py +0 -0
  173. {latch-2.53.7/latch_cli/snakemake/config → latch-2.53.7.dev2/latch_cli/services/test_data}/__init__.py +0 -0
  174. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/test_data/ls.py +0 -0
  175. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/test_data/remove.py +0 -0
  176. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/test_data/upload.py +0 -0
  177. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/test_data/utils.py +0 -0
  178. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/services/workspace.py +0 -0
  179. {latch-2.53.7/latch_cli/tui → latch-2.53.7.dev2/latch_cli/snakemake}/__init__.py +0 -0
  180. {latch-2.53.7/tests → latch-2.53.7.dev2/latch_cli/snakemake/config}/__init__.py +0 -0
  181. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/config/parser.py +0 -0
  182. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/config/utils.py +0 -0
  183. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/serialize.py +0 -0
  184. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/serialize_utils.py +0 -0
  185. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/single_task_snakemake.py +0 -0
  186. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/utils.py +0 -0
  187. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/snakemake/workflow.py +0 -0
  188. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/tinyrequests.py +0 -0
  189. {latch-2.53.7 → latch-2.53.7.dev2}/latch_cli/workflow_config.py +0 -0
  190. {latch-2.53.7 → latch-2.53.7.dev2}/pyproject.toml +0 -0
  191. {latch-2.53.7 → latch-2.53.7.dev2}/setup.cfg +0 -0
  192. {latch-2.53.7 → latch-2.53.7.dev2}/tests/cp/__init__.py +0 -0
  193. {latch-2.53.7 → latch-2.53.7.dev2}/tests/fixtures.py +0 -0
  194. {latch-2.53.7 → latch-2.53.7.dev2}/tests/test_ls.py +0 -0
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.53.7.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: cryptography<43.0.0
19
+ Requires-Dist: scp>=0.14.0
20
+ Requires-Dist: boto3>=1.26.0
21
+ Requires-Dist: tqdm>=4.63.0
22
+ Requires-Dist: lytekit==0.15.12
23
+ Requires-Dist: lytekitplugins-pods==0.6.2
24
+ Requires-Dist: typing-extensions==4.7.1
25
+ Requires-Dist: apscheduler==3.9.1
26
+ Requires-Dist: gql==3.4.0
27
+ Requires-Dist: graphql-core==3.2.3
28
+ Requires-Dist: requests-toolbelt==0.10.1
29
+ Requires-Dist: latch-sdk-gql==0.0.6
30
+ Requires-Dist: latch-sdk-config==0.0.4
31
+ Requires-Dist: python-dateutil>=2.8
32
+ Requires-Dist: GitPython==3.1.40
33
+ Requires-Dist: aioconsole==0.6.1
34
+ Requires-Dist: asyncssh==2.13.2
35
+ Requires-Dist: websockets==11.0.3
36
+ Requires-Dist: watchfiles==0.19.0
37
+ Requires-Dist: uvloop==0.19.0
38
+ Requires-Dist: aiohttp==3.9.5
39
+ Provides-Extra: snakemake
40
+ Requires-Dist: snakemake<7.30.2,>=7.18.0; extra == "snakemake"
41
+ Requires-Dist: pulp<2.8,>=2.0; extra == "snakemake"
42
+ Provides-Extra: pandas
43
+ Requires-Dist: pandas>=2.0.0; extra == "pandas"
@@ -71,7 +71,7 @@ def upload(
71
71
  dest_data = node_data.data[dest]
72
72
 
73
73
  if not (dest_data.exists() or dest_data.is_direct_parent()) and not create_parents:
74
- raise LatchPathError("no such Latch file or directory", dest)
74
+ raise LatchPathError("no such Latch file or directory", dest, node_data.acc_id)
75
75
 
76
76
  dest_is_dir = dest_data.type in {
77
77
  LDataNodeType.account_root,
@@ -6,7 +6,7 @@ class LatchPathError(RuntimeError):
6
6
  def __init__(
7
7
  self,
8
8
  message: str,
9
- remote_path: Optional[str] = None,
9
+ remote_path: str,
10
10
  acc_id: Optional[str] = None,
11
11
  ):
12
12
  super().__init__(message)
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.1
2
+ Name: latch
3
+ Version: 2.53.7.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: cryptography<43.0.0
19
+ Requires-Dist: scp>=0.14.0
20
+ Requires-Dist: boto3>=1.26.0
21
+ Requires-Dist: tqdm>=4.63.0
22
+ Requires-Dist: lytekit==0.15.12
23
+ Requires-Dist: lytekitplugins-pods==0.6.2
24
+ Requires-Dist: typing-extensions==4.7.1
25
+ Requires-Dist: apscheduler==3.9.1
26
+ Requires-Dist: gql==3.4.0
27
+ Requires-Dist: graphql-core==3.2.3
28
+ Requires-Dist: requests-toolbelt==0.10.1
29
+ Requires-Dist: latch-sdk-gql==0.0.6
30
+ Requires-Dist: latch-sdk-config==0.0.4
31
+ Requires-Dist: python-dateutil>=2.8
32
+ Requires-Dist: GitPython==3.1.40
33
+ Requires-Dist: aioconsole==0.6.1
34
+ Requires-Dist: asyncssh==2.13.2
35
+ Requires-Dist: websockets==11.0.3
36
+ Requires-Dist: watchfiles==0.19.0
37
+ Requires-Dist: uvloop==0.19.0
38
+ Requires-Dist: aiohttp==3.9.5
39
+ Provides-Extra: snakemake
40
+ Requires-Dist: snakemake<7.30.2,>=7.18.0; extra == "snakemake"
41
+ Requires-Dist: pulp<2.8,>=2.0; extra == "snakemake"
42
+ Provides-Extra: pandas
43
+ Requires-Dist: pandas>=2.0.0; extra == "pandas"
@@ -103,15 +103,28 @@ latch_cli/services/workspace.py
103
103
  latch_cli/services/cp/__init__.py
104
104
  latch_cli/services/cp/autocomplete.py
105
105
  latch_cli/services/cp/glob.py
106
+ latch_cli/services/cp/http_utils.py
106
107
  latch_cli/services/cp/main.py
107
108
  latch_cli/services/cp/utils.py
109
+ latch_cli/services/cp/download/__init__.py
110
+ latch_cli/services/cp/download/main.py
111
+ latch_cli/services/cp/download/worker.py
112
+ latch_cli/services/cp/upload/__init__.py
113
+ latch_cli/services/cp/upload/main.py
114
+ latch_cli/services/cp/upload/worker.py
108
115
  latch_cli/services/execute/__init__.py
109
116
  latch_cli/services/execute/main.py
110
117
  latch_cli/services/execute/utils.py
111
118
  latch_cli/services/init/__init__.py
112
119
  latch_cli/services/init/init.py
120
+ latch_cli/services/init/__pycache__/__init__.cpython-310.pyc
113
121
  latch_cli/services/init/__pycache__/__init__.cpython-311.pyc
122
+ latch_cli/services/init/__pycache__/__init__.cpython-38.pyc
123
+ latch_cli/services/init/__pycache__/__init__.cpython-39.pyc
124
+ latch_cli/services/init/__pycache__/init.cpython-310.pyc
114
125
  latch_cli/services/init/__pycache__/init.cpython-311.pyc
126
+ latch_cli/services/init/__pycache__/init.cpython-38.pyc
127
+ latch_cli/services/init/__pycache__/init.cpython-39.pyc
115
128
  latch_cli/services/init/assemble_and_sort/.env
116
129
  latch_cli/services/init/assemble_and_sort/LICENSE
117
130
  latch_cli/services/init/assemble_and_sort/README.md
@@ -119,18 +132,22 @@ latch_cli/services/init/assemble_and_sort/__init__.py
119
132
  latch_cli/services/init/assemble_and_sort/assemble.py
120
133
  latch_cli/services/init/assemble_and_sort/sort.py
121
134
  latch_cli/services/init/assemble_and_sort/system-requirements.txt
135
+ latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc
122
136
  latch_cli/services/init/common/.dockerignore
123
137
  latch_cli/services/init/example_conda/__init__.py
124
138
  latch_cli/services/init/example_conda/conda_task.py
125
139
  latch_cli/services/init/example_conda/environment.yaml
140
+ latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc
126
141
  latch_cli/services/init/example_docker/__init__.py
127
142
  latch_cli/services/init/example_docker/task.py
143
+ latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc
128
144
  latch_cli/services/init/example_nfcore/Dockerfile
129
145
  latch_cli/services/init/example_nfcore/__init__.py
130
146
  latch_cli/services/init/example_nfcore/task.py
131
147
  latch_cli/services/init/example_r/__init__.py
132
148
  latch_cli/services/init/example_r/environment.R
133
149
  latch_cli/services/init/example_r/r_task.py
150
+ latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc
134
151
  latch_cli/services/init/example_snakemake/Dockerfile
135
152
  latch_cli/services/init/example_snakemake/Snakefile
136
153
  latch_cli/services/init/example_snakemake/config.yaml
@@ -143,6 +160,7 @@ latch_cli/services/init/template/LICENSE
143
160
  latch_cli/services/init/template/README.md
144
161
  latch_cli/services/init/template/__init__.py
145
162
  latch_cli/services/init/template/task.py
163
+ latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc
146
164
  latch_cli/services/register/__init__.py
147
165
  latch_cli/services/register/constants.py
148
166
  latch_cli/services/register/register.py
@@ -23,6 +23,8 @@ aioconsole==0.6.1
23
23
  asyncssh==2.13.2
24
24
  websockets==11.0.3
25
25
  watchfiles==0.19.0
26
+ uvloop==0.19.0
27
+ aiohttp==3.9.5
26
28
 
27
29
  [pandas]
28
30
  pandas>=2.0.0
@@ -4,15 +4,13 @@ import os
4
4
  import sys
5
5
  from pathlib import Path
6
6
  from textwrap import dedent
7
- from typing import Callable, List, Optional, Tuple, TypeVar, Union
7
+ from typing import Callable, List, Literal, Optional, Tuple, TypeVar, Union
8
8
 
9
9
  import click
10
10
  from packaging.version import parse as parse_version
11
11
  from typing_extensions import ParamSpec
12
12
 
13
13
  import latch_cli.click_utils
14
- from latch.ldata._transfer.progress import Progress as _Progress
15
- from latch_cli.click_utils import EnumChoice
16
14
  from latch_cli.exceptions.handler import CrashHandler
17
15
  from latch_cli.services.cp.autocomplete import complete as cp_complete
18
16
  from latch_cli.services.cp.autocomplete import remote_complete
@@ -693,7 +691,7 @@ LDATA COMMANDS
693
691
  @click.option(
694
692
  "--progress",
695
693
  help="Type of progress information to show while copying",
696
- type=EnumChoice(_Progress, case_sensitive=False),
694
+ type=click.Choice(["none", "total", "tasks"]),
697
695
  default="tasks",
698
696
  show_default=True,
699
697
  )
@@ -705,6 +703,14 @@ LDATA COMMANDS
705
703
  default=False,
706
704
  show_default=True,
707
705
  )
706
+ @click.option(
707
+ "--force",
708
+ "-f",
709
+ help="Don't ask to confirm when overwriting files",
710
+ is_flag=True,
711
+ default=False,
712
+ show_default=True,
713
+ )
708
714
  @click.option(
709
715
  "--no-glob",
710
716
  "-G",
@@ -727,8 +733,9 @@ LDATA COMMANDS
727
733
  def cp(
728
734
  src: List[str],
729
735
  dest: str,
730
- progress: _Progress,
736
+ progress: Literal["none", "total", "tasks"],
731
737
  verbose: bool,
738
+ force: bool,
732
739
  no_glob: bool,
733
740
  cores: Optional[int] = None,
734
741
  chunk_size_mib: Optional[int] = None,
@@ -747,6 +754,7 @@ def cp(
747
754
  src,
748
755
  dest,
749
756
  progress=progress,
757
+ force=force,
750
758
  verbose=verbose,
751
759
  expand_globs=not no_glob,
752
760
  cores=cores,
@@ -0,0 +1,208 @@
1
+ import asyncio
2
+ import queue
3
+ import shutil
4
+ import time
5
+ from pathlib import Path
6
+ from textwrap import dedent
7
+ from typing import Dict, List, Literal, Optional, TypedDict
8
+
9
+ import click
10
+ import requests
11
+ import requests.adapters
12
+ import tqdm
13
+ import uvloop
14
+
15
+ from ....utils import get_auth_header, human_readable_time, with_si_suffix
16
+ from ....utils.path import normalize_path
17
+ from ..glob import expand_pattern
18
+ from .worker import Work, run_workers
19
+
20
+ http_session = requests.Session()
21
+
22
+ _adapter = requests.adapters.HTTPAdapter(
23
+ max_retries=requests.adapters.Retry(
24
+ status_forcelist=[429, 500, 502, 503, 504],
25
+ backoff_factor=1,
26
+ allowed_methods=["GET", "PUT", "POST"],
27
+ )
28
+ )
29
+ http_session.mount("https://", _adapter)
30
+ http_session.mount("http://", _adapter)
31
+
32
+
33
+ class GetSignedUrlData(TypedDict):
34
+ url: str
35
+
36
+
37
+ class GetSignedUrlsRecursiveData(TypedDict):
38
+ urls: Dict[str, str]
39
+
40
+
41
+ def download(
42
+ srcs: List[str],
43
+ dest: Path,
44
+ progress: Literal["none", "total", "tasks"],
45
+ verbose: bool,
46
+ force: bool,
47
+ expand_globs: bool,
48
+ cores: Optional[int],
49
+ chunk_size_mib: Optional[int],
50
+ ):
51
+ if cores is None:
52
+ cores = 4
53
+ if chunk_size_mib is None:
54
+ chunk_size_mib = 16
55
+
56
+ start = time.monotonic()
57
+
58
+ if not dest.parent.exists():
59
+ click.secho(
60
+ f"Invalid copy destination {dest}. Parent directory {dest.parent} does"
61
+ " not exist.",
62
+ fg="red",
63
+ )
64
+ raise click.exceptions.Exit(1)
65
+
66
+ if len(srcs) > 1 and not (dest.exists() and dest.is_dir()):
67
+ click.secho(
68
+ f"Copy destination {dest} does not exist. Multi-source copies must write to"
69
+ " a pre-existing directory.",
70
+ fg="red",
71
+ )
72
+ raise click.exceptions.Exit(1)
73
+
74
+ from latch.ldata.path import _get_node_data
75
+ from latch.ldata.type import LDataNodeType
76
+
77
+ all_node_data = _get_node_data(*srcs)
78
+ work_queue = asyncio.Queue[Work]()
79
+ total = 0
80
+
81
+ if expand_globs:
82
+ new_srcs = []
83
+ for src in srcs:
84
+ new_srcs.extend(expand_pattern(src))
85
+
86
+ srcs = new_srcs
87
+
88
+ # todo(ayush): parallelize
89
+ for src in srcs:
90
+ node_data = all_node_data.data[src]
91
+ normalized = normalize_path(src)
92
+
93
+ can_have_children = node_data.type in {
94
+ LDataNodeType.account_root,
95
+ LDataNodeType.dir,
96
+ LDataNodeType.mount,
97
+ LDataNodeType.mount_gcp,
98
+ LDataNodeType.mount_azure,
99
+ }
100
+
101
+ if not can_have_children:
102
+ endpoint = "https://nucleus.latch.bio/ldata/get-signed-url"
103
+ else:
104
+ endpoint = "https://nucleus.latch.bio/ldata/get-signed-urls-recursive"
105
+
106
+ res = http_session.post(
107
+ endpoint,
108
+ headers={"Authorization": get_auth_header()},
109
+ json={"path": normalized},
110
+ )
111
+
112
+ json = res.json()
113
+
114
+ if not can_have_children:
115
+ gsud: GetSignedUrlData = json["data"]
116
+ total += 1
117
+
118
+ work_dest = dest
119
+ if dest.exists() and dest.is_dir():
120
+ work_dest = dest / node_data.name
121
+
122
+ if (
123
+ work_dest.exists()
124
+ and not force
125
+ and not click.confirm(
126
+ f"Copy destination path {work_dest} already exists and its contents"
127
+ " may be overwritten. Proceed?"
128
+ )
129
+ ):
130
+ continue
131
+
132
+ try:
133
+ work_dest.unlink(missing_ok=True)
134
+ work_queue.put_nowait(Work(gsud["url"], work_dest, chunk_size_mib))
135
+ except OSError:
136
+ click.secho(
137
+ f"Cannot write file to {work_dest} - directory exists.", fg="red"
138
+ )
139
+
140
+ else:
141
+ gsurd: GetSignedUrlsRecursiveData = json["data"]
142
+ total += len(gsurd["urls"])
143
+
144
+ work_dest = dest
145
+ if dest.exists() and not normalized.endswith("/"):
146
+ work_dest = dest / node_data.name
147
+
148
+ if (
149
+ work_dest.exists()
150
+ and work_dest.is_dir()
151
+ and not force
152
+ and not click.confirm(
153
+ f"Copy destination path {work_dest} already exists and its contents"
154
+ " may be overwritten. Proceed?"
155
+ )
156
+ ):
157
+ return
158
+
159
+ for rel, url in gsurd["urls"].items():
160
+ res = work_dest / rel
161
+
162
+ try:
163
+ res.parent.mkdir(exist_ok=True, parents=True)
164
+ if res.is_dir():
165
+ click.secho(
166
+ f"Cannot write file to {work_dest / rel} - directory"
167
+ " exists.",
168
+ fg="red",
169
+ )
170
+ continue
171
+
172
+ work_queue.put_nowait(Work(url, work_dest / rel, chunk_size_mib))
173
+ except (NotADirectoryError, FileExistsError):
174
+ click.secho(
175
+ f"Cannot write file to {work_dest / rel} - upstream file"
176
+ " exists.",
177
+ fg="red",
178
+ )
179
+
180
+ tbar = tqdm.tqdm(
181
+ total=total,
182
+ leave=False,
183
+ colour="green",
184
+ smoothing=0,
185
+ unit="B",
186
+ unit_scale=True,
187
+ disable=progress == "none",
188
+ )
189
+
190
+ num_workers = min(total, cores)
191
+ uvloop.install()
192
+
193
+ loop = uvloop.new_event_loop()
194
+ res = loop.run_until_complete(
195
+ run_workers(work_queue, num_workers, tbar, progress != "none", verbose)
196
+ )
197
+
198
+ total_bytes = sum(res)
199
+
200
+ tbar.clear()
201
+ total_time = time.monotonic() - start
202
+
203
+ if progress != "none":
204
+ click.echo(dedent(f"""\
205
+ {click.style("Download Complete", fg="green")}
206
+ {click.style("Time Elapsed:", fg="blue")} {human_readable_time(total_time)}
207
+ {click.style("Files Downloaded:", fg="blue")} {total} ({with_si_suffix(total_bytes)})\
208
+ """))
@@ -0,0 +1,121 @@
1
+ import asyncio
2
+ import os
3
+ import queue
4
+ import shutil
5
+ import time
6
+ from dataclasses import dataclass
7
+ from http import HTTPStatus
8
+ from pathlib import Path
9
+ from typing import Awaitable, List
10
+
11
+ import aiohttp
12
+ import tqdm
13
+ import uvloop
14
+
15
+ from latch_cli.services.cp.utils import chunked
16
+
17
+ from ....constants import Units
18
+ from ..http_utils import RetryClientSession
19
+
20
+
21
+ @dataclass
22
+ class Work:
23
+ url: str
24
+ dest: Path
25
+ chunk_size_mib: int = 5
26
+
27
+
28
+ async def download_chunk(
29
+ sess: aiohttp.ClientSession,
30
+ url: str,
31
+ fd: int,
32
+ index: int,
33
+ chunk_size: int,
34
+ pbar: tqdm.tqdm,
35
+ ):
36
+ start = index * chunk_size
37
+ end = start + chunk_size - 1
38
+
39
+ res = await sess.get(url, headers={"Range": f"bytes={start}-{end}"})
40
+ content = await res.read()
41
+ pbar.update(os.pwrite(fd, content, start))
42
+
43
+
44
+ async def worker(
45
+ work_queue: asyncio.Queue[Work],
46
+ tbar: tqdm.tqdm,
47
+ show_task_progress: bool,
48
+ print_file_on_completion: bool,
49
+ ) -> int:
50
+ pbar = tqdm.tqdm(
51
+ total=0,
52
+ leave=False,
53
+ smoothing=0,
54
+ unit="B",
55
+ unit_scale=True,
56
+ disable=not show_task_progress,
57
+ )
58
+ total_bytes = 0
59
+
60
+ try:
61
+ async with RetryClientSession(read_timeout=90, conn_timeout=10) as sess:
62
+ while True:
63
+ try:
64
+ work: Work = work_queue.get_nowait()
65
+ except asyncio.QueueEmpty:
66
+ break
67
+
68
+ pbar.reset()
69
+ pbar.desc = work.dest.name
70
+
71
+ res = await sess.get(work.url, headers={"Range": "bytes=0-0"})
72
+
73
+ # s3 throws a REQUESTED_RANGE_NOT_SATISFIABLE if the file is empty
74
+ if res.status == 416:
75
+ total_size = 0
76
+ else:
77
+ content_range = res.headers["Content-Range"]
78
+ total_size = int(content_range.replace("bytes 0-0/", ""))
79
+
80
+ assert total_size is not None
81
+
82
+ total_bytes += total_size
83
+ pbar.total = total_size
84
+
85
+ chunk_size = work.chunk_size_mib * Units.MiB
86
+
87
+ with work.dest.open("wb") as f:
88
+ coros: List[Awaitable] = []
89
+
90
+ cur = 0
91
+ while cur * chunk_size < total_size:
92
+ coros.append(
93
+ download_chunk(
94
+ sess, work.url, f.fileno(), cur, chunk_size, pbar
95
+ )
96
+ )
97
+ cur += 1
98
+
99
+ await asyncio.gather(*coros)
100
+
101
+ if print_file_on_completion:
102
+ pbar.write(str(work.dest))
103
+
104
+ tbar.update(1)
105
+
106
+ return total_bytes
107
+ finally:
108
+ pbar.clear()
109
+
110
+
111
+ async def run_workers(
112
+ work_queue: asyncio.Queue[Work],
113
+ num_workers: int,
114
+ tbar: tqdm.tqdm,
115
+ show_task_progress: bool,
116
+ print_file_on_completion: bool,
117
+ ) -> List[int]:
118
+ return await asyncio.gather(*[
119
+ worker(work_queue, tbar, show_task_progress, print_file_on_completion)
120
+ for _ in range(num_workers)
121
+ ])
@@ -0,0 +1,91 @@
1
+ import asyncio
2
+ from http import HTTPStatus
3
+ from typing import Awaitable, Callable, Dict, List, Optional
4
+
5
+ import aiohttp
6
+ import aiohttp.typedefs
7
+ from typing_extensions import ParamSpec
8
+
9
+ P = ParamSpec("P")
10
+
11
+
12
+ class RetriesExhaustedException(RuntimeError): ...
13
+
14
+
15
+ class RateLimitExceeded(RuntimeError): ...
16
+
17
+
18
+ class RetryClientSession(aiohttp.ClientSession):
19
+ def __init__(
20
+ self,
21
+ status_list: Optional[List[HTTPStatus]] = None,
22
+ retries: int = 10,
23
+ backoff: float = 0.1,
24
+ *args,
25
+ **kwargs,
26
+ ):
27
+
28
+ self.status_list = (
29
+ status_list
30
+ if status_list is not None
31
+ else [
32
+ HTTPStatus.TOO_MANY_REQUESTS, # 429
33
+ HTTPStatus.INTERNAL_SERVER_ERROR, # 500
34
+ HTTPStatus.BAD_GATEWAY, # 502
35
+ HTTPStatus.SERVICE_UNAVAILABLE, # 503
36
+ HTTPStatus.GATEWAY_TIMEOUT, # 504
37
+ ]
38
+ )
39
+
40
+ self.retries = retries
41
+ self.backoff = backoff
42
+
43
+ self.semas: Dict[aiohttp.typedefs.StrOrURL, asyncio.BoundedSemaphore] = {
44
+ "https://nucleus.latch.bio/ldata/start-upload": asyncio.BoundedSemaphore(2),
45
+ "https://nucleus.latch.bio/ldata/end-upload": asyncio.BoundedSemaphore(2),
46
+ }
47
+
48
+ super().__init__(*args, **kwargs)
49
+
50
+ async def _request(
51
+ self,
52
+ method: str,
53
+ str_or_url: aiohttp.typedefs.StrOrURL,
54
+ **kwargs,
55
+ ) -> aiohttp.ClientResponse:
56
+ sema = self.semas.get(str_or_url)
57
+
58
+ error: Optional[Exception] = None
59
+ last_res: Optional[aiohttp.ClientResponse] = None
60
+
61
+ cur = 0
62
+ while cur < self.retries:
63
+ if cur > 0:
64
+ await asyncio.sleep(max(self.backoff * 2**cur, 10))
65
+
66
+ cur += 1
67
+
68
+ try:
69
+ if sema is None:
70
+ res = await super()._request(method, str_or_url, **kwargs)
71
+ else:
72
+ async with sema:
73
+ res = await super()._request(method, str_or_url, **kwargs)
74
+
75
+ if res.status in self.status_list:
76
+ last_res = res
77
+ continue
78
+
79
+ return res
80
+ except Exception as e:
81
+ error = e
82
+ continue
83
+
84
+ if last_res is not None:
85
+ return last_res
86
+
87
+ if error is not None:
88
+ raise error
89
+
90
+ # we'll never get here but putting here anyway so the type checker is happy
91
+ raise RetriesExhaustedException