latch 2.41.3.dev0__tar.gz → 2.41.3.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 (184) hide show
  1. {latch-2.41.3.dev0/latch.egg-info → latch-2.41.3.dev2}/PKG-INFO +1 -1
  2. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/tasks.py +40 -36
  3. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/directory.py +2 -0
  4. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/metadata.py +31 -0
  5. {latch-2.41.3.dev0 → latch-2.41.3.dev2/latch.egg-info}/PKG-INFO +1 -1
  6. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch.egg-info/SOURCES.txt +4 -11
  7. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/centromere/ctx.py +1 -1
  8. latch-2.41.3.dev2/latch_cli/nextflow/dependencies.py +91 -0
  9. latch-2.41.3.dev2/latch_cli/nextflow/utils.py +27 -0
  10. latch-2.41.3.dev2/latch_cli/nextflow/workflow.py +222 -0
  11. latch-2.41.3.dev2/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  12. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
  13. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/config/utils.py +20 -6
  14. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/setup.py +1 -1
  15. latch-2.41.3.dev2/tests/__init__.py +0 -0
  16. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  17. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  18. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
  19. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
  20. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
  21. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
  22. latch-2.41.3.dev0/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
  23. latch-2.41.3.dev0/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
  24. latch-2.41.3.dev0/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
  25. latch-2.41.3.dev0/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
  26. latch-2.41.3.dev0/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
  27. latch-2.41.3.dev0/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
  28. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/LICENSE +0 -0
  29. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/MANIFEST.in +0 -0
  30. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/README.md +0 -0
  31. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/__init__.py +0 -0
  32. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/account.py +0 -0
  33. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/executions.py +0 -0
  34. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/functions/__init__.py +0 -0
  35. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/functions/messages.py +0 -0
  36. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/functions/operators.py +0 -0
  37. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/functions/secrets.py +0 -0
  38. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/__init__.py +0 -0
  39. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/__init__.py +0 -0
  40. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/download.py +0 -0
  41. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/manager.py +0 -0
  42. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/node.py +0 -0
  43. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/progress.py +0 -0
  44. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/remote_copy.py +0 -0
  45. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/throttle.py +0 -0
  46. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/upload.py +0 -0
  47. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/_transfer/utils.py +0 -0
  48. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/path.py +0 -0
  49. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/ldata/type.py +0 -0
  50. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/__init__.py +0 -0
  51. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/project.py +0 -0
  52. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/record.py +0 -0
  53. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/table.py +0 -0
  54. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/types.py +0 -0
  55. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/upstream_types/__init__.py +0 -0
  56. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/upstream_types/types.py +0 -0
  57. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/upstream_types/values.py +0 -0
  58. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/registry/utils.py +0 -0
  59. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/__init__.py +0 -0
  60. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/conditional.py +0 -0
  61. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/dynamic.py +0 -0
  62. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/launch_plan.py +0 -0
  63. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/map_tasks.py +0 -0
  64. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/reference_workflow.py +0 -0
  65. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/resources/workflow.py +0 -0
  66. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/__init__.py +0 -0
  67. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/file.py +0 -0
  68. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/glob.py +0 -0
  69. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/json.py +0 -0
  70. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/types/utils.py +0 -0
  71. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/utils.py +0 -0
  72. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/__init__.py +0 -0
  73. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/deseq2.py +0 -0
  74. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/mafft.py +0 -0
  75. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/pathway.py +0 -0
  76. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/rnaseq.py +0 -0
  77. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch/verified/trim_galore.py +0 -0
  78. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch.egg-info/dependency_links.txt +0 -0
  79. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch.egg-info/entry_points.txt +0 -0
  80. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch.egg-info/requires.txt +0 -0
  81. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch.egg-info/top_level.txt +0 -0
  82. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/__init__.py +0 -0
  83. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/auth/__init__.py +0 -0
  84. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/auth/csrf.py +0 -0
  85. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/auth/oauth2.py +0 -0
  86. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/auth/pkce.py +0 -0
  87. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/auth/utils.py +0 -0
  88. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/centromere/__init__.py +0 -0
  89. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/centromere/utils.py +0 -0
  90. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/click_utils.py +0 -0
  91. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/constants.py +0 -0
  92. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/docker_utils/__init__.py +0 -0
  93. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/exceptions/__init__.py +0 -0
  94. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/exceptions/cache.py +0 -0
  95. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/exceptions/errors.py +0 -0
  96. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/exceptions/handler.py +0 -0
  97. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/exceptions/traceback.py +0 -0
  98. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/main.py +0 -0
  99. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/menus.py +0 -0
  100. {latch-2.41.3.dev0/latch_cli/services/cp → latch-2.41.3.dev2/latch_cli/nextflow}/__init__.py +0 -0
  101. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/__init__.py +0 -0
  102. {latch-2.41.3.dev0/latch_cli/services/execute → latch-2.41.3.dev2/latch_cli/services/cp}/__init__.py +0 -0
  103. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/cp/autocomplete.py +0 -0
  104. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/cp/glob.py +0 -0
  105. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/cp/main.py +0 -0
  106. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/cp/utils.py +0 -0
  107. {latch-2.41.3.dev0/latch_cli/services/test_data → latch-2.41.3.dev2/latch_cli/services/execute}/__init__.py +0 -0
  108. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/execute/main.py +0 -0
  109. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/execute/utils.py +0 -0
  110. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/get.py +0 -0
  111. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/get_executions.py +0 -0
  112. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/get_params.py +0 -0
  113. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/__init__.py +0 -0
  114. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/.env +0 -0
  115. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
  116. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
  117. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
  118. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
  119. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
  120. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
  121. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/common/.dockerignore +0 -0
  122. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_conda/__init__.py +0 -0
  123. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_conda/conda_task.py +0 -0
  124. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_conda/environment.yaml +0 -0
  125. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_docker/__init__.py +0 -0
  126. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_docker/task.py +0 -0
  127. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
  128. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
  129. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_nfcore/task.py +0 -0
  130. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_r/__init__.py +0 -0
  131. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_r/environment.R +0 -0
  132. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_r/r_task.py +0 -0
  133. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
  134. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
  135. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
  136. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
  137. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
  138. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
  139. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
  140. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/example_snakemake/version +0 -0
  141. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/init.py +0 -0
  142. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/template/LICENSE +0 -0
  143. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/template/README.md +0 -0
  144. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/template/__init__.py +0 -0
  145. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/init/template/task.py +0 -0
  146. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/launch.py +0 -0
  147. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/local_dev.py +0 -0
  148. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/local_dev_old.py +0 -0
  149. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/login.py +0 -0
  150. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/ls.py +0 -0
  151. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/mkdir.py +0 -0
  152. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/move.py +0 -0
  153. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/preview.py +0 -0
  154. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/register/__init__.py +0 -0
  155. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/register/constants.py +0 -0
  156. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/register/register.py +0 -0
  157. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/register/utils.py +0 -0
  158. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/rm.py +0 -0
  159. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/stop_pod.py +0 -0
  160. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/sync.py +0 -0
  161. {latch-2.41.3.dev0/latch_cli/snakemake → latch-2.41.3.dev2/latch_cli/services/test_data}/__init__.py +0 -0
  162. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/test_data/ls.py +0 -0
  163. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/test_data/remove.py +0 -0
  164. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/test_data/upload.py +0 -0
  165. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/test_data/utils.py +0 -0
  166. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/services/workspace.py +0 -0
  167. {latch-2.41.3.dev0/latch_cli/snakemake/config → latch-2.41.3.dev2/latch_cli/snakemake}/__init__.py +0 -0
  168. {latch-2.41.3.dev0/latch_cli/tui → latch-2.41.3.dev2/latch_cli/snakemake/config}/__init__.py +0 -0
  169. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/config/parser.py +0 -0
  170. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/serialize.py +0 -0
  171. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/serialize_utils.py +0 -0
  172. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/single_task_snakemake.py +0 -0
  173. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/utils.py +0 -0
  174. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/snakemake/workflow.py +0 -0
  175. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/tinyrequests.py +0 -0
  176. {latch-2.41.3.dev0/tests → latch-2.41.3.dev2/latch_cli/tui}/__init__.py +0 -0
  177. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/utils/__init__.py +0 -0
  178. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/utils/path.py +0 -0
  179. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/latch_cli/workflow_config.py +0 -0
  180. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/pyproject.toml +0 -0
  181. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/setup.cfg +0 -0
  182. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/tests/cp/__init__.py +0 -0
  183. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/tests/fixtures.py +0 -0
  184. {latch-2.41.3.dev0 → latch-2.41.3.dev2}/tests/test_ls.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: latch
3
- Version: 2.41.3.dev0
3
+ Version: 2.41.3.dev2
4
4
  Summary: The Latch SDK
5
5
  Author-email: kenny@latch.bio
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -182,40 +182,6 @@ def _get_small_pod() -> Pod:
182
182
  )
183
183
 
184
184
 
185
- def _get_nextflow_runtime_pod() -> Pod:
186
- primary_container = V1Container(name="primary")
187
- resources = V1ResourceRequirements(
188
- requests={"cpu": "2", "memory": "4Gi", "ephemeral-storage": "100Gi"},
189
- limits={"cpu": "2", "memory": "4Gi", "ephemeral-storage": "100Gi"},
190
- )
191
- primary_container.resources = resources
192
- volume_mounts = [V1VolumeMount(mount_path="/nf-workdir", name="nextflow-workdir")]
193
- primary_container.volume_mounts = volume_mounts
194
-
195
- return Pod(
196
- annotations={
197
- "io.kubernetes.cri-o.userns-mode": (
198
- "private:uidmapping=0:1048576:65536;gidmapping=0:1048576:65536"
199
- )
200
- },
201
- pod_spec=V1PodSpec(
202
- runtime_class_name="sysbox-runc",
203
- service_account_name="rahul-test",
204
- containers=[primary_container],
205
- volumes=[
206
- V1Volume(
207
- name="nextflow-workdir",
208
- persistent_volume_claim=V1PersistentVolumeClaimVolumeSource(
209
- # this value will be injected by flytepropeller
210
- claim_name="nextflow-pvc-placeholder"
211
- ),
212
- )
213
- ],
214
- ),
215
- primary_container_name="primary",
216
- )
217
-
218
-
219
185
  large_gpu_task = functools.partial(task, task_config=_get_large_gpu_pod())
220
186
  """This task will get scheduled on a large GPU-enabled node.
221
187
 
@@ -351,8 +317,6 @@ small_task = functools.partial(task, task_config=_get_small_pod())
351
317
  - False
352
318
  """
353
319
 
354
- nextflow_runtime_task = functools.partial(task, task_config=_get_nextflow_runtime_pod())
355
-
356
320
 
357
321
  def custom_memory_optimized_task(cpu: int, memory: int):
358
322
  """Returns a custom task configuration requesting
@@ -530,3 +494,43 @@ def custom_task(
530
494
  return functools.partial(
531
495
  task, task_config=_custom_task_config(cpu, memory, storage_gib), timeout=timeout
532
496
  )
497
+
498
+
499
+ def nextflow_runtime_task(cpu: int, memory: int):
500
+ primary_container = V1Container(name="primary")
501
+ resources = V1ResourceRequirements(
502
+ requests={
503
+ "cpu": str(cpu),
504
+ "memory": f"{memory}Gi",
505
+ "ephemeral-storage": "20Gi",
506
+ },
507
+ limits={"cpu": str(cpu), "memory": f"{memory}Gi", "ephemeral-storage": "20Gi"},
508
+ )
509
+ primary_container.resources = resources
510
+ volume_mounts = [V1VolumeMount(mount_path="/nf-workdir", name="nextflow-workdir")]
511
+ primary_container.volume_mounts = volume_mounts
512
+
513
+ task_config = Pod(
514
+ annotations={
515
+ "io.kubernetes.cri-o.userns-mode": (
516
+ "private:uidmapping=0:1048576:65536;gidmapping=0:1048576:65536"
517
+ )
518
+ },
519
+ pod_spec=V1PodSpec(
520
+ runtime_class_name="sysbox-runc",
521
+ service_account_name="rahul-test",
522
+ containers=[primary_container],
523
+ volumes=[
524
+ V1Volume(
525
+ name="nextflow-workdir",
526
+ persistent_volume_claim=V1PersistentVolumeClaimVolumeSource(
527
+ # this value will be injected by flytepropeller
528
+ claim_name="nextflow-pvc-placeholder"
529
+ ),
530
+ )
531
+ ],
532
+ ),
533
+ primary_container_name="primary",
534
+ )
535
+
536
+ 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 = path
117
118
  self._remote_directory = self.path
118
119
  else:
120
+ self._raw_remote_path = 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:
@@ -483,6 +483,21 @@ class NextflowParameter(Generic[T], LatchParameter):
483
483
  self.type = Annotated[self.type, "samplesheet"]
484
484
 
485
485
 
486
+ @dataclass(frozen=True)
487
+ class NextflowRuntimeResources:
488
+ """Resources for Nextflow runtime tasks"""
489
+
490
+ cpus: Optional[int] = 4
491
+ """
492
+ Number of CPUs required for the task
493
+ """
494
+ memory: Optional[str] = 8
495
+ """
496
+ Memory required for the task (e.g. "1 GB")
497
+ """
498
+ storage_gib: Optional[int] = 100
499
+
500
+
486
501
  @dataclass
487
502
  class LatchMetadata:
488
503
  """Class for organizing workflow metadata
@@ -683,7 +698,23 @@ _snakemake_metadata: Optional[SnakemakeMetadata] = None
683
698
  @dataclass
684
699
  class NextflowMetadata(LatchMetadata):
685
700
  name: Optional[str] = None
701
+ """
702
+ Name of the workflow
703
+ """
686
704
  parameters: Dict[str, NextflowParameter] = field(default_factory=dict)
705
+ """
706
+ A dictionary mapping parameter names (strings) to `NextflowParameter` objects
707
+ """
708
+ runtime_resources: NextflowRuntimeResources = field(
709
+ default_factory=NextflowRuntimeResources
710
+ )
711
+ """
712
+ Resources (cpu/memory/storage) for Nextflow runtime task
713
+ """
714
+ output_dir: Optional[LatchDir] = None
715
+ """
716
+ Directory to dump Nextflow logs
717
+ """
687
718
 
688
719
  def __post_init__(self):
689
720
  if self.name is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: latch
3
- Version: 2.41.3.dev0
3
+ Version: 2.41.3.dev2
4
4
  Summary: The Latch SDK
5
5
  Author-email: kenny@latch.bio
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -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
@@ -258,7 +258,7 @@ class _CentromereCtx:
258
258
  click.secho(
259
259
  dedent("""
260
260
  Failed to register Nextflow workflow.
261
- Make sure the project root contains a `wf/__init__.py`
261
+ Make sure the project root contains a `latch_metadata/__init__.py`
262
262
  with a `NextflowMetadata` object defined.
263
263
  """),
264
264
  fg="red",
@@ -0,0 +1,91 @@
1
+ import shutil
2
+ import subprocess
3
+ from concurrent.futures import ProcessPoolExecutor
4
+ from ctypes import c_int
5
+ from multiprocessing.managers import SyncManager
6
+ from pathlib import Path
7
+ from urllib.parse import urljoin
8
+
9
+ import boto3
10
+ import click
11
+
12
+ from latch_cli import tinyrequests
13
+ from latch_cli.utils import dedent
14
+
15
+
16
+ def _do_download(
17
+ url: str,
18
+ output_path: Path,
19
+ total_count: int,
20
+ counter,
21
+ lock,
22
+ ): # todo(ayush): figure out the right type annotation for counter/lock
23
+ res = tinyrequests.get(url)
24
+ output_path.parent.mkdir(parents=True, exist_ok=True)
25
+ output_path.write_bytes(res.content)
26
+
27
+ with lock:
28
+ counter.value += 1
29
+ progress_str = f"{counter.value}/{total_count}"
30
+
31
+ click.echo("\x1b[0K", nl=False)
32
+ click.secho(progress_str, dim=True, italic=True, nl=False)
33
+ click.echo(f"\x1b[{len(progress_str)}D", nl=False)
34
+
35
+
36
+ def download_nf_jars(pkg_root: Path):
37
+ s3_resource = boto3.resource("s3")
38
+ bucket = s3_resource.Bucket("latch-public")
39
+
40
+ objects = list(bucket.objects.filter(Prefix=".nextflow/"))
41
+
42
+ click.secho(" Downloading Nextflow binaries: \x1b[?25l", italic=True, nl=False)
43
+
44
+ with SyncManager() as man:
45
+ counter = man.Value(c_int, 0)
46
+ lock = man.Lock()
47
+ with ProcessPoolExecutor() as exec:
48
+ for obj in objects:
49
+ url = urljoin(
50
+ "https://latch-public.s3.us-west-2.amazonaws.com/", obj.key
51
+ )
52
+ obj_path = pkg_root / ".latch" / obj.key
53
+
54
+ exec.submit(_do_download, url, obj_path, len(objects), counter, lock)
55
+
56
+ click.echo("\x1b[0K", nl=False)
57
+ click.secho("Done. \x1b[?25h", italic=True)
58
+
59
+
60
+ def ensure_nf_dependencies(pkg_root: Path, *, force_redownload: bool = False):
61
+ try:
62
+ subprocess.run(["java", "--version"], check=True, capture_output=True)
63
+ except (subprocess.CalledProcessError, FileNotFoundError) as e:
64
+ click.secho(
65
+ dedent("""\
66
+ Java is not installed - this is a requirement to run Nextflow.
67
+ Please install Java and try again.
68
+ """),
69
+ fg="red",
70
+ )
71
+ raise click.exceptions.Exit(1) from e
72
+
73
+ nf_executable = pkg_root / ".latch" / "bin" / "nextflow"
74
+ nf_jars = pkg_root / ".latch" / ".nextflow"
75
+
76
+ if force_redownload:
77
+ nf_executable.unlink(missing_ok=True)
78
+ if nf_jars.exists():
79
+ shutil.rmtree(nf_jars)
80
+
81
+ if not nf_executable.exists():
82
+ res = tinyrequests.get(
83
+ "https://latch-public.s3.us-west-2.amazonaws.com/nextflow"
84
+ )
85
+ nf_executable.parent.mkdir(parents=True, exist_ok=True)
86
+
87
+ nf_executable.write_bytes(res.content)
88
+ nf_executable.chmod(0o700)
89
+
90
+ if not nf_jars.exists():
91
+ download_nf_jars(pkg_root)
@@ -0,0 +1,27 @@
1
+ import os
2
+ from typing import Optional
3
+
4
+ import gql
5
+ from latch_sdk_gql.execute import execute
6
+
7
+
8
+ def _get_execution_name() -> Optional[str]:
9
+ token = os.environ.get("FLYTE_INTERNAL_EXECUTION_ID", None)
10
+ if token is None:
11
+ return None
12
+
13
+ res = execute(
14
+ gql.gql("""
15
+ query executionCreatorsByToken($token: String!) {
16
+ executionCreatorByToken(token: $token) {
17
+ flytedbId
18
+ info {
19
+ displayName
20
+ }
21
+ }
22
+ }
23
+ """),
24
+ {"token": token},
25
+ )["executionCreatorByToken"]
26
+
27
+ return res["info"]["displayName"]
@@ -0,0 +1,222 @@
1
+ import re
2
+ from dataclasses import fields, is_dataclass
3
+ from enum import Enum
4
+ from pathlib import Path
5
+ from typing import Any, List, Optional, Tuple
6
+
7
+ import click
8
+
9
+ import latch.types.metadata as metadata
10
+ from latch.types.directory import LatchDir
11
+ from latch.types.file import LatchFile
12
+ from latch_cli.snakemake.config.utils import get_preamble, type_repr
13
+ from latch_cli.snakemake.utils import reindent
14
+ from latch_cli.utils import identifier_from_str, urljoins
15
+
16
+ template = """\
17
+ from dataclasses import dataclass
18
+ from enum import Enum
19
+ import os
20
+ import subprocess
21
+ import requests
22
+ import shutil
23
+ from pathlib import Path
24
+ import typing
25
+ import typing_extensions
26
+
27
+ from latch.resources.workflow import workflow
28
+ from latch.resources.tasks import nextflow_runtime_task, custom_task
29
+ from latch.types.file import LatchFile
30
+ from latch.types.directory import LatchDir, LatchOutputDir
31
+ from latch.ldata.path import LPath
32
+ from latch_cli.nextflow.workflow import get_flag
33
+ from latch_cli.nextflow.utils import _get_execution_name
34
+ from latch_cli.utils import urljoins
35
+ from latch.types import metadata
36
+ from flytekit.core.annotation import FlyteAnnotation
37
+
38
+ import latch_metadata
39
+
40
+
41
+ @custom_task(cpu=0.25, memory=0.5, storage_gib=1)
42
+ def initialize() -> str:
43
+ token = os.environ.get("FLYTE_INTERNAL_EXECUTION_ID")
44
+ if token is None:
45
+ raise RuntimeError("failed to get execution token")
46
+
47
+ print("Provisioning shared storage volume...")
48
+ headers = {{"Authorization": f"Latch-Execution-Token {{token}}"}}
49
+ resp = requests.post(
50
+ "http://nf-dispatcher-service.flyte.svc.cluster.local/provision-storage",
51
+ headers=headers,
52
+ json={{
53
+ "storage_gib": {storage_gib},
54
+ }}
55
+ )
56
+ resp.raise_for_status()
57
+ return resp.json()["name"]
58
+
59
+
60
+ {preambles}
61
+
62
+
63
+ @nextflow_runtime_task(cpu={cpu}, memory={memory})
64
+ def nextflow_runtime(pvc_name: str, {param_signature}) -> None:
65
+ try:
66
+ shared_dir = Path("/nf-workdir")
67
+
68
+ shutil.copytree(
69
+ Path("/root"),
70
+ shared_dir,
71
+ ignore=lambda src, names: ["latch", ".latch"],
72
+ ignore_dangling_symlinks=True,
73
+ dirs_exist_ok=True,
74
+ )
75
+
76
+ env = {{
77
+ **os.environ,
78
+ "NXF_HOME": "/root/.nextflow",
79
+ "K8_STORAGE_CLAIM_NAME": pvc_name,
80
+ }}
81
+ subprocess.run(
82
+ [
83
+ "/root/.latch/bin/nextflow",
84
+ "run",
85
+ str(shared_dir / "{nf_script}"),
86
+ "-work-dir",
87
+ str(shared_dir),
88
+ "-profile",
89
+ "{execution_profile}",
90
+ {params_to_flags}
91
+ ],
92
+ env=env,
93
+ check=True,
94
+ )
95
+ except subprocess.CalledProcessError:
96
+ remote = LPath(urljoins("{remote_output_dir}", _get_execution_name(), "nextflow.log"))
97
+ print(f"Uploading .nextflow.log to {{remote.path}}")
98
+ remote.upload_from(Path("/root/.nextflow.log"))
99
+ raise
100
+ finally:
101
+ token = os.environ.get("FLYTE_INTERNAL_EXECUTION_ID")
102
+ if token is None:
103
+ raise RuntimeError("failed to get execution token")
104
+
105
+ headers = {{"Authorization": f"Latch-Execution-Token {{token}}"}}
106
+ resp = requests.post(
107
+ "http://nf-dispatcher-service.flyte.svc.cluster.local/finalize",
108
+ headers=headers,
109
+ json={{
110
+ "pvc_name": pvc_name,
111
+ }}
112
+ )
113
+ if resp.status_code != 200:
114
+ print("Failed to finalize workflow:", resp.status_code)
115
+
116
+
117
+
118
+ @workflow(metadata._nextflow_metadata)
119
+ def {workflow_func_name}({param_signature_with_defaults}) -> None:
120
+ pvc_name: str = initialize()
121
+ nextflow_runtime(pvc_name=pvc_name, {param_args})
122
+
123
+ """
124
+
125
+
126
+ def _get_flags_for_dataclass(name: str, val: Any) -> List[str]:
127
+ assert is_dataclass(val)
128
+
129
+ flags = []
130
+ for f in fields(val):
131
+ flags.extend(get_flag(f"{name}.{f.name}", getattr(val, f.name)))
132
+
133
+ return flags
134
+
135
+
136
+ def get_flag(name: str, val: Any) -> List[str]:
137
+ flag = f"--{name}"
138
+
139
+ if isinstance(val, bool):
140
+ return [flag] if val else []
141
+ elif isinstance(val, LatchFile) or isinstance(val, LatchDir):
142
+ if val.remote_path is not None:
143
+ return [flag, val.remote_path]
144
+
145
+ return [flag, str(val.path)]
146
+ elif is_dataclass(val):
147
+ return _get_flags_for_dataclass(name, val)
148
+ elif isinstance(val, Enum):
149
+ return [flag, getattr(val, "value")]
150
+ else:
151
+ return [flag, str(val)]
152
+
153
+
154
+ def generate_nextflow_workflow(
155
+ pkg_root: Path,
156
+ workflow_name: str,
157
+ nf_script: Path,
158
+ *,
159
+ execution_profile: Optional[str] = None,
160
+ ):
161
+ assert metadata._nextflow_metadata is not None
162
+
163
+ wf_name = metadata._nextflow_metadata.name
164
+ parameters = metadata._nextflow_metadata.parameters
165
+ resources = metadata._nextflow_metadata.runtime_resources
166
+
167
+ flags = []
168
+ for param_name, param in parameters.items():
169
+ flags.append(reindent(f"*get_flag({repr(param_name)}, {param_name})", 3))
170
+
171
+ defaults: List[Tuple[str, str]] = []
172
+ no_defaults: List[str] = []
173
+ preambles: List[str] = []
174
+ for param_name, param in parameters.items():
175
+ sig = f"{param_name}: {type_repr(param.type)}"
176
+ if param.default is not None:
177
+ if isinstance(param.default, Enum):
178
+ defaults.append((sig, param.default))
179
+ else:
180
+ defaults.append((sig, repr(param.default)))
181
+ else:
182
+ no_defaults.append(sig)
183
+
184
+ preamble = get_preamble(param.type)
185
+ if len(preamble) > 0:
186
+ preambles.append(preamble)
187
+
188
+ if metadata._nextflow_metadata.output_dir is None:
189
+ output_dir = "latch:///nextflow_outputs"
190
+ else:
191
+ output_dir = metadata._nextflow_metadata.output_dir._raw_remote_path
192
+ output_dir = urljoins(output_dir, wf_name)
193
+
194
+ entrypoint = template.format(
195
+ workflow_func_name=identifier_from_str(workflow_name),
196
+ nf_script=nf_script.resolve().relative_to(pkg_root.resolve()),
197
+ param_signature_with_defaults=", ".join(
198
+ no_defaults + [f"{name}={val}" for name, val in defaults]
199
+ ),
200
+ param_signature=", ".join(no_defaults + [name for name, _ in defaults]),
201
+ param_args=", ".join(
202
+ f"{param_name}={param_name}" for param_name in parameters.keys()
203
+ ),
204
+ params_to_flags=",\n".join(flags),
205
+ execution_profile=(
206
+ execution_profile if execution_profile is not None else "standard"
207
+ ),
208
+ preambles="\n\n".join(preambles),
209
+ cpu=resources.cpus,
210
+ memory=resources.memory,
211
+ storage_gib=resources.storage_gib,
212
+ remote_output_dir=output_dir,
213
+ )
214
+
215
+ entrypoint_path = pkg_root / "wf" / "entrypoint.py"
216
+ entrypoint_path.parent.mkdir(exist_ok=True)
217
+ entrypoint_path.write_text(entrypoint)
218
+
219
+ click.secho(
220
+ f"Nextflow workflow written to {pkg_root / 'wf' / 'entrypoint.py'}",
221
+ fg="green",
222
+ )
@@ -192,7 +192,7 @@ def parse_value(t: Type, v: JSONValue):
192
192
  def is_primitive_type(
193
193
  typ: Type,
194
194
  ) -> TypeGuard[Union[Type[None], Type[str], Type[bool], Type[int], Type[float]]]:
195
- return typ in {Type[None], str, bool, int, float}
195
+ return typ in {type(None), str, bool, int, float}
196
196
 
197
197
 
198
198
  def is_primitive_value(val: object) -> TypeGuard[Union[None, str, bool, int, float]]:
@@ -231,11 +231,12 @@ def type_repr(t: Type, *, add_namespace: bool = False) -> str:
231
231
  if get_origin(t) is Annotated:
232
232
  args = get_args(t)
233
233
  assert len(args) > 1
234
- assert isinstance(args[1], FlyteAnnotation)
235
- return (
236
- f"typing_extensions.Annotated[{type_repr(args[0], add_namespace=add_namespace)},"
237
- f" FlyteAnnotation({repr(args[1].data)})]"
238
- )
234
+ if isinstance(args[1], FlyteAnnotation):
235
+ return (
236
+ f"typing_extensions.Annotated[{type_repr(args[0], add_namespace=add_namespace)},"
237
+ f" FlyteAnnotation({repr(args[1].data)})]"
238
+ )
239
+ return type_repr(args[0], add_namespace=add_namespace)
239
240
 
240
241
  return t.__name__
241
242
 
@@ -250,6 +251,16 @@ def dataclass_repr(typ: Type) -> str:
250
251
  return "\n".join(lines) + "\n\n\n"
251
252
 
252
253
 
254
+ def enum_repr(typ: Type) -> str:
255
+ assert issubclass(typ, Enum), typ
256
+
257
+ lines = [f"class {typ.__name__}(Enum):"]
258
+ for name, val in typ._member_map_.items():
259
+ lines.append(f" {name} = {repr(val.value)}")
260
+
261
+ return "\n".join(lines) + "\n\n\n"
262
+
263
+
253
264
  def get_preamble(typ: Type) -> str:
254
265
  if get_origin(typ) is Annotated:
255
266
  args = get_args(typ)
@@ -262,6 +273,9 @@ def get_preamble(typ: Type) -> str:
262
273
  if get_origin(typ) in {Union, list}:
263
274
  return "".join([get_preamble(t) for t in get_args(typ)])
264
275
 
276
+ if issubclass(typ, Enum):
277
+ return enum_repr(typ)
278
+
265
279
  assert is_dataclass(typ), typ
266
280
 
267
281
  preamble = "".join([get_preamble(f.type) for f in fields(typ)])
@@ -13,7 +13,7 @@ if cur_ver < (3, 8) or cur_ver > (3, 11):
13
13
 
14
14
  setup(
15
15
  name="latch",
16
- version="v2.41.3.dev0",
16
+ version="v2.41.3.dev2",
17
17
  author_email="kenny@latch.bio",
18
18
  description="The Latch SDK",
19
19
  packages=find_packages(),
File without changes