latch 2.39.0.dev24__tar.gz → 2.39.0.dev26__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.
- {latch-2.39.0.dev24/latch.egg-info → latch-2.39.0.dev26}/PKG-INFO +1 -1
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/metadata.py +2 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26/latch.egg-info}/PKG-INFO +1 -1
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch.egg-info/SOURCES.txt +3 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/docker_utils/__init__.py +3 -12
- latch-2.39.0.dev26/latch_cli/extras/common/config/parser.py +82 -0
- latch-2.39.0.dev26/latch_cli/extras/common/config/utils.py +235 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/common/serialize.py +23 -9
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/common/utils.py +9 -2
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/build.py +5 -3
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/config.py +6 -2
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/serialize.py +1 -1
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/base.py +2 -2
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/operator.py +2 -2
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/process.py +2 -2
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/workflow.py +33 -12
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/setup.py +1 -1
- latch-2.39.0.dev26/tests/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/LICENSE +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/MANIFEST.in +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/README.md +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/account.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/executions.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/functions/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/functions/messages.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/functions/operators.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/functions/secrets.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/download.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/manager.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/node.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/progress.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/remote_copy.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/throttle.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/upload.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/_transfer/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/path.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/ldata/type.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/project.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/record.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/table.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/types.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/upstream_types/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/upstream_types/types.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/upstream_types/values.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/registry/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/conditional.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/launch_plan.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/map_tasks.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/reference_workflow.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/tasks.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/resources/workflow.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/directory.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/file.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/glob.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/json.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/types/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/deseq2.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/mafft.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/pathway.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/rnaseq.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch/verified/trim_galore.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch.egg-info/dependency_links.txt +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch.egg-info/entry_points.txt +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch.egg-info/requires.txt +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch.egg-info/top_level.txt +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/auth/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/auth/csrf.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/auth/oauth2.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/auth/pkce.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/auth/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/centromere/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/centromere/ctx.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/centromere/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/click_utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/constants.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/exceptions/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/exceptions/cache.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/exceptions/errors.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/exceptions/handler.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/exceptions/traceback.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/common/__init__.py +0 -0
- {latch-2.39.0.dev24/latch_cli/extras/nextflow → latch-2.39.0.dev26/latch_cli/extras/common/config}/__init__.py +0 -0
- {latch-2.39.0.dev24/latch_cli/extras/nextflow/tasks → latch-2.39.0.dev26/latch_cli/extras/nextflow}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/channel.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/dag.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/file_persistence.py +0 -0
- {latch-2.39.0.dev24/latch_cli/extras/snakemake → latch-2.39.0.dev26/latch_cli/extras/nextflow/tasks}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/adapters.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/conditional.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/input.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/map.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/merge.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/nextflow/tasks/output.py +0 -0
- {latch-2.39.0.dev24/latch_cli/services/cp → latch-2.39.0.dev26/latch_cli/extras/snakemake}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/snakemake/config.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/snakemake/serialize.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/snakemake/single_task_snakemake.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/snakemake/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/extras/snakemake/workflow.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/main.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/menus.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/__init__.py +0 -0
- {latch-2.39.0.dev24/latch_cli/services/execute → latch-2.39.0.dev26/latch_cli/services/cp}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/cp/autocomplete.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/cp/glob.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/cp/main.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/cp/utils.py +0 -0
- {latch-2.39.0.dev24/latch_cli/services/test_data → latch-2.39.0.dev26/latch_cli/services/execute}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/execute/main.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/execute/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/get.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/get_executions.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/get_params.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/__init__.cpython-311.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/__init__.cpython-38.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/__init__.cpython-39.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/init.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/init.cpython-311.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/init.cpython-38.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/__pycache__/init.cpython-39.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/.env +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/README.md +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/common/.dockerignore +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_conda/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_conda/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_conda/conda_task.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_conda/environment.yaml +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_docker/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_docker/task.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nf_integration/Dockerfile +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nf_integration/latch_metadata/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nf_integration/latch_metadata/__pycache__/__init__.cpython-311.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nf_integration/main.nf +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nf_integration/workflow.nf +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nfcore/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_nfcore/task.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_r/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_r/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_r/environment.R +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_r/r_task.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/Snakefile +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/config.yaml +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/example_snakemake/version +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/init.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/template/LICENSE +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/template/README.md +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/template/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/template/__pycache__/__init__.cpython-310.pyc +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/init/template/task.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/launch.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/local_dev.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/local_dev_old.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/login.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/ls.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/mkdir.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/move.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/preview.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/register/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/register/constants.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/register/register.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/register/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/rm.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/stop_pod.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/sync.py +0 -0
- {latch-2.39.0.dev24/latch_cli/tui → latch-2.39.0.dev26/latch_cli/services/test_data}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/test_data/ls.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/test_data/remove.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/test_data/upload.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/test_data/utils.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/services/workspace.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/tinyrequests.py +0 -0
- {latch-2.39.0.dev24/tests → latch-2.39.0.dev26/latch_cli/tui}/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/utils/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/utils/path.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/utils/workflow.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/latch_cli/workflow_config.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/pyproject.toml +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/setup.cfg +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/tests/cp/__init__.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/tests/fixtures.py +0 -0
- {latch-2.39.0.dev24 → latch-2.39.0.dev26}/tests/test_ls.py +0 -0
|
@@ -696,6 +696,8 @@ class NextflowMetadata(LatchMetadata):
|
|
|
696
696
|
def __post_init__(self):
|
|
697
697
|
if self.name is None:
|
|
698
698
|
self.name = f"nf_{identifier_suffix_from_str(self.display_name.lower())}"
|
|
699
|
+
else:
|
|
700
|
+
self.name = identifier_suffix_from_str(self.name)
|
|
699
701
|
|
|
700
702
|
if self.output_directory is None:
|
|
701
703
|
self.output_directory = LatchDir("latch:///Nextflow Outputs/")
|
|
@@ -82,6 +82,9 @@ latch_cli/extras/__init__.py
|
|
|
82
82
|
latch_cli/extras/common/__init__.py
|
|
83
83
|
latch_cli/extras/common/serialize.py
|
|
84
84
|
latch_cli/extras/common/utils.py
|
|
85
|
+
latch_cli/extras/common/config/__init__.py
|
|
86
|
+
latch_cli/extras/common/config/parser.py
|
|
87
|
+
latch_cli/extras/common/config/utils.py
|
|
85
88
|
latch_cli/extras/nextflow/__init__.py
|
|
86
89
|
latch_cli/extras/nextflow/build.py
|
|
87
90
|
latch_cli/extras/nextflow/channel.py
|
|
@@ -9,6 +9,7 @@ from typing import List
|
|
|
9
9
|
import click
|
|
10
10
|
import yaml
|
|
11
11
|
|
|
12
|
+
from latch_cli.click_utils import color
|
|
12
13
|
from latch_cli.constants import latch_constants
|
|
13
14
|
from latch_cli.utils import WorkflowType
|
|
14
15
|
from latch_cli.workflow_config import LatchWorkflowConfig, create_and_write_config
|
|
@@ -352,18 +353,8 @@ def generate_dockerfile(
|
|
|
352
353
|
with (pkg_root / latch_constants.pkg_config).open("r") as f:
|
|
353
354
|
config = LatchWorkflowConfig(**json.load(f))
|
|
354
355
|
|
|
355
|
-
click.echo(
|
|
356
|
-
|
|
357
|
-
click.style("Base image:", fg="bright_blue"),
|
|
358
|
-
config.base_image,
|
|
359
|
-
])
|
|
360
|
-
)
|
|
361
|
-
click.echo(
|
|
362
|
-
" ".join([
|
|
363
|
-
click.style("Latch SDK version:", fg="bright_blue"),
|
|
364
|
-
config.latch_version,
|
|
365
|
-
])
|
|
366
|
-
)
|
|
356
|
+
click.echo(" ".join([color("Base image:"), config.base_image]))
|
|
357
|
+
click.echo(" ".join([color("Latch SDK version:"), config.latch_version]))
|
|
367
358
|
click.echo()
|
|
368
359
|
|
|
369
360
|
with outfile.open("w") as f:
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Dict, Tuple, Type, TypeVar
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from ..utils import reindent
|
|
7
|
+
from .utils import JSONValue, parse_type, parse_value
|
|
8
|
+
|
|
9
|
+
T = TypeVar("T")
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def parse_config(
|
|
13
|
+
config: JSONValue,
|
|
14
|
+
*,
|
|
15
|
+
infer_files: bool = False,
|
|
16
|
+
) -> Dict[str, Tuple[Type[T], T]]:
|
|
17
|
+
parsed: Dict[str, Type] = {}
|
|
18
|
+
for k, v in config.items():
|
|
19
|
+
try:
|
|
20
|
+
typ = parse_type(v, k, infer_files=infer_files)
|
|
21
|
+
except ValueError as e:
|
|
22
|
+
click.secho(
|
|
23
|
+
f"WARNING: Skipping parameter {k}. Failed to parse type: {e}.",
|
|
24
|
+
fg="yellow",
|
|
25
|
+
)
|
|
26
|
+
continue
|
|
27
|
+
val, default = parse_value(typ, v)
|
|
28
|
+
|
|
29
|
+
parsed[k] = (typ, (val, default))
|
|
30
|
+
|
|
31
|
+
return parsed
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def write_metadata(
|
|
35
|
+
metadata: str,
|
|
36
|
+
params: str,
|
|
37
|
+
*,
|
|
38
|
+
skip_confirmation: bool = False,
|
|
39
|
+
) -> None:
|
|
40
|
+
metadata_root = Path("latch_metadata")
|
|
41
|
+
if metadata_root.is_file():
|
|
42
|
+
if not click.confirm("A file exists at `latch_metadata`. Delete it?"):
|
|
43
|
+
raise click.exceptions.Exit(0)
|
|
44
|
+
|
|
45
|
+
metadata_root.unlink()
|
|
46
|
+
|
|
47
|
+
metadata_root.mkdir(exist_ok=True)
|
|
48
|
+
|
|
49
|
+
metadata_path = metadata_root / Path("__init__.py")
|
|
50
|
+
old_metadata_path = Path("latch_metadata.py")
|
|
51
|
+
|
|
52
|
+
if old_metadata_path.exists() and not metadata_path.exists():
|
|
53
|
+
if click.confirm(
|
|
54
|
+
"Found legacy `latch_metadata.py` file in current directory. This is"
|
|
55
|
+
" deprecated and will be ignored in future releases. Move to"
|
|
56
|
+
" `latch_metadata/__init__.py`? (This will not change file contents)"
|
|
57
|
+
):
|
|
58
|
+
old_metadata_path.rename(metadata_path)
|
|
59
|
+
elif old_metadata_path.exists() and metadata_path.exists():
|
|
60
|
+
click.secho(
|
|
61
|
+
"Warning: Found both `latch_metadata.py` and"
|
|
62
|
+
" `latch_metadata/__init__.py` in current directory."
|
|
63
|
+
" `latch_metadata.py` will be ignored.",
|
|
64
|
+
fg="yellow",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if not metadata_path.exists():
|
|
68
|
+
metadata_path.write_text(reindent(metadata, 0))
|
|
69
|
+
click.secho("Generated `latch_metadata/__init__.py`.", fg="green")
|
|
70
|
+
|
|
71
|
+
params_path = metadata_root / Path("parameters.py")
|
|
72
|
+
if (
|
|
73
|
+
params_path.exists()
|
|
74
|
+
and not skip_confirmation
|
|
75
|
+
and not click.confirm(
|
|
76
|
+
"File `latch_metadata/parameters.py` already exists. Overwrite?"
|
|
77
|
+
)
|
|
78
|
+
):
|
|
79
|
+
raise click.exceptions.Exit(0)
|
|
80
|
+
|
|
81
|
+
params_path.write_text(reindent(params, 0))
|
|
82
|
+
click.secho("Generated `latch_metadata/parameters.py`.", fg="green")
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from dataclasses import fields, is_dataclass, make_dataclass
|
|
2
|
+
from typing import Any, Dict, List, Optional, Type, Union, get_args, get_origin
|
|
3
|
+
|
|
4
|
+
from flytekit.core.annotation import FlyteAnnotation
|
|
5
|
+
from typing_extensions import Annotated, TypeAlias, TypeGuard
|
|
6
|
+
|
|
7
|
+
from latch.types.directory import LatchDir
|
|
8
|
+
from latch.types.file import LatchFile
|
|
9
|
+
from latch_cli.utils import identifier_from_str
|
|
10
|
+
|
|
11
|
+
from ..utils import is_primitive_type, is_primitive_value, type_repr
|
|
12
|
+
|
|
13
|
+
JSONValue: TypeAlias = Union[int, str, bool, float, None, List["JSONValue"], "JSONDict"]
|
|
14
|
+
JSONDict: TypeAlias = Dict[str, "JSONValue"]
|
|
15
|
+
|
|
16
|
+
# ayush: yoinked from console
|
|
17
|
+
valid_extensions = {
|
|
18
|
+
"bed",
|
|
19
|
+
"vcf",
|
|
20
|
+
"css",
|
|
21
|
+
"csv",
|
|
22
|
+
"gif",
|
|
23
|
+
"png",
|
|
24
|
+
"pdf",
|
|
25
|
+
"webp",
|
|
26
|
+
"xhtml",
|
|
27
|
+
"xlsx",
|
|
28
|
+
"xml",
|
|
29
|
+
"py",
|
|
30
|
+
"log",
|
|
31
|
+
"json",
|
|
32
|
+
"gz",
|
|
33
|
+
"mmtf",
|
|
34
|
+
"deseqreport",
|
|
35
|
+
"sam",
|
|
36
|
+
"bam",
|
|
37
|
+
"cram",
|
|
38
|
+
"tsv",
|
|
39
|
+
"tab",
|
|
40
|
+
"sf",
|
|
41
|
+
"txt",
|
|
42
|
+
"text",
|
|
43
|
+
"license",
|
|
44
|
+
"readme",
|
|
45
|
+
"r",
|
|
46
|
+
"rscript",
|
|
47
|
+
"md",
|
|
48
|
+
"markdown",
|
|
49
|
+
"markdn",
|
|
50
|
+
"mdown",
|
|
51
|
+
"htm",
|
|
52
|
+
"html",
|
|
53
|
+
"ipynb",
|
|
54
|
+
"jpeg",
|
|
55
|
+
"jpg",
|
|
56
|
+
"jif",
|
|
57
|
+
"jpe",
|
|
58
|
+
"jfif",
|
|
59
|
+
"js",
|
|
60
|
+
"mjs",
|
|
61
|
+
"es",
|
|
62
|
+
"ts",
|
|
63
|
+
"jsx",
|
|
64
|
+
"tsx",
|
|
65
|
+
"svg",
|
|
66
|
+
"svgz",
|
|
67
|
+
"fasta",
|
|
68
|
+
"fna",
|
|
69
|
+
"fa",
|
|
70
|
+
"ffn",
|
|
71
|
+
"faa",
|
|
72
|
+
"frn",
|
|
73
|
+
"fastq",
|
|
74
|
+
"fq",
|
|
75
|
+
"pdb",
|
|
76
|
+
"pdb1",
|
|
77
|
+
"ent",
|
|
78
|
+
"brk",
|
|
79
|
+
"ml2",
|
|
80
|
+
"mol2",
|
|
81
|
+
"sy2",
|
|
82
|
+
"hdf",
|
|
83
|
+
"h4",
|
|
84
|
+
"hdf4",
|
|
85
|
+
"he4",
|
|
86
|
+
"h5",
|
|
87
|
+
"hdf5",
|
|
88
|
+
"he5",
|
|
89
|
+
"h5ad",
|
|
90
|
+
"yaml",
|
|
91
|
+
"yml",
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def parse_type(
|
|
96
|
+
v: JSONValue, name: Optional[str] = None, *, infer_files: bool = False
|
|
97
|
+
) -> Type:
|
|
98
|
+
if v is None:
|
|
99
|
+
return str
|
|
100
|
+
|
|
101
|
+
if infer_files and isinstance(v, str):
|
|
102
|
+
if any([v.endswith(ext) for ext in valid_extensions]):
|
|
103
|
+
return LatchFile
|
|
104
|
+
elif v.endswith("/"):
|
|
105
|
+
return LatchDir
|
|
106
|
+
|
|
107
|
+
if is_primitive_value(v):
|
|
108
|
+
return type(v)
|
|
109
|
+
|
|
110
|
+
if isinstance(v, list):
|
|
111
|
+
parsed_types = tuple(
|
|
112
|
+
parse_type(
|
|
113
|
+
x,
|
|
114
|
+
name,
|
|
115
|
+
infer_files=infer_files,
|
|
116
|
+
)
|
|
117
|
+
for x in v
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
if len(set(parsed_types)) != 1:
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"Generic Lists are not supported - please"
|
|
123
|
+
f" ensure that all elements in {name} are of the same type",
|
|
124
|
+
)
|
|
125
|
+
typ = parsed_types[0]
|
|
126
|
+
if typ in {LatchFile, LatchDir}:
|
|
127
|
+
return Annotated[List[typ], FlyteAnnotation({"size": len(v)})]
|
|
128
|
+
return List[typ]
|
|
129
|
+
|
|
130
|
+
assert isinstance(v, dict)
|
|
131
|
+
|
|
132
|
+
if name is None:
|
|
133
|
+
name = "SnakemakeRecord"
|
|
134
|
+
|
|
135
|
+
fields: Dict[str, Type] = {}
|
|
136
|
+
for k, x in v.items():
|
|
137
|
+
fields[identifier_from_str(k)] = parse_type(
|
|
138
|
+
x,
|
|
139
|
+
k,
|
|
140
|
+
infer_files=infer_files,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
return make_dataclass(identifier_from_str(name), fields.items())
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# returns raw value and generated default
|
|
147
|
+
def parse_value(t: Type, v: JSONValue):
|
|
148
|
+
if v is None:
|
|
149
|
+
return None, None
|
|
150
|
+
|
|
151
|
+
if get_origin(t) is Annotated:
|
|
152
|
+
args = get_args(t)
|
|
153
|
+
assert len(args) > 0
|
|
154
|
+
return parse_value(args[0], v)
|
|
155
|
+
|
|
156
|
+
if t in {LatchFile, LatchDir}:
|
|
157
|
+
# ayush: autogenerated defaults don't make sense for files/dirs since their
|
|
158
|
+
# value in the config is their local path
|
|
159
|
+
return v, None
|
|
160
|
+
|
|
161
|
+
if is_primitive_value(v):
|
|
162
|
+
return v, v
|
|
163
|
+
|
|
164
|
+
if isinstance(v, list):
|
|
165
|
+
assert get_origin(t) is list
|
|
166
|
+
|
|
167
|
+
args = get_args(t)
|
|
168
|
+
assert len(args) > 0
|
|
169
|
+
|
|
170
|
+
sub_type = args[0]
|
|
171
|
+
res = [parse_value(sub_type, x) for x in v]
|
|
172
|
+
return [x[0] for x in res], [x[1] for x in res]
|
|
173
|
+
|
|
174
|
+
assert isinstance(v, dict), v
|
|
175
|
+
assert is_dataclass(t), t
|
|
176
|
+
|
|
177
|
+
ret = {}
|
|
178
|
+
defaults = {}
|
|
179
|
+
fs = {identifier_from_str(f.name): f for f in fields(t)}
|
|
180
|
+
|
|
181
|
+
for k, x in v.items():
|
|
182
|
+
sanitized = identifier_from_str(k)
|
|
183
|
+
assert sanitized in fs, sanitized
|
|
184
|
+
val, default = parse_value(fs[sanitized].type, x)
|
|
185
|
+
ret[sanitized] = val
|
|
186
|
+
defaults[sanitized] = default
|
|
187
|
+
|
|
188
|
+
return t(**ret), t(**defaults)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def is_list_type(typ: Type) -> TypeGuard[Type[List]]:
|
|
192
|
+
return get_origin(typ) is list
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def dataclass_repr(typ: Type, *, make_optionals: bool = False) -> str:
|
|
196
|
+
assert is_dataclass(typ)
|
|
197
|
+
|
|
198
|
+
lines = ["@dataclass", f"class {typ.__name__}:"]
|
|
199
|
+
for f in fields(typ):
|
|
200
|
+
t = f.type
|
|
201
|
+
if make_optionals:
|
|
202
|
+
t = Optional[t]
|
|
203
|
+
|
|
204
|
+
lines.append(f" {f.name}: {type_repr(t)}")
|
|
205
|
+
|
|
206
|
+
return "\n".join(lines) + "\n\n\n"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_preamble(typ: Type, *, make_optionals: bool = False) -> str:
|
|
210
|
+
if get_origin(typ) is Annotated:
|
|
211
|
+
args = get_args(typ)
|
|
212
|
+
assert len(args) > 0
|
|
213
|
+
return get_preamble(args[0], make_optionals=make_optionals)
|
|
214
|
+
|
|
215
|
+
if is_primitive_type(typ) or typ in {LatchFile, LatchDir}:
|
|
216
|
+
return ""
|
|
217
|
+
|
|
218
|
+
if get_origin(typ) in {Union, list}:
|
|
219
|
+
return "".join(
|
|
220
|
+
[get_preamble(t, make_optionals=make_optionals) for t in get_args(typ)]
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
assert is_dataclass(typ), typ
|
|
224
|
+
|
|
225
|
+
preambles = []
|
|
226
|
+
for f in fields(typ):
|
|
227
|
+
t = f.type
|
|
228
|
+
if make_optionals:
|
|
229
|
+
t = Optional[f.type]
|
|
230
|
+
|
|
231
|
+
preambles.append(get_preamble(t, make_optionals=make_optionals))
|
|
232
|
+
|
|
233
|
+
preamble = "".join(preambles)
|
|
234
|
+
|
|
235
|
+
return "".join([preamble, dataclass_repr(typ, make_optionals=make_optionals)])
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
from dataclasses import fields
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Any, Dict, Optional, Type, TypeVar, Union, get_args
|
|
4
|
+
from typing import Any, Dict, List, Optional, Type, TypeVar, Union, get_args
|
|
5
5
|
|
|
6
6
|
import click
|
|
7
7
|
from flyteidl.admin.launch_plan_pb2 import LaunchPlan as _idl_admin_LaunchPlan
|
|
@@ -292,7 +292,7 @@ RegistrableEntity = Union[
|
|
|
292
292
|
]
|
|
293
293
|
|
|
294
294
|
|
|
295
|
-
def should_register_with_admin(entity:
|
|
295
|
+
def should_register_with_admin(entity: FlyteSerializableModel) -> bool:
|
|
296
296
|
return isinstance(entity, get_args(RegistrableEntity))
|
|
297
297
|
|
|
298
298
|
|
|
@@ -327,15 +327,29 @@ def serialize(
|
|
|
327
327
|
)
|
|
328
328
|
admin_lp = get_serializable_launch_plan(lp, settings, registrable_entity_cache)
|
|
329
329
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
330
|
+
click.secho(
|
|
331
|
+
"\nBuilding flyte models: \x1b[?25l",
|
|
332
|
+
nl=False,
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
registrable_entities = []
|
|
336
|
+
i = 0
|
|
337
|
+
for x in list(registrable_entity_cache.values()) + [admin_lp]:
|
|
338
|
+
progress_str = f"{i + 1}/{len(registrable_entity_cache) + 1}"
|
|
339
|
+
|
|
340
|
+
click.echo("\x1b[0K", nl=False)
|
|
341
|
+
click.secho(progress_str, dim=True, italic=True, nl=False)
|
|
342
|
+
click.echo(f"\x1b[{len(progress_str)}D", nl=False)
|
|
343
|
+
|
|
344
|
+
i += 1
|
|
345
|
+
|
|
346
|
+
if not should_register_with_admin(x):
|
|
347
|
+
continue
|
|
348
|
+
|
|
349
|
+
registrable_entities.append(x.to_flyte_idl())
|
|
337
350
|
|
|
338
351
|
click.secho("\nSerializing workflow entities", bold=True)
|
|
352
|
+
|
|
339
353
|
persist_registrable_entities(registrable_entities, output_dir)
|
|
340
354
|
|
|
341
355
|
if not write_spec:
|
|
@@ -3,7 +3,7 @@ from typing import Type, Union, get_args, get_origin
|
|
|
3
3
|
|
|
4
4
|
from typing_extensions import Annotated, TypeGuard
|
|
5
5
|
|
|
6
|
-
from latch.types.directory import LatchDir
|
|
6
|
+
from latch.types.directory import LatchDir, LatchOutputDir
|
|
7
7
|
from latch.types.file import LatchFile
|
|
8
8
|
|
|
9
9
|
|
|
@@ -17,7 +17,7 @@ def reindent(x: str, level: int) -> str:
|
|
|
17
17
|
def is_primitive_type(
|
|
18
18
|
typ: Type,
|
|
19
19
|
) -> TypeGuard[Union[Type[None], Type[str], Type[bool], Type[int], Type[float]]]:
|
|
20
|
-
return typ in {
|
|
20
|
+
return typ in {type(None), str, bool, int, float}
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def is_primitive_value(val: object) -> TypeGuard[Union[None, str, bool, int, float]]:
|
|
@@ -34,6 +34,13 @@ def is_blob_type(typ: Type) -> TypeGuard[Union[Type[LatchFile], Type[LatchDir]]]
|
|
|
34
34
|
return typ in {LatchFile, LatchDir}
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def is_downloadable_blob_type(typ: Type):
|
|
38
|
+
if not is_blob_type(typ):
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
return typ is not LatchOutputDir
|
|
42
|
+
|
|
43
|
+
|
|
37
44
|
def type_repr(t: Type, *, add_namespace: bool = False) -> str:
|
|
38
45
|
if getattr(t, "__name__", None) == "NoneType":
|
|
39
46
|
return "None"
|
|
@@ -19,6 +19,7 @@ from flytekit.models import literals as literals_models
|
|
|
19
19
|
from latch_sdk_gql.execute import execute
|
|
20
20
|
|
|
21
21
|
from latch_cli import tinyrequests
|
|
22
|
+
from latch_cli.extras.common.config.utils import get_preamble
|
|
22
23
|
from latch_cli.extras.nextflow.tasks.base import NextflowBaseTask, NFTaskType
|
|
23
24
|
|
|
24
25
|
from ...click_utils import italic
|
|
@@ -102,7 +103,7 @@ def build_from_nextflow_dag(
|
|
|
102
103
|
|
|
103
104
|
output_name = "res"
|
|
104
105
|
if len(dep.outputNames) > 0:
|
|
105
|
-
idx = int(edge.label)
|
|
106
|
+
idx = int(edge.label or "0")
|
|
106
107
|
input_name = f"{input_name}_{idx}"
|
|
107
108
|
output_name = dep.outputNames[idx]
|
|
108
109
|
|
|
@@ -128,8 +129,6 @@ def build_from_nextflow_dag(
|
|
|
128
129
|
upstream_nodes.append(node_map[dep.id])
|
|
129
130
|
|
|
130
131
|
node_name = get_node_name(vertex.id)
|
|
131
|
-
if vertex.type == VertexType.Merge:
|
|
132
|
-
task_outputs = {k: Optional[str] for k in merge_sources.keys()}
|
|
133
132
|
|
|
134
133
|
if vertex.type == VertexType.Process:
|
|
135
134
|
pre_adapter_task = NextflowProcessPreAdapterTask(
|
|
@@ -513,6 +512,9 @@ def generate_nf_entrypoint(
|
|
|
513
512
|
0,
|
|
514
513
|
)
|
|
515
514
|
|
|
515
|
+
for t in wf.python_interface.inputs.values():
|
|
516
|
+
preamble += get_preamble(t, make_optionals=True)
|
|
517
|
+
|
|
516
518
|
nf_script_path_in_container = nf_script.resolve().relative_to(pkg_root.resolve())
|
|
517
519
|
|
|
518
520
|
entrypoint_code = [preamble]
|
|
@@ -2,7 +2,7 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import subprocess
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import List
|
|
5
|
+
from typing import List, Optional
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
@@ -37,6 +37,7 @@ def generate_nf_metadata(
|
|
|
37
37
|
skip_confirmation: bool = False,
|
|
38
38
|
generate_defaults: bool = False,
|
|
39
39
|
infer_files: bool = False,
|
|
40
|
+
make_optionals: bool = True,
|
|
40
41
|
):
|
|
41
42
|
if not config_path.is_dir():
|
|
42
43
|
click.secho(
|
|
@@ -103,7 +104,10 @@ def generate_nf_metadata(
|
|
|
103
104
|
params: List[str] = []
|
|
104
105
|
|
|
105
106
|
for k, (typ, (val, default)) in parsed.items():
|
|
106
|
-
|
|
107
|
+
if make_optionals:
|
|
108
|
+
typ = Optional[typ]
|
|
109
|
+
|
|
110
|
+
preambles.append(get_preamble(typ, make_optionals=make_optionals))
|
|
107
111
|
|
|
108
112
|
param_str = reindent(
|
|
109
113
|
f"""\
|
|
@@ -47,8 +47,8 @@ class NextflowBaseTask(PythonAutoContainerTask[Pod]):
|
|
|
47
47
|
wf: NextflowWorkflow,
|
|
48
48
|
nf_task_type: NFTaskType,
|
|
49
49
|
# todo(ayush): expose / infer these somehow
|
|
50
|
-
cpu:
|
|
51
|
-
memory:
|
|
50
|
+
cpu: float = 0.5,
|
|
51
|
+
memory: float = 1,
|
|
52
52
|
):
|
|
53
53
|
self.id = id
|
|
54
54
|
self.wf = wf
|
|
@@ -130,7 +130,7 @@ class NextflowOperatorTask(NextflowBaseTask):
|
|
|
130
130
|
if {k} is not None:
|
|
131
131
|
{k}_p = Path({k}).resolve()
|
|
132
132
|
check_exists_and_rename({k}_p, Path("/root") / {k}_p.name)
|
|
133
|
-
wf_paths[{k}] = Path("/root") / {k}_p.name
|
|
133
|
+
wf_paths["{k}"] = Path("/root") / {k}_p.name
|
|
134
134
|
|
|
135
135
|
""",
|
|
136
136
|
2,
|
|
@@ -140,7 +140,7 @@ class NextflowOperatorTask(NextflowBaseTask):
|
|
|
140
140
|
f"""
|
|
141
141
|
if {k} is not None:
|
|
142
142
|
{k}_p = Path("/root/").resolve() # superhack
|
|
143
|
-
wf_paths[{k}] = {k}_p
|
|
143
|
+
wf_paths["{k}"] = {k}_p
|
|
144
144
|
|
|
145
145
|
""",
|
|
146
146
|
2,
|
|
@@ -136,7 +136,7 @@ class NextflowProcessTask(NextflowBaseTask):
|
|
|
136
136
|
if {k} is not None:
|
|
137
137
|
{k}_p = Path({k}).resolve()
|
|
138
138
|
check_exists_and_rename({k}_p, Path("/root") / {k}_p.name)
|
|
139
|
-
wf_paths[{k}] = Path("/root") / {k}_p.name
|
|
139
|
+
wf_paths["{k}"] = Path("/root") / {k}_p.name
|
|
140
140
|
|
|
141
141
|
""",
|
|
142
142
|
1,
|
|
@@ -146,7 +146,7 @@ class NextflowProcessTask(NextflowBaseTask):
|
|
|
146
146
|
f"""
|
|
147
147
|
if {k} is not None:
|
|
148
148
|
{k}_p = Path("/root/").resolve() # superhack
|
|
149
|
-
wf_paths[{k}] = {k}_p
|
|
149
|
+
wf_paths["{k}"] = {k}_p
|
|
150
150
|
|
|
151
151
|
""",
|
|
152
152
|
1,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
from dataclasses import fields, is_dataclass
|
|
1
2
|
from pathlib import Path
|
|
2
|
-
from typing import List
|
|
3
|
+
from typing import Any, Dict, List, Tuple, Type
|
|
3
4
|
|
|
4
5
|
from flytekit.core.class_based_resolver import ClassStorageTaskResolver
|
|
5
6
|
from flytekit.core.docstring import Docstring
|
|
@@ -13,10 +14,32 @@ from flytekit.core.workflow import (
|
|
|
13
14
|
from flytekit.exceptions import scopes as exception_scopes
|
|
14
15
|
|
|
15
16
|
from latch.types import metadata
|
|
16
|
-
from
|
|
17
|
+
from latch_cli.extras.common.utils import is_blob_type, is_downloadable_blob_type
|
|
17
18
|
|
|
18
19
|
from .dag import DAG
|
|
19
20
|
|
|
21
|
+
# def _get_flattened_inputs(
|
|
22
|
+
# key: str, t: Type, val: Any, inputs: Dict[str, Tuple[Type, Any]]
|
|
23
|
+
# ):
|
|
24
|
+
# if not is_dataclass(t):
|
|
25
|
+
# inputs[key] = (t, val)
|
|
26
|
+
# return
|
|
27
|
+
|
|
28
|
+
# for f in fields(t):
|
|
29
|
+
# v = val
|
|
30
|
+
# if val is not None:
|
|
31
|
+
# v = getattr()
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _get_flags_to_params(key: str, t: Type, flags: Dict[str, str]):
|
|
35
|
+
if is_blob_type(t):
|
|
36
|
+
flags[f"--{key}"] = f"wf_paths['wf_{key}']"
|
|
37
|
+
elif is_dataclass(t):
|
|
38
|
+
for f in fields(t):
|
|
39
|
+
_get_flags_to_params(f"{key}.{f.name}", f.type, flags)
|
|
40
|
+
else:
|
|
41
|
+
flags[f"--{key}"] = f"wf_{key}"
|
|
42
|
+
|
|
20
43
|
|
|
21
44
|
class NextflowWorkflow(WorkflowBase, ClassStorageTaskResolver):
|
|
22
45
|
def __init__(self, nf_script: Path, version: str, dag: DAG):
|
|
@@ -39,19 +62,17 @@ class NextflowWorkflow(WorkflowBase, ClassStorageTaskResolver):
|
|
|
39
62
|
docstring=docstring,
|
|
40
63
|
)
|
|
41
64
|
|
|
42
|
-
self.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
)
|
|
48
|
-
for k, v in metadata._nextflow_metadata.parameters.items()
|
|
49
|
-
}
|
|
65
|
+
self.flattened_inputs = {}
|
|
66
|
+
|
|
67
|
+
self.flags_to_params = {}
|
|
68
|
+
for k, v in metadata._nextflow_metadata.parameters.items():
|
|
69
|
+
assert v.type is not None
|
|
70
|
+
_get_flags_to_params(k, v.type, self.flags_to_params)
|
|
50
71
|
|
|
51
72
|
self.downloadable_params = {
|
|
52
|
-
k
|
|
73
|
+
k
|
|
53
74
|
for k, v in metadata._nextflow_metadata.parameters.items()
|
|
54
|
-
if
|
|
75
|
+
if is_downloadable_blob_type(v.type)
|
|
55
76
|
}
|
|
56
77
|
|
|
57
78
|
name = metadata._nextflow_metadata.name
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|