diff --git a/src/neptune_scale/cli/main.py b/src/neptune_scale/cli/main.py index 8e4921d..0dc0f3e 100644 --- a/src/neptune_scale/cli/main.py +++ b/src/neptune_scale/cli/main.py @@ -13,40 +13,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from pathlib import Path -from typing import Optional - import click -from neptune_scale.cli import ( - misc, - sync, -) -from neptune_scale.storage.operations import DATA_DIR +from neptune_scale.cli import sync from neptune_scale.util.styles import ensure_style_detected @click.group() -@click.option( - "--path", - type=click.Path(exists=True, file_okay=False), - help="Path containing Neptune data. Defaults to $CWD/.neptune", -) -@click.pass_context -def main(ctx: click.Context, path: Optional[str]) -> None: +def main() -> None: ensure_style_detected() - ctx.ensure_object(dict) - if path is None: - neptune_dir = Path(".") / DATA_DIR - else: - neptune_dir = Path(path) - - ctx.obj["neptune_dir"] = neptune_dir - main.add_command(sync.sync) -main.add_command(misc.status) if __name__ == "__main__": main() diff --git a/src/neptune_scale/cli/misc.py b/src/neptune_scale/cli/misc.py deleted file mode 100644 index b19f293..0000000 --- a/src/neptune_scale/cli/misc.py +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2025, Neptune Labs Sp. z o.o. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys - -import click - -from neptune_scale.cli.util import ( - format_local_run, - is_neptune_dir, -) -from neptune_scale.storage.operations import list_runs - - -@click.command() -@click.pass_context -def status(ctx: click.Context) -> None: - """Display information on runs stored locally.""" - if not is_neptune_dir(ctx.obj["neptune_dir"]): - sys.exit(1) - - for run in list_runs(ctx.obj["neptune_dir"]): - print(f"Run {run.run_id}:") - line = format_local_run(run, with_run_id=False) - print(line, end="\n\n") diff --git a/src/neptune_scale/cli/sync.py b/src/neptune_scale/cli/sync.py index 54547d1..4f2291b 100644 --- a/src/neptune_scale/cli/sync.py +++ b/src/neptune_scale/cli/sync.py @@ -38,7 +38,6 @@ from neptune_scale.cli.util import ( format_duration, format_local_run, - is_neptune_dir, ) from neptune_scale.exceptions import ( NeptuneRunDuplicate, @@ -224,11 +223,10 @@ def _verify_fork_parent(local_run: LocalRun, parent_must_exist: bool) -> None: This can happen if the parent run was created in offline mode and is not yet synced to the Neptune backend. -Run {bash}neptune status -v{end} to list all local runs, and manually sync the parent -run first using {bash}neptune sync {end}. +Before syncing this run, you need manually sync the parent run first using {bash}neptune sync {end}. Alternatively you can run {bash}neptune sync --sync-no-parent{end} to ignore this error, -and proceed with syncing the without the parent run. +and proceed with syncing without the parent run. """ raise Exception(msg.format(fork_run_id=local_run.fork_run_id, **STYLES)) @@ -306,12 +304,10 @@ def sync_file( "are stuck on a metric being sent multiple times. ", ) @click.option("--sync-no-parent", is_flag=True, help="Do not require the parent run to exist when syncing forked runs") -@click.pass_context def sync( - ctx: click.Context, - filename: Optional[str], - api_token: Optional[str], + filename: Path, keep: bool, + api_token: Optional[str], allow_non_increasing_step: bool, sync_no_parent: bool, ) -> None: @@ -322,41 +318,24 @@ def sync( means that the process can be interrupted and resumed later. """ - neptune_dir = ctx.obj["neptune_dir"] - if not is_neptune_dir(neptune_dir): - logger.error(f"No Neptune data found at {neptune_dir}") - sys.exit(1) - t0 = time.monotonic() - if filename: - files = [Path(filename)] - # For the time being we're not allowing to sync the entire directory, because of the potential for - # users to make mistakes in terms of forked runs and missing parents. - # else: - # files = [run.path for run in list_runs(ctx.obj["neptune_dir"])] - - if not files: - logger.info("No data to sync") - sys.exit(1) - logger.info("Starting `neptune sync`") error = False - for path in files: - try: - sync_file( - path, - api_token=api_token, - allow_non_increasing_step=allow_non_increasing_step, - parent_must_exist=not sync_no_parent, - ) - if not keep: - logger.info(f"Removing file {path}") - path.unlink() - except Exception as e: - logger.error("An error occurred during `neptune sync`: %s", e) - error = True + try: + sync_file( + filename, + api_token=api_token, + allow_non_increasing_step=allow_non_increasing_step, + parent_must_exist=not sync_no_parent, + ) + if not keep: + logger.info(f"Removing file {filename}") + filename.unlink() + except Exception as e: + logger.error("An error occurred during `neptune sync`: %s", e) + error = True duration = format_duration(int(time.monotonic() - t0)) if error: diff --git a/src/neptune_scale/cli/util.py b/src/neptune_scale/cli/util.py index 864de24..3f796c3 100644 --- a/src/neptune_scale/cli/util.py +++ b/src/neptune_scale/cli/util.py @@ -50,27 +50,25 @@ def format_duration(seconds: int) -> str: return " ".join(parts) -def format_local_run(run: LocalRun, with_run_id: bool = True) -> str: +def format_local_run(run: LocalRun) -> str: if run.operation_count: pct = round(run.last_synced_operation / run.operation_count * 100, 2) else: pct = 100.0 parts = [ + f"Run ID: {run.run_id}", f"Project: {run.project}", - f"Synced: {run.last_synced_operation}/{run.operation_count} ({pct}%)", + f"Synced: {run.last_synced_operation}/{run.operation_count} operations ({pct}%)", f"Created at: {run.creation_time}", ] - if with_run_id: - parts.insert(0, f"Run ID: {run.run_id}") - if run.experiment_name: parts.append(f"Experiment: {run.experiment_name}") if run.fork_run_id: parts.append(f"Forked from `{run.fork_run_id}` at step {run.fork_step}") - parts.append(f"Path: {run.path}") + # parts.append(f"Path: {run.path}") text = "\n".join(f" - {part}" for part in parts) return text