latch 2.76.3__tar.gz → 2.76.4__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.76.3 → latch-2.76.4}/PKG-INFO +5 -4
- {latch-2.76.3 → latch-2.76.4}/pyproject.toml +6 -5
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/file.py +1 -4
- {latch-2.76.3 → latch-2.76.4}/src/latch/utils.py +21 -9
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/centromere/ctx.py +22 -2
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/centromere/utils.py +49 -4
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/constants.py +3 -2
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/main.py +232 -57
- latch-2.76.4/src/latch_cli/services/gql/pod_ssh.graphql +10 -0
- latch-2.76.4/src/latch_cli/services/gql/pods_list.graphql +48 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/local_dev_old.py +11 -18
- latch-2.76.4/src/latch_cli/services/login.py +160 -0
- latch-2.76.4/src/latch_cli/services/pods.py +435 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/register/register.py +14 -2
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/register/utils.py +19 -2
- latch-2.76.4/src/latch_cli/services/stop_pod.py +3 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/workspace.py +28 -6
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/serialize.py +14 -25
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/utils/__init__.py +13 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_config/latch.py +0 -11
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_gql/execute.py +6 -2
- latch-2.76.3/src/latch_cli/services/launch.py +0 -262
- latch-2.76.3/src/latch_cli/services/login.py +0 -95
- latch-2.76.3/src/latch_cli/services/stop_pod.py +0 -32
- {latch-2.76.3 → latch-2.76.4}/.gitignore +0 -0
- {latch-2.76.3 → latch-2.76.4}/LICENSE +0 -0
- {latch-2.76.3 → latch-2.76.4}/README.md +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/account.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/executions.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/functions/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/functions/messages.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/functions/operators.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/functions/secrets.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/admin/common.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/admin/launch_plan.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/admin/schedule.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/admin/workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/condition.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/execution.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/identifier.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/interface.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/literals.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/security.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/tasks.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/types.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/core/workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/idl/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/download.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/manager.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/node.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/progress.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/remote_copy.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/throttle.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/upload.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/_transfer/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/path.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/ldata/type.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/py.typed +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/project.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/record.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/table.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/types.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/upstream_types/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/upstream_types/types.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/upstream_types/values.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/registry/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/conditional.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/dynamic.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/launch_plan.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/map_tasks.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/reference_workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/tasks.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/resources/workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/directory.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/glob.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/json.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/metadata.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/plots.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/samplesheet_item.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/types/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/deseq2.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/mafft.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/pathway.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/rnaseq.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch/verified/trim_galore.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/auth/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/auth/csrf.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/auth/oauth2.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/auth/pkce.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/auth/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/centromere/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/centromere/ast_parsing.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/click_utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/docker_utils/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/exceptions/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/exceptions/cache.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/exceptions/errors.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/exceptions/handler.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/exceptions/traceback.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/menus.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/config.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/forch_register.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/parse_schema.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/nextflow/workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/py.typed +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/cp/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/cp/autocomplete.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/cp/glob.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/cp/main.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/cp/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/docker/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/docker/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/get.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/get_executions.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/get_params.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/.env +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/LICENSE +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/README.md +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/assemble.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/sort.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/assemble_and_sort/system-requirements.txt +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/common/.dockerignore +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_conda/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_conda/conda_task.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_conda/environment.yaml +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_docker/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_docker/task.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_nfcore/Dockerfile +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_nfcore/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_nfcore/task.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_r/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_r/environment.R +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_r/r_task.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/.latch/latch_entrypoint +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/Dockerfile +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/Snakefile +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/config.yaml +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/environment.yaml +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/latch_metadata.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/scripts/plot-quals.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/example_snakemake/version +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/init.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/template/LICENSE +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/template/README.md +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/template/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/init/template/task.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/attach.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/develop.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/execute.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/k8s/ws_utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/launch/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/launch/interface.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/launch/launch.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/launch/launch_v2.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/launch/type_converter.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/ls.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/mkdir.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/move.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/preview.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/private_images.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/register/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/register/constants.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/register/staging.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/rm.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/sync.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/test_data/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/test_data/ls.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/test_data/remove.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/test_data/upload.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/services/test_data/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/config/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/config/parser.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/config/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/serialize_utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/single_task_snakemake.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/utils.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/snakemake/workflow.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/tinyrequests.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/tui/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/utils/path.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_cli/workflow_config.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_config/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_config/py.typed +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_config/user.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_gql/__init__.py +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_gql/py.typed +0 -0
- {latch-2.76.3 → latch-2.76.4}/src/latch_sdk_gql/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: latch
|
|
3
|
-
Version: 2.76.
|
|
3
|
+
Version: 2.76.4
|
|
4
4
|
Summary: The Latch SDK
|
|
5
5
|
Project-URL: Homepage, https://latch.bio
|
|
6
6
|
Project-URL: Documentation, https://latch.wiki
|
|
@@ -41,7 +41,6 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
41
41
|
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
42
42
|
Classifier: Topic :: Software Development :: Build Tools
|
|
43
43
|
Requires-Python: >=3.9
|
|
44
|
-
Requires-Dist: aioconsole==0.6.1
|
|
45
44
|
Requires-Dist: apscheduler>=3.10.0
|
|
46
45
|
Requires-Dist: asyncssh==2.13.2
|
|
47
46
|
Requires-Dist: boto3>=1.26.0
|
|
@@ -53,20 +52,22 @@ Requires-Dist: gql==3.5.0
|
|
|
53
52
|
Requires-Dist: graphql-core==3.2.3
|
|
54
53
|
Requires-Dist: kubernetes>=24.2.0
|
|
55
54
|
Requires-Dist: latch-persistence>=0.1.5
|
|
56
|
-
Requires-Dist: lytekit==0.
|
|
55
|
+
Requires-Dist: lytekit==0.16
|
|
57
56
|
Requires-Dist: lytekitplugins-pods==0.7.4
|
|
58
57
|
Requires-Dist: orjson>=3.10.12
|
|
59
58
|
Requires-Dist: paramiko>=3.4.0
|
|
59
|
+
Requires-Dist: pydantic<3,>=2
|
|
60
60
|
Requires-Dist: pyjwt>=0.2.0
|
|
61
61
|
Requires-Dist: python-dateutil>=2.8
|
|
62
62
|
Requires-Dist: pyxattr>=0.8.1
|
|
63
63
|
Requires-Dist: requests-toolbelt==1.0.0
|
|
64
64
|
Requires-Dist: requests>=2.28.1
|
|
65
|
+
Requires-Dist: rich>=14.0.0
|
|
65
66
|
Requires-Dist: scp>=0.14.0
|
|
66
67
|
Requires-Dist: tqdm>=4.63.0
|
|
67
68
|
Requires-Dist: typing-extensions>=4.12.0
|
|
68
69
|
Requires-Dist: watchfiles==1.1.1
|
|
69
|
-
Requires-Dist: websockets
|
|
70
|
+
Requires-Dist: websockets<16,>=11
|
|
70
71
|
Provides-Extra: pandas
|
|
71
72
|
Requires-Dist: pandas>=2.0.0; extra == 'pandas'
|
|
72
73
|
Provides-Extra: snakemake
|
|
@@ -3,7 +3,7 @@ requires = ["hatchling"]
|
|
|
3
3
|
build-backend = "hatchling.build"
|
|
4
4
|
|
|
5
5
|
[tool.hatch.build.targets.sdist]
|
|
6
|
-
include = ["src/**/*.py", "src/**/py.typed", "src/latch_cli/services/init/*"]
|
|
6
|
+
include = ["src/**/*.py", "src/**/*.graphql", "src/**/py.typed", "src/latch_cli/services/init/*"]
|
|
7
7
|
|
|
8
8
|
[tool.hatch.build.targets.wheel.force-include]
|
|
9
9
|
"src/latch_cli" = "latch_cli"
|
|
@@ -12,7 +12,7 @@ include = ["src/**/*.py", "src/**/py.typed", "src/latch_cli/services/init/*"]
|
|
|
12
12
|
|
|
13
13
|
[project]
|
|
14
14
|
name = "latch"
|
|
15
|
-
version = "2.76.
|
|
15
|
+
version = "2.76.4"
|
|
16
16
|
description = "The Latch SDK"
|
|
17
17
|
authors = [{ name = "Kenny Workman", email = "kenny@latch.bio" }]
|
|
18
18
|
maintainers = [{ name = "Kenny Workman", email = "kenny@latch.bio" }]
|
|
@@ -31,7 +31,7 @@ dependencies = [
|
|
|
31
31
|
"scp>=0.14.0",
|
|
32
32
|
"boto3>=1.26.0",
|
|
33
33
|
"tqdm>=4.63.0",
|
|
34
|
-
"lytekit==0.
|
|
34
|
+
"lytekit==0.16",
|
|
35
35
|
"lytekitplugins-pods==0.7.4",
|
|
36
36
|
"typing-extensions>=4.12.0",
|
|
37
37
|
"apscheduler>=3.10.0",
|
|
@@ -39,11 +39,12 @@ dependencies = [
|
|
|
39
39
|
"graphql-core==3.2.3",
|
|
40
40
|
"requests-toolbelt==1.0.0",
|
|
41
41
|
"python-dateutil>=2.8",
|
|
42
|
+
"pydantic>=2,<3",
|
|
43
|
+
"rich>=14.0.0",
|
|
42
44
|
"GitPython==3.1.40",
|
|
43
45
|
# for old latch develop, to be removed
|
|
44
|
-
"aioconsole==0.6.1",
|
|
45
46
|
"asyncssh==2.13.2",
|
|
46
|
-
"websockets>=
|
|
47
|
+
"websockets>=11,<16",
|
|
47
48
|
"watchfiles==1.1.1",
|
|
48
49
|
"pyxattr>=0.8.1",
|
|
49
50
|
"orjson>=3.10.12",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from os import PathLike
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import Annotated, Optional, Union
|
|
4
|
+
from typing import Annotated, Optional, Union
|
|
5
5
|
from urllib.parse import urlparse
|
|
6
6
|
|
|
7
7
|
import gql
|
|
@@ -249,9 +249,6 @@ class LatchFilePathTransformer(FlyteFilePathTransformer):
|
|
|
249
249
|
"Casting from Pathlike to LatchFile is currently not supported."
|
|
250
250
|
)
|
|
251
251
|
|
|
252
|
-
while get_origin(expected_python_type) == Annotated:
|
|
253
|
-
expected_python_type = get_args(expected_python_type)[0]
|
|
254
|
-
|
|
255
252
|
if not issubclass(expected_python_type, LatchFile):
|
|
256
253
|
raise TypeError(
|
|
257
254
|
f"Neither os.PathLike nor LatchFile specified {expected_python_type}"
|
|
@@ -4,27 +4,39 @@ from typing import Dict, TypedDict
|
|
|
4
4
|
|
|
5
5
|
import gql
|
|
6
6
|
import jwt
|
|
7
|
+
|
|
7
8
|
from latch_sdk_config.user import user_config
|
|
8
9
|
from latch_sdk_gql.execute import execute
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def account_id_from_token(token: str) -> str:
|
|
12
|
-
"""
|
|
13
|
+
"""Resolve the Latch account ID associated with ``token``.
|
|
13
14
|
|
|
14
15
|
Latch account IDs are needed for any user-specific request, eg. register
|
|
15
16
|
workflows or copy files to Latch.
|
|
16
17
|
|
|
17
18
|
Args:
|
|
18
|
-
token:
|
|
19
|
+
token: A Latch SDK token.
|
|
19
20
|
|
|
20
21
|
Returns:
|
|
21
|
-
A Latch account ID
|
|
22
|
+
A Latch account ID.
|
|
22
23
|
"""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
|
|
25
|
+
res = execute(
|
|
26
|
+
gql.gql("""
|
|
27
|
+
query AccountIdFromToken {
|
|
28
|
+
accountInfoCurrent {
|
|
29
|
+
id
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
""")
|
|
33
|
+
)
|
|
34
|
+
aic = res.get("accountInfoCurrent")
|
|
35
|
+
if aic is None or aic.get("id") is None:
|
|
36
|
+
raise ValueError(
|
|
37
|
+
"Your Latch access token is invalid or could not be resolved to an account."
|
|
38
|
+
)
|
|
39
|
+
return aic["id"]
|
|
28
40
|
|
|
29
41
|
|
|
30
42
|
def retrieve_or_login() -> str:
|
|
@@ -170,7 +182,7 @@ def current_workspace() -> str:
|
|
|
170
182
|
}
|
|
171
183
|
}
|
|
172
184
|
}
|
|
173
|
-
""")
|
|
185
|
+
""")
|
|
174
186
|
)["accountInfoCurrent"]
|
|
175
187
|
|
|
176
188
|
if res is not None:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from logging import getLogger
|
|
1
2
|
import re
|
|
2
3
|
import sys
|
|
3
4
|
import traceback
|
|
@@ -30,6 +31,8 @@ from latch_cli.utils import (
|
|
|
30
31
|
)
|
|
31
32
|
from latch_sdk_config.latch import config
|
|
32
33
|
|
|
34
|
+
log = getLogger(__name__)
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
@dataclass
|
|
35
38
|
class _Container:
|
|
@@ -91,12 +94,14 @@ class _CentromereCtx:
|
|
|
91
94
|
use_new_centromere: bool = False,
|
|
92
95
|
overwrite: bool = False,
|
|
93
96
|
dockerfile_path: Optional[Path] = None,
|
|
97
|
+
account_id: Optional[str] = None,
|
|
94
98
|
):
|
|
95
99
|
self.use_new_centromere = use_new_centromere
|
|
96
100
|
self.remote = remote
|
|
97
101
|
self.disable_auto_version = disable_auto_version
|
|
98
102
|
self.wf_module = wf_module if wf_module is not None else "wf"
|
|
99
103
|
|
|
104
|
+
log.debug("Initializing CentromereCtx")
|
|
100
105
|
if self.wf_module.startswith("."):
|
|
101
106
|
click.secho(
|
|
102
107
|
dedent(f"""\
|
|
@@ -107,10 +112,15 @@ class _CentromereCtx:
|
|
|
107
112
|
raise click.exceptions.Exit(1)
|
|
108
113
|
|
|
109
114
|
try:
|
|
115
|
+
log.debug("retrieve_or_login")
|
|
110
116
|
self.token = retrieve_or_login()
|
|
111
|
-
|
|
117
|
+
log.debug("current_workspace")
|
|
118
|
+
self.account_id = (
|
|
119
|
+
account_id if account_id is not None else current_workspace()
|
|
120
|
+
)
|
|
112
121
|
|
|
113
122
|
self.dkr_repo = config.dkr_repo
|
|
123
|
+
log.debug("resolving pkg_root")
|
|
114
124
|
self.pkg_root = pkg_root.resolve()
|
|
115
125
|
|
|
116
126
|
if snakefile is not None and nf_script is not None:
|
|
@@ -131,6 +141,7 @@ class _CentromereCtx:
|
|
|
131
141
|
else:
|
|
132
142
|
self.workflow_type = WorkflowType.latchbiosdk
|
|
133
143
|
|
|
144
|
+
log.debug("Determining version")
|
|
134
145
|
version_file = self.pkg_root / "version"
|
|
135
146
|
try:
|
|
136
147
|
self.version = version_file.read_text()
|
|
@@ -143,6 +154,7 @@ class _CentromereCtx:
|
|
|
143
154
|
|
|
144
155
|
self.version = self.version.strip()
|
|
145
156
|
|
|
157
|
+
log.debug("Loading the git repo")
|
|
146
158
|
try:
|
|
147
159
|
from git import GitError, Repo
|
|
148
160
|
|
|
@@ -162,6 +174,7 @@ class _CentromereCtx:
|
|
|
162
174
|
fg="yellow",
|
|
163
175
|
)
|
|
164
176
|
|
|
177
|
+
log.debug("Auto-versioning")
|
|
165
178
|
if not self.disable_auto_version:
|
|
166
179
|
hash = ""
|
|
167
180
|
|
|
@@ -198,6 +211,7 @@ class _CentromereCtx:
|
|
|
198
211
|
),
|
|
199
212
|
)
|
|
200
213
|
|
|
214
|
+
log.debug("Loading Flyte objects")
|
|
201
215
|
try:
|
|
202
216
|
if not module_path.exists():
|
|
203
217
|
click.secho(error_msg, fg="red")
|
|
@@ -426,6 +440,7 @@ class _CentromereCtx:
|
|
|
426
440
|
self.ssh_key_path, add_to_agent=False
|
|
427
441
|
)
|
|
428
442
|
|
|
443
|
+
log.debug("use_new_centromere=%s", use_new_centromere)
|
|
429
444
|
if use_new_centromere:
|
|
430
445
|
self.internal_ip, self.username = (
|
|
431
446
|
self.provision_register_deployment()
|
|
@@ -448,6 +463,7 @@ class _CentromereCtx:
|
|
|
448
463
|
def _patched_connect(self): ...
|
|
449
464
|
|
|
450
465
|
def _patched_create_paramiko_client(self, base_url):
|
|
466
|
+
log.debug("_patched_create_paramiko_client")
|
|
451
467
|
self.ssh_client = ssh_client
|
|
452
468
|
|
|
453
469
|
SSHHTTPAdapter._create_paramiko_client = _patched_create_paramiko_client
|
|
@@ -514,6 +530,7 @@ class _CentromereCtx:
|
|
|
514
530
|
return f"{self.image}:{self.version}"
|
|
515
531
|
|
|
516
532
|
def task_image_name(self, task_name: str) -> str:
|
|
533
|
+
log.debug("task_image_name: %s", task_name)
|
|
517
534
|
task_name = identifier_suffix_from_str(task_name).lower()
|
|
518
535
|
task_name = docker_image_name_illegal_pat.sub("_", task_name)
|
|
519
536
|
|
|
@@ -555,6 +572,7 @@ class _CentromereCtx:
|
|
|
555
572
|
|
|
556
573
|
def provision_register_deployment(self) -> Tuple[str, str]:
|
|
557
574
|
"""Retrieve centromere IP + username."""
|
|
575
|
+
log.debug("provision_register_deployment")
|
|
558
576
|
click.echo("Provisioning register instance. This may take a few minutes.")
|
|
559
577
|
|
|
560
578
|
assert self.ssh_key_path is not None
|
|
@@ -610,9 +628,11 @@ class _CentromereCtx:
|
|
|
610
628
|
def nucleus_check_version(self, version: str, workflow_name: str) -> bool:
|
|
611
629
|
"""Check if version has already been registered for given workflow"""
|
|
612
630
|
|
|
631
|
+
log.debug("nucleus_check_version")
|
|
632
|
+
|
|
613
633
|
headers = {"Authorization": f"Bearer {self.token}"}
|
|
614
634
|
|
|
615
|
-
ws_id =
|
|
635
|
+
ws_id = self.account_id
|
|
616
636
|
if ws_id is None or ws_id == "":
|
|
617
637
|
ws_id = account_id_from_token(retrieve_or_login())
|
|
618
638
|
|
|
@@ -6,6 +6,7 @@ import string
|
|
|
6
6
|
import sys
|
|
7
7
|
import tempfile
|
|
8
8
|
from dataclasses import dataclass
|
|
9
|
+
from logging import getLogger
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from types import ModuleType
|
|
11
12
|
from typing import Callable, Iterator, List, Optional, TypeVar
|
|
@@ -17,6 +18,8 @@ from typing_extensions import ParamSpec
|
|
|
17
18
|
|
|
18
19
|
from latch_cli.constants import latch_constants
|
|
19
20
|
|
|
21
|
+
log = getLogger(__name__)
|
|
22
|
+
|
|
20
23
|
|
|
21
24
|
@dataclass
|
|
22
25
|
class RemoteConnInfo:
|
|
@@ -109,6 +112,7 @@ def _construct_dkr_client(ssh_host: Optional[str] = None):
|
|
|
109
112
|
If `ssh_host` is passed, we attempt to make a connection with a remote
|
|
110
113
|
machine.
|
|
111
114
|
"""
|
|
115
|
+
log.debug("Creating docker client: %s", ssh_host)
|
|
112
116
|
|
|
113
117
|
def _from_env():
|
|
114
118
|
host = environment.get("DOCKER_HOST")
|
|
@@ -124,6 +128,8 @@ def _construct_dkr_client(ssh_host: Optional[str] = None):
|
|
|
124
128
|
|
|
125
129
|
enable_tls = tls_verify or cert_path is not None
|
|
126
130
|
|
|
131
|
+
log.debug("Determined Docker host from environment: %s", host)
|
|
132
|
+
|
|
127
133
|
dkr_client = None
|
|
128
134
|
try:
|
|
129
135
|
if not enable_tls:
|
|
@@ -164,8 +170,19 @@ def _construct_dkr_client(ssh_host: Optional[str] = None):
|
|
|
164
170
|
if host is not None and host != "":
|
|
165
171
|
return _from_env()
|
|
166
172
|
else:
|
|
173
|
+
try:
|
|
174
|
+
base_url = f"unix:/{Path.home()}/.docker/run/docker.sock"
|
|
175
|
+
log.debug(
|
|
176
|
+
"Using default Docker host: unix://$HOME/run/docker.sock (%s)", base_url
|
|
177
|
+
)
|
|
178
|
+
return docker.APIClient(base_url=base_url)
|
|
179
|
+
except docker.errors.DockerException:
|
|
180
|
+
tracebac
|
|
181
|
+
pass
|
|
182
|
+
|
|
167
183
|
try:
|
|
168
184
|
# TODO: platform specific socket defaults
|
|
185
|
+
log.debug("Using default Docker host: unix://var/run/docker.sock")
|
|
169
186
|
return docker.APIClient(base_url="unix://var/run/docker.sock")
|
|
170
187
|
except docker.errors.DockerException as de:
|
|
171
188
|
raise OSError(
|
|
@@ -177,40 +194,66 @@ def _construct_dkr_client(ssh_host: Optional[str] = None):
|
|
|
177
194
|
def _construct_ssh_client(
|
|
178
195
|
remote_conn_info: RemoteConnInfo, *, use_gateway: bool = True
|
|
179
196
|
) -> paramiko.SSHClient:
|
|
197
|
+
log.debug(
|
|
198
|
+
"_construct_ssh_client conn_info=%s use_gateway=%s",
|
|
199
|
+
remote_conn_info,
|
|
200
|
+
use_gateway,
|
|
201
|
+
)
|
|
202
|
+
|
|
180
203
|
if use_gateway:
|
|
181
204
|
gateway = paramiko.SSHClient()
|
|
205
|
+
|
|
206
|
+
log.debug("Loading system host keys")
|
|
182
207
|
gateway.load_system_host_keys()
|
|
208
|
+
|
|
209
|
+
log.debug("Setting missing host key policy")
|
|
183
210
|
gateway.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy)
|
|
184
211
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
)
|
|
212
|
+
path = str(remote_conn_info.jump_key_path.resolve())
|
|
213
|
+
log.debug("Loading public key from %s", path)
|
|
214
|
+
gateway_pkey = paramiko.PKey.from_path(path=path)
|
|
188
215
|
|
|
216
|
+
log.debug(
|
|
217
|
+
"Connecting to gateway: %s@%s",
|
|
218
|
+
latch_constants.jump_user,
|
|
219
|
+
latch_constants.jump_host,
|
|
220
|
+
)
|
|
189
221
|
gateway.connect(
|
|
190
222
|
latch_constants.jump_host,
|
|
191
223
|
username=latch_constants.jump_user,
|
|
192
224
|
pkey=gateway_pkey,
|
|
193
225
|
)
|
|
194
226
|
|
|
227
|
+
log.debug("Getting gateway transport")
|
|
195
228
|
gateway_transport = gateway.get_transport()
|
|
196
229
|
if gateway_transport is None:
|
|
197
230
|
raise ConnectionError("unable to create connection to jump host")
|
|
198
231
|
|
|
232
|
+
log.debug("Opening gateway channel")
|
|
199
233
|
sock = gateway_transport.open_channel(
|
|
200
234
|
kind="direct-tcpip", dest_addr=(remote_conn_info.ip, 22), src_addr=("", 0)
|
|
201
235
|
)
|
|
202
236
|
else:
|
|
203
237
|
sock = None
|
|
204
238
|
|
|
205
|
-
|
|
239
|
+
path = str(remote_conn_info.ssh_key_path.resolve())
|
|
240
|
+
log.debug("Loading public key")
|
|
241
|
+
pkey = paramiko.PKey.from_path(path=path)
|
|
206
242
|
|
|
207
243
|
ssh = paramiko.SSHClient()
|
|
244
|
+
|
|
245
|
+
log.debug("Loading system host keys")
|
|
208
246
|
ssh.load_system_host_keys()
|
|
247
|
+
|
|
248
|
+
log.debug("Setting missing host key policy")
|
|
209
249
|
ssh.set_missing_host_key_policy(paramiko.MissingHostKeyPolicy)
|
|
250
|
+
|
|
251
|
+
log.debug("Connecting to remote")
|
|
210
252
|
ssh.connect(
|
|
211
253
|
remote_conn_info.ip, username=remote_conn_info.username, sock=sock, pkey=pkey
|
|
212
254
|
)
|
|
213
255
|
|
|
256
|
+
log.debug("Getting transport")
|
|
214
257
|
transport = ssh.get_transport()
|
|
215
258
|
if transport is None:
|
|
216
259
|
raise ConnectionError(
|
|
@@ -219,6 +262,7 @@ def _construct_ssh_client(
|
|
|
219
262
|
|
|
220
263
|
# (kenny) Equivalent of OpenSSH configuration `ServerAliveInterval`
|
|
221
264
|
# No analogue for `ServerAliveCountMax` in paramiko I could find.
|
|
265
|
+
log.debug("Setting Keep-Alive")
|
|
222
266
|
transport.set_keepalive(latch_constants.centromere_keepalive_interval)
|
|
223
267
|
|
|
224
268
|
return ssh
|
|
@@ -242,6 +286,7 @@ class MaybeRemoteDir:
|
|
|
242
286
|
self.reconnect_info = reconnect_info
|
|
243
287
|
|
|
244
288
|
def __enter__(self):
|
|
289
|
+
log.debug("MaybeRemoteDir.__enter__")
|
|
245
290
|
return self.create()
|
|
246
291
|
|
|
247
292
|
def __exit__(self, exc_type, exc_value, tb):
|
|
@@ -57,10 +57,11 @@ latch_constants = LatchConstants()
|
|
|
57
57
|
|
|
58
58
|
@dataclass(frozen=True)
|
|
59
59
|
class OAuth2Constants:
|
|
60
|
-
client_id: str = "
|
|
60
|
+
client_id: str = "UQs8mV2SvKLrPkcI5dt3nmsnrdZvPUs0"
|
|
61
61
|
"""Identifies the authentication server in 0Auth2.0 flow"""
|
|
62
62
|
|
|
63
|
-
authz_server_host: str = "https://
|
|
63
|
+
authz_server_host: str = "https://auth.latch.bio"
|
|
64
|
+
|
|
64
65
|
"""Host of the authentication server used in 0Auth2.0 flow."""
|
|
65
66
|
|
|
66
67
|
redirect_url: str = "http://127.0.0.1:5050/callback"
|