latch 2.51.2.dev5__tar.gz → 2.51.2.dev6__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 (189) hide show
  1. {latch-2.51.2.dev5/latch.egg-info → latch-2.51.2.dev6}/PKG-INFO +1 -1
  2. {latch-2.51.2.dev5 → latch-2.51.2.dev6/latch.egg-info}/PKG-INFO +1 -1
  3. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch.egg-info/SOURCES.txt +5 -2
  4. latch-2.51.2.dev6/latch_cli/menus/__init__.py +8 -0
  5. latch-2.51.2.dev6/latch_cli/menus/common.py +181 -0
  6. latch-2.51.2.dev6/latch_cli/menus/vt100.py +165 -0
  7. latch-2.51.2.dev6/latch_cli/menus/win32.py +241 -0
  8. latch-2.51.2.dev6/latch_cli/menus/win32_types.py +232 -0
  9. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/execute/main.py +2 -2
  10. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/get_executions.py +38 -31
  11. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/get_params.py +1 -8
  12. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/launch.py +1 -0
  13. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/local_dev_old.py +2 -2
  14. latch-2.51.2.dev6/latch_cli/services/preview.py +71 -0
  15. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/setup.py +1 -1
  16. latch-2.51.2.dev5/latch_cli/menus.py +0 -378
  17. latch-2.51.2.dev5/latch_cli/services/preview.py +0 -179
  18. latch-2.51.2.dev5/tests/__init__.py +0 -0
  19. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/LICENSE +0 -0
  20. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/MANIFEST.in +0 -0
  21. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/README.md +0 -0
  22. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/__init__.py +0 -0
  23. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/account.py +0 -0
  24. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/executions.py +0 -0
  25. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/functions/__init__.py +0 -0
  26. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/functions/messages.py +0 -0
  27. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/functions/operators.py +0 -0
  28. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/functions/secrets.py +0 -0
  29. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/__init__.py +0 -0
  30. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/__init__.py +0 -0
  31. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/download.py +0 -0
  32. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/manager.py +0 -0
  33. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/node.py +0 -0
  34. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/progress.py +0 -0
  35. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/remote_copy.py +0 -0
  36. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/throttle.py +0 -0
  37. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/upload.py +0 -0
  38. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/_transfer/utils.py +0 -0
  39. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/path.py +0 -0
  40. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/ldata/type.py +0 -0
  41. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/__init__.py +0 -0
  42. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/project.py +0 -0
  43. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/record.py +0 -0
  44. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/table.py +0 -0
  45. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/types.py +0 -0
  46. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/upstream_types/__init__.py +0 -0
  47. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/upstream_types/types.py +0 -0
  48. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/upstream_types/values.py +0 -0
  49. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/registry/utils.py +0 -0
  50. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/__init__.py +0 -0
  51. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/conditional.py +0 -0
  52. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/dynamic.py +0 -0
  53. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/launch_plan.py +0 -0
  54. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/map_tasks.py +0 -0
  55. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/reference_workflow.py +0 -0
  56. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/tasks.py +0 -0
  57. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/resources/workflow.py +0 -0
  58. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/__init__.py +0 -0
  59. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/directory.py +0 -0
  60. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/file.py +0 -0
  61. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/glob.py +0 -0
  62. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/json.py +0 -0
  63. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/metadata.py +0 -0
  64. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/types/utils.py +0 -0
  65. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/utils.py +0 -0
  66. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/__init__.py +0 -0
  67. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/deseq2.py +0 -0
  68. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/mafft.py +0 -0
  69. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/pathway.py +0 -0
  70. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/rnaseq.py +0 -0
  71. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch/verified/trim_galore.py +0 -0
  72. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch.egg-info/dependency_links.txt +0 -0
  73. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch.egg-info/entry_points.txt +0 -0
  74. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch.egg-info/requires.txt +0 -0
  75. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch.egg-info/top_level.txt +0 -0
  76. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/__init__.py +0 -0
  77. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/auth/__init__.py +0 -0
  78. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/auth/csrf.py +0 -0
  79. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/auth/oauth2.py +0 -0
  80. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/auth/pkce.py +0 -0
  81. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/auth/utils.py +0 -0
  82. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/centromere/__init__.py +0 -0
  83. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/centromere/ctx.py +0 -0
  84. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/centromere/utils.py +0 -0
  85. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/click_utils.py +0 -0
  86. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/constants.py +0 -0
  87. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/docker_utils/__init__.py +0 -0
  88. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/exceptions/__init__.py +0 -0
  89. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/exceptions/cache.py +0 -0
  90. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/exceptions/errors.py +0 -0
  91. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/exceptions/handler.py +0 -0
  92. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/exceptions/traceback.py +0 -0
  93. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/main.py +0 -0
  94. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/nextflow/__init__.py +0 -0
  95. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/nextflow/config.py +0 -0
  96. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/nextflow/utils.py +0 -0
  97. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/nextflow/workflow.py +0 -0
  98. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/__init__.py +0 -0
  99. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/cp/__init__.py +0 -0
  100. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/cp/autocomplete.py +0 -0
  101. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/cp/glob.py +0 -0
  102. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/cp/main.py +0 -0
  103. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/cp/utils.py +0 -0
  104. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/execute/__init__.py +0 -0
  105. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/execute/utils.py +0 -0
  106. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/get.py +0 -0
  107. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__init__.py +0 -0
  108. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
  109. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
  110. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
  111. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
  112. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
  113. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
  114. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
  115. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
  116. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/.env +0 -0
  117. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
  118. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
  119. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
  120. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
  121. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
  122. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
  123. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
  124. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/common/.dockerignore +0 -0
  125. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_conda/__init__.py +0 -0
  126. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
  127. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_conda/conda_task.py +0 -0
  128. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_conda/environment.yaml +0 -0
  129. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_docker/__init__.py +0 -0
  130. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_docker/task.py +0 -0
  131. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
  132. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
  133. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
  134. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_nfcore/task.py +0 -0
  135. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_r/__init__.py +0 -0
  136. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
  137. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_r/environment.R +0 -0
  138. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_r/r_task.py +0 -0
  139. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
  140. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
  141. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
  142. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
  143. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
  144. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
  145. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
  146. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/example_snakemake/version +0 -0
  147. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/init.py +0 -0
  148. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/template/LICENSE +0 -0
  149. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/template/README.md +0 -0
  150. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/template/__init__.py +0 -0
  151. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
  152. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/init/template/task.py +0 -0
  153. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/local_dev.py +0 -0
  154. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/login.py +0 -0
  155. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/ls.py +0 -0
  156. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/mkdir.py +0 -0
  157. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/move.py +0 -0
  158. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/register/__init__.py +0 -0
  159. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/register/constants.py +0 -0
  160. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/register/register.py +0 -0
  161. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/register/utils.py +0 -0
  162. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/rm.py +0 -0
  163. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/stop_pod.py +0 -0
  164. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/sync.py +0 -0
  165. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/test_data/__init__.py +0 -0
  166. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/test_data/ls.py +0 -0
  167. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/test_data/remove.py +0 -0
  168. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/test_data/upload.py +0 -0
  169. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/test_data/utils.py +0 -0
  170. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/services/workspace.py +0 -0
  171. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/__init__.py +0 -0
  172. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/config/__init__.py +0 -0
  173. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/config/parser.py +0 -0
  174. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/config/utils.py +0 -0
  175. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/serialize.py +0 -0
  176. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/serialize_utils.py +0 -0
  177. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/single_task_snakemake.py +0 -0
  178. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/utils.py +0 -0
  179. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/snakemake/workflow.py +0 -0
  180. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/tinyrequests.py +0 -0
  181. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/utils/__init__.py +0 -0
  182. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/utils/path.py +0 -0
  183. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/latch_cli/workflow_config.py +0 -0
  184. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/pyproject.toml +0 -0
  185. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/setup.cfg +0 -0
  186. {latch-2.51.2.dev5/latch_cli/tui → latch-2.51.2.dev6/tests}/__init__.py +0 -0
  187. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/tests/cp/__init__.py +0 -0
  188. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/tests/fixtures.py +0 -0
  189. {latch-2.51.2.dev5 → latch-2.51.2.dev6}/tests/test_ls.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: latch
3
- Version: 2.51.2.dev5
3
+ Version: 2.51.2.dev6
4
4
  Summary: The Latch SDK
5
5
  Author-email: kenny@latch.bio
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: latch
3
- Version: 2.51.2.dev5
3
+ Version: 2.51.2.dev6
4
4
  Summary: The Latch SDK
5
5
  Author-email: kenny@latch.bio
6
6
  Classifier: Programming Language :: Python :: 3.8
@@ -63,7 +63,6 @@ latch_cli/__init__.py
63
63
  latch_cli/click_utils.py
64
64
  latch_cli/constants.py
65
65
  latch_cli/main.py
66
- latch_cli/menus.py
67
66
  latch_cli/tinyrequests.py
68
67
  latch_cli/workflow_config.py
69
68
  latch_cli/auth/__init__.py
@@ -80,6 +79,11 @@ latch_cli/exceptions/cache.py
80
79
  latch_cli/exceptions/errors.py
81
80
  latch_cli/exceptions/handler.py
82
81
  latch_cli/exceptions/traceback.py
82
+ latch_cli/menus/__init__.py
83
+ latch_cli/menus/common.py
84
+ latch_cli/menus/vt100.py
85
+ latch_cli/menus/win32.py
86
+ latch_cli/menus/win32_types.py
83
87
  latch_cli/nextflow/__init__.py
84
88
  latch_cli/nextflow/config.py
85
89
  latch_cli/nextflow/utils.py
@@ -172,7 +176,6 @@ latch_cli/snakemake/workflow.py
172
176
  latch_cli/snakemake/config/__init__.py
173
177
  latch_cli/snakemake/config/parser.py
174
178
  latch_cli/snakemake/config/utils.py
175
- latch_cli/tui/__init__.py
176
179
  latch_cli/utils/__init__.py
177
180
  latch_cli/utils/path.py
178
181
  tests/__init__.py
@@ -0,0 +1,8 @@
1
+ import sys
2
+
3
+ if sys.platform == "win32":
4
+ from .win32 import raw_input, select_tui
5
+ else:
6
+ from .vt100 import raw_input, select_tui
7
+
8
+ from .common import *
@@ -0,0 +1,181 @@
1
+ import sys
2
+ from typing import Callable, Generic, Tuple
3
+
4
+ from git import Optional
5
+ from typing_extensions import TypedDict, TypeVar
6
+
7
+ old_print = print
8
+
9
+
10
+ def buffered_print() -> Tuple[Callable, Callable]:
11
+ buffer = []
12
+
13
+ def __print(*args):
14
+ for arg in args:
15
+ buffer.append(arg)
16
+
17
+ def __show():
18
+ nonlocal buffer
19
+ old_print("".join(buffer), flush=True, end="")
20
+ buffer = []
21
+
22
+ return __print, __show
23
+
24
+
25
+ # Allows for exactly one print per render, removing any weird flashing
26
+ # behavior and also speeding things up considerably
27
+ print, show = buffered_print()
28
+
29
+
30
+ def clear(k: int):
31
+ """
32
+ Clear `k` lines below the cursor, returning the cursor to its original position
33
+ """
34
+ print(f"\x1b[2K\x1b[1E" * (k) + f"\x1b[{k}F")
35
+
36
+
37
+ def draw_box(
38
+ ul_corner_pos: Tuple[int, int],
39
+ height: int,
40
+ width: int,
41
+ color: Optional[str] = None,
42
+ ):
43
+ if height <= 0 or width <= 0:
44
+ return
45
+ move_cursor(ul_corner_pos)
46
+ draw_horizontal_line(width, make_corner=True, color=color)
47
+ draw_vertical_line(height, make_corner=True, color=color)
48
+ draw_horizontal_line(width, left=True, make_corner=True, color=color)
49
+ draw_vertical_line(height, up=True, make_corner=True, color=color)
50
+
51
+
52
+ def clear_screen():
53
+ print("\x1b[2J")
54
+
55
+
56
+ def remove_cursor():
57
+ print("\x1b[?25l")
58
+
59
+
60
+ def reveal_cursor():
61
+ print("\x1b[?25h")
62
+
63
+
64
+ def move_cursor(pos: Tuple[int, int]):
65
+ """
66
+ Move the cursor to a given (x, y) coordinate
67
+ """
68
+ x, y = pos
69
+ if x < 0 or y < 0:
70
+ return
71
+ print(f"\x1b[{y};{x}H")
72
+
73
+
74
+ def move_cursor_up(n: int):
75
+ if n <= 0:
76
+ return
77
+ print(f"\x1b[{n}A")
78
+
79
+
80
+ def line_up(n: int):
81
+ """Moves to the start of the destination line"""
82
+ if n <= 0:
83
+ return
84
+ print(f"\x1b[{n}F")
85
+
86
+
87
+ def move_cursor_down(n: int):
88
+ if n <= 0:
89
+ return
90
+ print(f"\x1b[{n}B")
91
+
92
+
93
+ def line_down(n: int):
94
+ """Moves to the start of the destination line"""
95
+ if n <= 0:
96
+ return
97
+ print(f"\x1b[{n}E")
98
+
99
+
100
+ def move_cursor_right(n: int):
101
+ if n <= 0:
102
+ return
103
+ print(f"\x1b[{n}C")
104
+
105
+
106
+ def move_cursor_left(n: int):
107
+ if n <= 0:
108
+ return
109
+ print(f"\x1b[{n}D")
110
+
111
+
112
+ def current_cursor_position() -> Tuple[int, int]:
113
+ res = b""
114
+ sys.stdout.write("\x1b[6n")
115
+ sys.stdout.flush()
116
+ while not res.endswith(b"R"):
117
+ res += sys.stdin.buffer.read(1)
118
+ y, x = res.strip(b"\x1b[R").split(b";")
119
+ return int(x), int(y)
120
+
121
+
122
+ def draw_vertical_line(
123
+ height: int,
124
+ up: bool = False,
125
+ make_corner: bool = False,
126
+ color: Optional[str] = None,
127
+ ):
128
+ """
129
+ Draws a vertical line with given `height`, going upwards if `up` is True
130
+ and downwards otherwise.
131
+ """
132
+
133
+ if height <= 0:
134
+ return
135
+
136
+ if color is not None:
137
+ print(color)
138
+ sep = "\x1b[1A" if up else "\x1b[1B"
139
+ for i in range(height):
140
+ if i == 0 and make_corner:
141
+ corner = "\u2514" if up else "\u2510"
142
+ print(f"{corner}\x1b[1D{sep}")
143
+ else:
144
+ print(f"\u2502\x1b[1D{sep}")
145
+ if color is not None:
146
+ print("\x1b[0m")
147
+
148
+
149
+ def draw_horizontal_line(
150
+ width: int,
151
+ left: bool = False,
152
+ make_corner: bool = False,
153
+ color: Optional[str] = None,
154
+ ):
155
+ """
156
+ Draws a horizontal line with given `width`, going to the left if `left` is True
157
+ and to the right otherwise.
158
+ """
159
+
160
+ if width <= 0:
161
+ return
162
+
163
+ if color is not None:
164
+ print(color)
165
+ sep = "\x1b[2D" if left else ""
166
+ for i in range(width):
167
+ if i == 0 and make_corner:
168
+ corner = "\u2518" if left else "\u250c"
169
+ print(f"{corner}{sep}")
170
+ else:
171
+ print(f"\u2500{sep}")
172
+ if color is not None:
173
+ print("\x1b[0m")
174
+
175
+
176
+ T = TypeVar("T")
177
+
178
+
179
+ class SelectOption(TypedDict, Generic[T]):
180
+ display_name: str
181
+ value: T
@@ -0,0 +1,165 @@
1
+ import os
2
+ import sys
3
+ import termios
4
+ import tty
5
+ from functools import wraps
6
+ from typing import Callable, List, Optional, TypeVar
7
+
8
+ from typing_extensions import ParamSpec
9
+
10
+ from latch_cli.click_utils import AnsiCodes
11
+
12
+ from . import common
13
+
14
+ P = ParamSpec("P")
15
+ T = TypeVar("T")
16
+
17
+
18
+ def raw_input(f: Callable[P, T]) -> Callable[P, T]:
19
+ @wraps(f)
20
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
21
+ old_settings = termios.tcgetattr(sys.stdin.fileno())
22
+ tty.setraw(sys.stdin.fileno())
23
+
24
+ try:
25
+ return f(*args, **kwargs)
26
+ finally:
27
+ termios.tcsetattr(sys.stdin.fileno(), termios.TCSANOW, old_settings)
28
+
29
+ return wrapper
30
+
31
+
32
+ def read_next_byte() -> bytes:
33
+ b = sys.stdin.buffer.read(1)
34
+ if b in (
35
+ b"\x03", # CTRL C
36
+ b"\x04", # CTRL D
37
+ b"q",
38
+ b"Q",
39
+ ):
40
+ raise KeyboardInterrupt
41
+ return b
42
+
43
+
44
+ def read_bytes(num_bytes: int) -> bytes:
45
+ if num_bytes < 0:
46
+ raise ValueError(f"cannot read {num_bytes} bytes")
47
+ result = b""
48
+ for _ in range(num_bytes):
49
+ result += read_next_byte()
50
+ return result
51
+
52
+
53
+ @raw_input
54
+ def select_tui(
55
+ title: str, options: List[common.SelectOption[T]], clear_terminal: bool = True
56
+ ) -> Optional[T]:
57
+ """
58
+ Renders a terminal UI that allows users to select one of the options
59
+ listed in `options`
60
+
61
+ Args:
62
+ title: The title of the selection window.
63
+ options: A list of names for each of the options.
64
+ clear_terminal: Whether or not to clear the entire terminal window
65
+ before displaying - default False
66
+ """
67
+
68
+ if len(options) == 0:
69
+ raise ValueError("No options given")
70
+
71
+ def render(
72
+ curr_selected: int,
73
+ start_index: int = 0,
74
+ max_per_page: int = 10,
75
+ indent: str = " ",
76
+ ) -> int:
77
+ if curr_selected < 0 or curr_selected >= len(options):
78
+ curr_selected = 0
79
+
80
+ print(title)
81
+ common.line_down(2)
82
+
83
+ num_lines_rendered = 4 # 4 "extra" lines for header + footer
84
+
85
+ for i in range(start_index, start_index + max_per_page):
86
+ if i >= len(options):
87
+ break
88
+ name = options[i]["display_name"]
89
+ if i == curr_selected:
90
+ color = AnsiCodes.color
91
+ bold = AnsiCodes.bold
92
+ reset = AnsiCodes.full_reset
93
+
94
+ prefix = indent[:-2] + "> "
95
+
96
+ print(f"{color}{bold}{prefix}{name}{reset}\x1b[1E")
97
+ else:
98
+ print(f"{indent}{name}\x1b[1E")
99
+ num_lines_rendered += 1
100
+
101
+ common.line_down(1)
102
+
103
+ control_str = "[ARROW-KEYS] Navigate\t[ENTER] Select\t[Q] Quit"
104
+ print(control_str)
105
+ common.line_up(num_lines_rendered - 1)
106
+
107
+ common.show()
108
+
109
+ return num_lines_rendered
110
+
111
+ curr_selected = 0
112
+ start_index = 0
113
+ _, term_height = os.get_terminal_size()
114
+ common.remove_cursor()
115
+
116
+ max_per_page = min(len(options), term_height - 4)
117
+
118
+ if clear_terminal:
119
+ common.clear_screen()
120
+ common.move_cursor((0, 0))
121
+ else:
122
+ print("\n" * (max_per_page + 3))
123
+ common.move_cursor_up(max_per_page + 4)
124
+
125
+ num_lines_rendered = render(
126
+ curr_selected,
127
+ start_index=start_index,
128
+ max_per_page=max_per_page,
129
+ )
130
+
131
+ try:
132
+ while True:
133
+ b = read_bytes(1)
134
+ if b == b"\r":
135
+ return options[curr_selected]["value"]
136
+ elif b == b"\x1b":
137
+ b = read_bytes(2)
138
+ if b == b"[A": # Up Arrow
139
+ curr_selected = max(curr_selected - 1, 0)
140
+ if (
141
+ curr_selected - start_index < max_per_page // 2
142
+ and start_index > 0
143
+ ):
144
+ start_index -= 1
145
+ elif b == b"[B": # Down Arrow
146
+ curr_selected = min(curr_selected + 1, len(options) - 1)
147
+ if (
148
+ curr_selected - start_index > max_per_page // 2
149
+ and start_index < len(options) - max_per_page
150
+ ):
151
+ start_index += 1
152
+ else:
153
+ continue
154
+ common.clear(num_lines_rendered)
155
+ num_lines_rendered = render(
156
+ curr_selected,
157
+ start_index=start_index,
158
+ max_per_page=max_per_page,
159
+ )
160
+ except KeyboardInterrupt:
161
+ ...
162
+ finally:
163
+ common.clear(num_lines_rendered)
164
+ common.reveal_cursor()
165
+ common.show()
@@ -0,0 +1,241 @@
1
+ import msvcrt
2
+ import os
3
+ import sys
4
+ from ctypes import c_ulong, pointer, windll
5
+ from ctypes.wintypes import DWORD, HANDLE
6
+ from dataclasses import dataclass
7
+ from enum import Enum
8
+ from functools import wraps
9
+ from typing import TYPE_CHECKING, Callable, List, Optional, TypeVar
10
+
11
+ from typing_extensions import ParamSpec
12
+
13
+ from latch_cli.click_utils import AnsiCodes
14
+
15
+ from . import common
16
+ from .win32_types import (
17
+ INPUT_RECORD,
18
+ KEY_EVENT_RECORD,
19
+ MOUSE_EVENT_RECORD,
20
+ STD_INPUT_HANDLE,
21
+ EventTypes,
22
+ )
23
+
24
+ # assert sys.platform == "win32"
25
+
26
+ P = ParamSpec("P")
27
+ T = TypeVar("T")
28
+
29
+
30
+ def raw_input(f: Callable[P, T]) -> Callable[P, T]:
31
+ # ayush: got most of this from
32
+ # https://github.com/prompt-toolkit/python-prompt-toolkit/blob/669541123c9a72da1fda662cbd0a18ffe9e6d113/src/prompt_toolkit/input/win32.py
33
+ @wraps(f)
34
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
35
+
36
+ original_mode = DWORD()
37
+ handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
38
+ windll.kernel32.GetConsoleMode(handle, pointer(original_mode))
39
+
40
+ enable_echo_input = 0x0004
41
+ enable_line_input = 0x0002
42
+ enable_processed_input = 0x0001
43
+
44
+ windll.kernel32.SetConsoleMode(
45
+ handle,
46
+ original_mode.value
47
+ & ~(enable_echo_input | enable_line_input | enable_processed_input),
48
+ )
49
+
50
+ try:
51
+ return f(*args, **kwargs)
52
+ finally:
53
+ windll.kernel32.SetConsoleMode(handle, original_mode)
54
+
55
+ return wrapper
56
+
57
+
58
+ class Special(Enum):
59
+ left = "left"
60
+ right = "right"
61
+ up = "up"
62
+ down = "down"
63
+ enter = "enter"
64
+ ctrlc = "ctrlc"
65
+ ctrld = "ctrld"
66
+
67
+
68
+ @dataclass
69
+ class KeyInput:
70
+ special: Optional[Special]
71
+ value: str
72
+
73
+
74
+ # ignoring most things except for arrow keys / enter
75
+ def get_key_input() -> Optional[KeyInput]:
76
+ # ayush:
77
+ # https://github.com/prompt-toolkit/python-prompt-toolkit/blob/669541123c9a72da1fda662cbd0a18ffe9e6d113/src/prompt_toolkit/input/win32.py#L127
78
+ handle: HANDLE
79
+ if sys.stdin.isatty():
80
+ handle = HANDLE(windll.kernel32.GetStdHandle(STD_INPUT_HANDLE))
81
+ else:
82
+ _fdcon = os.open("CONIN$", os.O_RDWR | os.O_BINARY)
83
+ handle = HANDLE(msvcrt.get_osfhandle(_fdcon))
84
+
85
+ max_count = 2048 # Max events to read at the same time.
86
+
87
+ read = DWORD(0)
88
+ arrtype = INPUT_RECORD * max_count
89
+ input_records = arrtype()
90
+
91
+ windll.kernel32.ReadConsoleInputW(
92
+ handle, pointer(input_records), max_count, pointer(read)
93
+ )
94
+
95
+ for i in range(read.value):
96
+ ir = input_records[i]
97
+
98
+ if ir.EventType not in EventTypes:
99
+ continue
100
+
101
+ ev = getattr(ir.Event, EventTypes[ir.EventType])
102
+
103
+ if not (isinstance(ev, KEY_EVENT_RECORD) and ev.KeyDown):
104
+ continue
105
+
106
+ u_char = ev.uChar.UnicodeChar
107
+
108
+ special: Optional[Special] = None
109
+ if u_char == "\x00": # special keys, e.g. arrow keys
110
+ if ev.VirtualKeyCode == 37:
111
+ special = Special.left
112
+ elif ev.VirtualKeyCode == 38:
113
+ special = Special.up
114
+ elif ev.VirtualKeyCode == 39:
115
+ special = Special.right
116
+ elif ev.VirtualKeyCode == 40:
117
+ special = Special.down
118
+ elif u_char == "\x0d":
119
+ special = Special.enter
120
+ elif u_char == "\x03":
121
+ special = Special.ctrlc
122
+ elif u_char == "\x04":
123
+ special = Special.ctrld
124
+
125
+ return KeyInput(special, u_char)
126
+
127
+
128
+ @raw_input
129
+ def select_tui(
130
+ title: str, options: List[common.SelectOption[T]], clear_terminal: bool = True
131
+ ) -> Optional[T]:
132
+ """
133
+ Renders a terminal UI that allows users to select one of the options
134
+ listed in `options`
135
+
136
+ Args:
137
+ title: The title of the selection window.
138
+ options: A list of names for each of the options.
139
+ clear_terminal: Whether or not to clear the entire terminal window
140
+ before displaying - default False
141
+ """
142
+
143
+ if len(options) == 0:
144
+ raise ValueError("No options given")
145
+
146
+ def render(
147
+ curr_selected: int,
148
+ start_index: int = 0,
149
+ max_per_page: int = 10,
150
+ indent: str = " ",
151
+ ) -> int:
152
+ if curr_selected < 0 or curr_selected >= len(options):
153
+ curr_selected = 0
154
+
155
+ print(title)
156
+ common.line_down(2)
157
+
158
+ num_lines_rendered = 4 # 4 "extra" lines for header + footer
159
+
160
+ for i in range(start_index, start_index + max_per_page):
161
+ if i >= len(options):
162
+ break
163
+ name = options[i]["display_name"]
164
+ if i == curr_selected:
165
+ color = AnsiCodes.color
166
+ bold = AnsiCodes.bold
167
+ reset = AnsiCodes.full_reset
168
+
169
+ prefix = indent[:-2] + "> "
170
+
171
+ print(f"{color}{bold}{prefix}{name}{reset}\x1b[1E")
172
+ else:
173
+ print(f"{indent}{name}\x1b[1E")
174
+ num_lines_rendered += 1
175
+
176
+ common.line_down(1)
177
+
178
+ control_str = "[ARROW-KEYS] Navigate\t[ENTER] Select\t[Q] Quit"
179
+ print(control_str)
180
+ common.line_up(num_lines_rendered - 1)
181
+
182
+ common.show()
183
+
184
+ return num_lines_rendered
185
+
186
+ curr_selected = 0
187
+ start_index = 0
188
+ _, term_height = os.get_terminal_size()
189
+ common.remove_cursor()
190
+
191
+ max_per_page = min(len(options), term_height - 4)
192
+
193
+ if clear_terminal:
194
+ common.clear_screen()
195
+ common.move_cursor((0, 0))
196
+ else:
197
+ print("\n" * (max_per_page + 3))
198
+ common.move_cursor_up(max_per_page + 4)
199
+
200
+ num_lines_rendered = render(
201
+ curr_selected,
202
+ start_index=start_index,
203
+ max_per_page=max_per_page,
204
+ )
205
+
206
+ try:
207
+ while True:
208
+ k = get_key_input()
209
+ if k is None:
210
+ continue
211
+
212
+ if k.special == Special.enter:
213
+ return options[curr_selected]["value"]
214
+ elif k.special == Special.up: # Up Arrow
215
+ curr_selected = max(curr_selected - 1, 0)
216
+ if curr_selected - start_index < max_per_page // 2 and start_index > 0:
217
+ start_index -= 1
218
+ elif k.special == Special.down: # Down Arrow
219
+ curr_selected = min(curr_selected + 1, len(options) - 1)
220
+ if (
221
+ curr_selected - start_index > max_per_page // 2
222
+ and start_index < len(options) - max_per_page
223
+ ):
224
+ start_index += 1
225
+ elif k.special in {Special.ctrlc, Special.ctrld} or k.value in {"q", "Q"}:
226
+ return
227
+ else:
228
+ continue
229
+
230
+ common.clear(num_lines_rendered)
231
+ num_lines_rendered = render(
232
+ curr_selected,
233
+ start_index=start_index,
234
+ max_per_page=max_per_page,
235
+ )
236
+ except KeyboardInterrupt:
237
+ ...
238
+ finally:
239
+ common.clear(num_lines_rendered)
240
+ common.reveal_cursor()
241
+ common.show()