Skip to content

Commit

Permalink
dur
Browse files Browse the repository at this point in the history
Signed-off-by: Ayush Kamat <[email protected]>
  • Loading branch information
ayushkamat committed Nov 8, 2023
1 parent 3d891d0 commit 3fe88fa
Showing 1 changed file with 47 additions and 14 deletions.
61 changes: 47 additions & 14 deletions latch_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import sys
from pathlib import Path
from textwrap import dedent
from typing import List, Optional, Tuple, Union
from typing import Callable, List, Optional, Tuple, TypeVar, Union

import click
from packaging.version import parse as parse_version
from typing_extensions import ParamSpec

import latch_cli.click_utils
from latch_cli.click_utils import EnumChoice
Expand All @@ -30,6 +31,30 @@

crash_handler = CrashHandler()

P = ParamSpec("P")
T = TypeVar("T")


def requires_login(f: Callable[P, T]) -> Callable[P, T]:
def decorated(*args, **kwargs):
try:
get_auth_header()
except AuthenticationError as e:
click.secho(
dedent("""
Unable to authenticate with Latch.
If you are on a machine with a browser, run `latch login`.
If not, navigate to `https://console.latch.bio/settings/developer` on a different machine, select `Access Tokens`, and copy your `API Key` to `~/.latch/token` on this machine.
""").strip("\n"),
fg="red",
)
raise click.exceptions.Exit(1) from e

return f(*args, **kwargs)

return decorated


@click.group(
"latch",
Expand All @@ -43,19 +68,6 @@ def main():
Collection of command line tools for using the Latch SDK and
interacting with the Latch platform.
"""
try:
get_auth_header()
except AuthenticationError as e:
click.secho(
dedent("""
Unable to authenticate with Latch.
If you are on a machine with a browser, run `latch login`.
If not, navigate to `https://console.latch.bio/settings/developer` on a different machine, select `Access Tokens`, and copy your `API Key` to `~/.latch/token` on this machine.
""").strip("\n"),
fg="red",
)
raise click.exceptions.Exit(1) from e

local_ver = parse_version(get_local_package_version())
latest_ver = parse_version(get_latest_package_version())
Expand Down Expand Up @@ -150,6 +162,7 @@ def dockerfile(pkg_root: str, snakemake: bool = False):
default=None,
help="Path to a Snakefile to register.",
)
@requires_login
def register(
pkg_root: str,
disable_auto_version: bool,
Expand Down Expand Up @@ -204,6 +217,7 @@ def register(
type=EnumChoice(TaskSize, case_sensitive=False),
help="Instance size to use for develop session.",
)
@requires_login
def local_development(
pkg_root: Path, yes: bool, image: Optional[str], size: Optional[TaskSize]
):
Expand Down Expand Up @@ -323,6 +337,7 @@ def init(
default=False,
show_default=True,
)
@requires_login
def cp(
src: List[str],
dest: str,
Expand Down Expand Up @@ -357,6 +372,7 @@ def cp(
default=False,
show_default=True,
)
@requires_login
def mv(src: str, dest: str, no_glob: bool):
"""Move remote files in LatchData."""

Expand All @@ -377,6 +393,7 @@ def mv(src: str, dest: str, no_glob: bool):
default=False,
)
@click.argument("paths", nargs=-1, shell_complete=remote_complete)
@requires_login
def ls(paths: Tuple[str], group_directories_first: bool):
"""
List the contents of a Latch Data directory
Expand Down Expand Up @@ -451,6 +468,7 @@ def generate_metadata(
default=None,
help="The version of the workflow to launch. Defaults to latest.",
)
@requires_login
def launch(params_file: Path, version: Union[str, None] = None):
"""Launch a workflow using a python parameter map."""

Expand All @@ -476,6 +494,7 @@ def launch(params_file: Path, version: Union[str, None] = None):
default=None,
help="The version of the workflow. Defaults to latest.",
)
@requires_login
def get_params(wf_name: Union[str, None], version: Union[str, None] = None):
"""Generate a python parameter map for a workflow."""
crash_handler.message = "Unable to generate param map for workflow"
Expand All @@ -499,6 +518,7 @@ def get_params(wf_name: Union[str, None], version: Union[str, None] = None):
default=None,
help="The name of the workflow to list. Will display all versions",
)
@requires_login
def get_wf(name: Union[str, None] = None):
"""List workflows."""
crash_handler.message = "Unable to get workflows"
Expand Down Expand Up @@ -527,6 +547,7 @@ def get_wf(name: Union[str, None] = None):

@main.command("open")
@click.argument("remote_file", nargs=1, type=str)
@requires_login
def open_remote_file(remote_file: str):
"""Open a remote file in the browser."""
crash_handler.message = f"Unable to open {remote_file}"
Expand All @@ -540,6 +561,7 @@ def open_remote_file(remote_file: str):

@main.command("rm")
@click.argument("remote_path", nargs=1, type=str)
@requires_login
def rm(remote_path: str):
"""Deletes a remote entity."""
crash_handler.message = f"Unable to delete {remote_path}"
Expand All @@ -556,6 +578,7 @@ def rm(remote_path: str):

@main.command("mkdir")
@click.argument("remote_directory", nargs=1, type=str)
@requires_login
def mkdir(remote_directory: str):
"""Creates a new remote directory."""
crash_handler.message = f"Unable to create directory {remote_directory}"
Expand All @@ -573,6 +596,7 @@ def mkdir(remote_directory: str):

@main.command("touch")
@click.argument("remote_file", nargs=1, type=str)
@requires_login
def touch(remote_file: str):
"""Creates an empty text file."""
crash_handler.message = f"Unable to create {remote_file}"
Expand All @@ -590,6 +614,7 @@ def touch(remote_file: str):

@main.command("exec")
@click.argument("task_name", nargs=1, type=str)
@requires_login
def execute(task_name: str):
"""Drops the user into an interactive shell from within a task."""
crash_handler.message = f"Unable to exec into {task_name}"
Expand All @@ -602,6 +627,7 @@ def execute(task_name: str):

@main.command("preview")
@click.argument("pkg_root", nargs=1, type=click.Path(exists=True, path_type=Path))
@requires_login
def preview(pkg_root: Path):
"""Creates a preview of your workflow interface."""
crash_handler.message = f"Unable to preview inputs for {pkg_root}"
Expand All @@ -613,6 +639,7 @@ def preview(pkg_root: Path):


@main.command("workspace")
@requires_login
def workspace():
"""Spawns an interactive terminal prompt allowing users to choose what workspace they want to work in."""

Expand All @@ -625,6 +652,7 @@ def workspace():


@main.command("get-executions")
@requires_login
def get_executions():
"""Spawns an interactive terminal UI that shows all executions in a given workspace"""

Expand All @@ -643,6 +671,7 @@ def pods():

@pods.command("stop")
@click.argument("pod_id", nargs=1, type=int, required=False)
@requires_login
def stop_pod(pod_id: Optional[int] = None):
"""Stops a pod given a pod_id or the pod from which the command is run"""
crash_handler.message = "Unable to stop pod"
Expand Down Expand Up @@ -693,6 +722,7 @@ def test_data(ctx: click.Context):
type=bool,
help="Automatically overwrite any files without asking for confirmation.",
)
@requires_login
def test_data_upload(src_path: str, dont_confirm_overwrite: bool):
"""Upload test data object."""

Expand All @@ -707,6 +737,7 @@ def test_data_upload(src_path: str, dont_confirm_overwrite: bool):

@test_data.command("remove")
@click.argument("object_url", nargs=1, type=str)
@requires_login
def test_data_remove(object_url: str):
"""Remove test data object."""

Expand All @@ -720,6 +751,7 @@ def test_data_remove(object_url: str):


@test_data.command("ls")
@requires_login
def test_data_ls():
"""List test data objects."""

Expand Down Expand Up @@ -751,6 +783,7 @@ def test_data_ls():
is_flag=True,
default=False,
)
@requires_login
def sync(srcs: List[str], dst: str, delete: bool, ignore_unsyncable: bool):
"""
Update the contents of a remote directory with local data or vice versa.
Expand Down

0 comments on commit 3fe88fa

Please sign in to comment.