Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ dependencies = [
# marshmallow_jsonschema depends on setuptools but doesn't specify it so we have to do it for them yay :D
"setuptools>=75.3.0",
"pyxattr>=0.8.1",
"uvloop>=0.21.0",
"aiohttp>=3.11.7",
"orjson>=3.10.12",
"latch-persistence>=0.1.5",
"dill>=0.4.0",
Expand Down
2 changes: 1 addition & 1 deletion src/latch/ldata/_transfer/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def upload(
dest_data = node_data.data[dest]

if not (dest_data.exists() or dest_data.is_direct_parent()) and not create_parents:
raise LatchPathError("no such Latch file or directory", dest)
raise LatchPathError("no such Latch file or directory", dest, node_data.acc_id)

dest_is_dir = dest_data.type in {
LDataNodeType.account_root,
Expand Down
2 changes: 1 addition & 1 deletion src/latch/ldata/type.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class LatchPathError(RuntimeError):
def __init__(
self,
message: str,
remote_path: Optional[str] = None,
remote_path: str,
acc_id: Optional[str] = None,
):
super().__init__(message)
Expand Down
67 changes: 13 additions & 54 deletions src/latch_cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
import traceback
from pathlib import Path
from textwrap import dedent
from typing import Callable, Optional, TypeVar, Union
from typing import Callable, Literal, Optional, TypeVar, Union

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

import latch_cli.click_utils
from latch.ldata._transfer.progress import Progress as _Progress # noqa: PLC2701
from latch.utils import current_workspace
from latch_cli.click_utils import EnumChoice
from latch_cli.exceptions.handler import CrashHandler
from latch_cli.services.cp.autocomplete import complete as cp_complete
from latch_cli.services.cp.autocomplete import remote_complete
from latch_cli.services.init.init import template_flag_to_option
Expand All @@ -35,7 +33,6 @@

latch_cli.click_utils.patch()

crash_handler = CrashHandler()

P = ParamSpec("P")
T = TypeVar("T")
Expand Down Expand Up @@ -85,8 +82,6 @@ def main():
fg="yellow",
)

crash_handler.init()


"""
LOGIN COMMANDS
Expand All @@ -103,9 +98,6 @@ def main():
def login(connection: Optional[str]):
"""Manually login to Latch."""

crash_handler.message = "Unable to log in"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.login import login

login(connection)
Expand All @@ -117,9 +109,6 @@ def login(connection: Optional[str]):
def workspace():
"""Spawns an interactive terminal prompt allowing users to choose what workspace they want to work in."""

crash_handler.message = "Unable to fetch workspaces"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.workspace import workspace

workspace()
Expand Down Expand Up @@ -159,9 +148,6 @@ def init(
):
"""Initialize boilerplate for local workflow code."""

crash_handler.message = f"Unable to initialize {pkg_name}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.init import init

created = init(pkg_name, template, dockerfile, base_image)
Expand Down Expand Up @@ -499,9 +485,6 @@ def local_development(
Visit docs.latch.bio to learn more.
"""

crash_handler.message = "Error during local development session"
crash_handler.pkg_root = str(pkg_root)

# todo(ayush): purge
if snakemake:
from latch_cli.services.local_dev_old import local_development
Expand Down Expand Up @@ -713,9 +696,6 @@ def register(

use_new_centromere = os.environ.get("LATCH_REGISTER_BETA") is not None

crash_handler.message = "Unable to register workflow."
crash_handler.pkg_root = pkg_root

if nf_script is None and (nf_execution_profile is not None):
click.secho(
"Command Invalid: --execution-profile flag is only valid when registering a"
Expand Down Expand Up @@ -821,9 +801,6 @@ def get_params(wf_name: Union[str, None], version: Union[str, None] = None):
fg="yellow",
)

crash_handler.message = "Unable to generate param map for workflow"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.get_params import get_params

get_params(wf_name, version)
Expand All @@ -845,8 +822,6 @@ def get_params(wf_name: Union[str, None], version: Union[str, None] = None):
@requires_login
def get_wf(name: Union[str, None] = None):
"""List workflows."""
crash_handler.message = "Unable to get workflows"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.get import get_wf

Expand Down Expand Up @@ -874,8 +849,6 @@ def get_wf(name: Union[str, None] = None):
@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}"
crash_handler.pkg_root = str(pkg_root)

from latch_cli.services.preview import preview

Expand All @@ -887,8 +860,6 @@ def preview(pkg_root: Path):
def get_executions():
"""Spawns an interactive terminal UI that shows all executions in a given workspace"""

crash_handler.message = "Unable to fetch executions"

from latch_cli.services.get_executions import get_executions

get_executions()
Expand All @@ -905,7 +876,7 @@ def get_executions():
@click.option(
"--progress",
help="Type of progress information to show while copying",
type=EnumChoice(_Progress, case_sensitive=False),
type=click.Choice(["none", "total", "tasks"]),
default="tasks",
show_default=True,
)
Expand All @@ -917,6 +888,14 @@ def get_executions():
default=False,
show_default=True,
)
@click.option(
"--force",
"-f",
help="Don't ask to confirm when overwriting files",
is_flag=True,
default=False,
show_default=True,
)
@click.option(
"--no-glob",
"-G",
Expand All @@ -937,8 +916,9 @@ def get_executions():
def cp(
src: list[str],
dest: str,
progress: _Progress,
progress: Literal["none", "total", "tasks"],
verbose: bool,
force: bool,
no_glob: bool,
cores: Optional[int] = None,
chunk_size_mib: Optional[int] = None,
Expand All @@ -947,15 +927,14 @@ def cp(

Behaves like `cp -R` in Unix. Directories are copied recursively. If any parents of dest do not exist, the copy will fail.
"""
crash_handler.message = f"Unable to copy {src} to {dest}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.cp.main import cp

cp(
src,
dest,
progress=progress,
force=force,
verbose=verbose,
expand_globs=not no_glob,
cores=cores,
Expand All @@ -978,9 +957,6 @@ def cp(
def mv(src: str, dest: str, no_glob: bool):
"""Move remote files in LatchData."""

crash_handler.message = f"Unable to move {src} to {dest}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.move import move

move(src, dest, no_glob=no_glob)
Expand All @@ -999,9 +975,6 @@ def mv(src: str, dest: str, no_glob: bool):
def ls(paths: tuple[str], group_directories_first: bool):
"""List the contents of a Latch Data directory"""

crash_handler.message = f"Unable to display contents of {paths}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.ls import ls

# If the user doesn't provide any arguments, default to root
Expand Down Expand Up @@ -1047,8 +1020,6 @@ def ls(paths: tuple[str], group_directories_first: bool):
@requires_login
def rmr(remote_path: str, yes: bool, no_glob: bool, verbose: bool):
"""Deletes a remote entity."""
crash_handler.message = f"Unable to delete {remote_path}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.rm import rmr

Expand All @@ -1060,8 +1031,6 @@ def rmr(remote_path: str, yes: bool, no_glob: bool, verbose: bool):
@requires_login
def mkdir(remote_directory: str):
"""Creates a new remote directory."""
crash_handler.message = f"Unable to create directory {remote_directory}"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.mkdir import mkdirp

Expand Down Expand Up @@ -1426,7 +1395,6 @@ def pods():
@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"

from latch_cli.services.stop_pod import stop_pod

Expand Down Expand Up @@ -1480,9 +1448,6 @@ def test_data(ctx: click.Context):
def test_data_upload(src_path: str, dont_confirm_overwrite: bool):
"""Upload test data object."""

crash_handler.message = f"Unable to upload {src_path} to managed bucket"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.test_data.upload import upload

s3_url = upload(src_path, dont_confirm_overwrite)
Expand All @@ -1495,9 +1460,6 @@ def test_data_upload(src_path: str, dont_confirm_overwrite: bool):
def test_data_remove(object_url: str):
"""Remove test data object."""

crash_handler.message = f"Unable to remove {object_url} from managed bucket"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.test_data.remove import remove

remove(object_url)
Expand All @@ -1509,9 +1471,6 @@ def test_data_remove(object_url: str):
def test_data_ls():
"""List test data objects."""

crash_handler.message = "Unable to list objects within managed bucket"
crash_handler.pkg_root = str(Path.cwd())

from latch_cli.services.test_data.ls import ls

objects = ls()
Expand Down
Empty file.
Loading