Skip to content
Open

CLI #72

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f876b16
add cli foundation: errors, output, parsing, aliases
brohoya Mar 29, 2026
8141291
add cli app structure and special commands
brohoya Mar 29, 2026
039abc8
add core cli commands: predict, val, export, train
brohoya Mar 29, 2026
de97f2a
add typer dependency and cli entry point
brohoya Mar 29, 2026
06c8640
add TRAIN_CONFIG class attribute to model classes
brohoya Mar 29, 2026
2a7e667
refactor cli config to auto-discover family defaults from model registry
brohoya Mar 29, 2026
a481992
simplify TRAIN_CONFIG import to direct import
brohoya Mar 29, 2026
985a43a
remove unnecessary TYPE_CHECKING guards where no circular import exists
brohoya Mar 29, 2026
c73292a
show elapsed time in predict human output
brohoya Mar 29, 2026
b325cf5
apply ruff formatting fixes
brohoya Mar 29, 2026
fc17f29
add unified logger with colored output and wire into cli
brohoya Mar 29, 2026
e0b9af6
add cli unit tests for parsing, aliases, config, errors, output
brohoya Mar 29, 2026
7bc6fb3
add cli e2e tests for special commands, predict, train dry-run, export
brohoya Mar 29, 2026
69a9edb
fix rfdetr 1.6.2 compatibility and pin max version
brohoya Mar 29, 2026
3088734
add supports_fp16 attribute to exporters, fix formats display
brohoya Mar 29, 2026
c2ee312
migrate print calls to logger in library modules
brohoya Mar 29, 2026
72fad23
migrate remaining export print calls to logger
brohoya Mar 29, 2026
620f1f1
predict output format with image counter and dimensions
brohoya Mar 29, 2026
f55bb8e
warn and skip half flag in predict (pytorch fp16 inference not yet su…
brohoya Mar 29, 2026
ad5a347
centralize rfdetr lazy registration via try_ensure_rfdetr()
brohoya Mar 30, 2026
de7818e
derive cfg defaults from config dataclasses instead of hardcoding
brohoya Mar 30, 2026
201be1f
auto-build train kwargs from TrainConfig dataclass fields
brohoya Mar 30, 2026
c73aa3c
add tests for build_train_kwargs, get_cfg_defaults, val e2e, multi-fa…
brohoya Mar 30, 2026
ec97fec
preserve model size ordering by parameter count
brohoya Apr 4, 2026
6e229b7
suppress third-party warnings in cli entrypoint
brohoya Apr 4, 2026
7b22c32
suggest valid model names on unknown model in info command
brohoya Apr 4, 2026
c6ec7b5
print output path after predict --save
brohoya Apr 4, 2026
da73ba2
improve --data help text and error suggestions
brohoya Apr 4, 2026
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
156 changes: 156 additions & 0 deletions docs/CLI_TEST_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# CLI Test Checklist

Test commands for the LibreYOLO CLI before merging.
Uses `coco8.yaml` (8 images) for fast training/validation runs.

## Special Commands

```bash
# Help (no args)
libreyolo

# Version
libreyolo version
libreyolo version --json

# System checks
libreyolo checks
libreyolo checks --json

# List models
libreyolo models
libreyolo models --json

# List export formats
libreyolo formats
libreyolo formats --json

# Default config
libreyolo cfg
libreyolo cfg --json

# Model info (downloads yolox-s if not present)
libreyolo info model=yolox-s
libreyolo info model=yolox-s --json
```

## Predict

```bash
# Basic inference
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolox-s

# With conf threshold
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolox-s conf=0.5

# JSON output
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolox-s --json --quiet

# Save annotated image
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolox-s save

# Bare bool flags
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolox-s half save

# --key value syntax (standard CLI)
libreyolo predict --source libreyolo/assets/parkour.jpg --model yolox-s --conf 0.5

# Mixed syntax
libreyolo predict source=libreyolo/assets/parkour.jpg --model yolox-s conf=0.5

# Task prefix (detect is stripped)
libreyolo detect predict source=libreyolo/assets/parkour.jpg model=yolox-s

# YOLOv9 model (auto-downloads)
libreyolo predict source=libreyolo/assets/parkour.jpg model=yolo9-t

# Local weights path
libreyolo predict source=libreyolo/assets/parkour.jpg model=weights/LibreYOLOXs.pt

# Schema discovery
libreyolo predict --help-json
libreyolo predict --help
```

## Train

```bash
# YOLOX — short real training on coco8
libreyolo train data=coco8.yaml model=yolox-s epochs=3 batch=4 imgsz=416

# YOLOX — JSON output
libreyolo train data=coco8.yaml model=yolox-s epochs=3 batch=4 imgsz=416 --json

# YOLOv9 — short real training
libreyolo train data=coco8.yaml model=yolo9-t epochs=3 batch=4

# RF-DETR — short real training
libreyolo train data=coco8.yaml model=rfdetr-s epochs=3 batch=2

# Dry run — verify family defaults without training
libreyolo train data=coco8.yaml model=yolox-s --dry-run --json
libreyolo train data=coco8.yaml model=yolo9-t --dry-run --json
libreyolo train data=coco8.yaml model=rfdetr-s --dry-run --json

# User override wins over family default
libreyolo train data=coco8.yaml model=yolox-s momentum=0.5 --dry-run --json

# Schema discovery
libreyolo train --help-json
libreyolo train --help
```

## Val

```bash
# Validate with pretrained weights
libreyolo val model=yolox-s data=coco8.yaml

# JSON output
libreyolo val model=yolox-s data=coco8.yaml --json

# With overrides
libreyolo val model=yolox-s data=coco8.yaml batch=8 conf=0.01

# Local weights
libreyolo val model=weights/LibreYOLOXs.pt data=coco8.yaml

# YOLOv9
libreyolo val model=yolo9-t data=coco8.yaml
```

## Export

```bash
# ONNX export
libreyolo export model=weights/LibreYOLOXs.pt format=onnx

# ONNX with options
libreyolo export model=weights/LibreYOLOXs.pt format=onnx half dynamic

# JSON output
libreyolo export model=weights/LibreYOLOXs.pt format=onnx --json

# TensorRT (engine alias)
libreyolo export model=weights/LibreYOLOXs.pt format=engine half

# OpenVINO
libreyolo export model=weights/LibreYOLOXs.pt format=openvino
```

## Error Cases

```bash
# Missing source file
libreyolo predict source=nonexistent.jpg model=yolox-s

# Missing source — JSON error
libreyolo predict source=nonexistent.jpg model=yolox-s --json

# Missing required arg
libreyolo train model=yolox-s
libreyolo predict model=yolox-s

# Half + int8 conflict
libreyolo export model=weights/LibreYOLOXs.pt format=onnx half int8
```
67 changes: 67 additions & 0 deletions libreyolo/cli/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""LibreYOLO CLI — ultralytics-compatible command-line interface.

Entry point registered in pyproject.toml as ``libreyolo``.
"""

import sys

import typer

app = typer.Typer(
name="libreyolo",
help="LibreYOLO — open source YOLO detection toolkit.",
add_completion=False,
no_args_is_help=True,
)


def _strip_task_prefix() -> None:
"""Strip optional 'detect' task prefix from argv.

``libreyolo detect predict ...`` becomes ``libreyolo predict ...``.
"""
known_tasks = {"detect"}
args = sys.argv[1:]
if args and args[0] in known_tasks:
sys.argv = [sys.argv[0]] + args[1:]


def _setup_logging_from_argv() -> None:
"""Configure logging early, before Typer parses args.

Peeks at sys.argv for --quiet/--verbose so the logger is ready
before any command code runs.
"""
from ..utils.logging import setup_logging

args = sys.argv[1:]
quiet = "--quiet" in args
verbose = "--verbose" in args
setup_logging(quiet=quiet, verbose=verbose)


def entrypoint() -> None:
"""CLI entry point registered in pyproject.toml."""
import warnings

warnings.filterwarnings("ignore")

_strip_task_prefix()
_setup_logging_from_argv()

from .commands import special, predict, train, val, export # noqa: F401
from .parsing import KeyValueCommand

# Special commands
for cmd_name in ("version", "checks", "models", "formats", "cfg", "info"):
app.command(cmd_name, cls=KeyValueCommand)(
getattr(special, f"{cmd_name}_cmd")
)

# Core mode commands
app.command("predict", cls=KeyValueCommand)(predict.predict_cmd)
app.command("train", cls=KeyValueCommand)(train.train_cmd)
app.command("val", cls=KeyValueCommand)(val.val_cmd)
app.command("export", cls=KeyValueCommand)(export.export_cmd)

app()
41 changes: 41 additions & 0 deletions libreyolo/cli/aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""Mode-aware alias resolution for CLI parameter names.

Translates user-facing ultralytics names to internal library field names.
This is the single source of truth for name translation.
"""

TRAIN_ALIASES: dict[str, str] = {
"mosaic": "mosaic_prob",
"mixup": "mixup_prob",
}

VAL_ALIASES: dict[str, str] = {
"batch": "batch_size",
"conf": "conf_thres",
"iou": "iou_thres",
"workers": "num_workers",
}

# Predict and export use native parameter names — no aliases needed.

_MODE_ALIASES: dict[str, dict[str, str]] = {
"train": TRAIN_ALIASES,
"val": VAL_ALIASES,
}


def resolve_aliases(overrides: dict, mode: str) -> dict:
"""Translate CLI-facing keys to internal config field names.

Args:
overrides: Dict of CLI parameter names and values.
mode: Command mode ("train", "val", "predict", "export").

Returns:
Dict with internal field names.
"""
aliases = _MODE_ALIASES.get(mode, {})
resolved = {}
for key, value in overrides.items():
resolved[aliases.get(key, key)] = value
return resolved
1 change: 1 addition & 0 deletions libreyolo/cli/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""CLI command implementations."""
Loading