from pathlib import Path import shlex import subprocess import sys ROOT = Path(__file__).resolve().parents[2] def test_operator_yolo_dataset_export_script_contract() -> None: script_path = ROOT / "scripts" / "export_operator_yolo_dataset.py" readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text( encoding="utf-8" ) assert script_path.exists() script = script_path.read_text(encoding="utf-8") assert "py_compile scripts/export_operator_yolo_dataset.py" in readiness assert "operator_samples_manifest.json" in script assert "dataset.yaml" in script assert "images/train" in script assert "labels/train" in script assert "images/val" in script assert "labels/val" in script assert "building" in script assert "reference_feature_count" in script assert "source_name" in script assert "reference_layer_name" in script assert "rasterio" in script assert "Transformer" in script assert "demo/workflow" not in script assert "fixture_mode" not in script assert "will_download_models" not in script def test_operator_yolo_dataset_export_help_does_not_require_gis_dependencies() -> None: script_path = ROOT / "scripts" / "export_operator_yolo_dataset.py" result = subprocess.run( [sys.executable, str(script_path), "--help"], check=False, capture_output=True, text=True, ) assert result.returncode == 0 assert ( "Export operator real-data samples to a YOLO detection dataset" in result.stdout ) assert "--manifest-path" in result.stdout assert "--val-samples" in result.stdout def test_operator_yolo_train_smoke_script_contract() -> None: script_path = ROOT / "scripts" / "train_operator_yolo_detector.sh" readiness = (ROOT / "scripts" / "run_readiness_check.sh").read_text( encoding="utf-8" ) assert script_path.exists() script = script_path.read_text(encoding="utf-8") assert "bash -n scripts/train_operator_yolo_detector.sh" in readiness assert "TRAIN_REQUIRE_CUDA" in script_path.read_text(encoding="utf-8") assert "OPERATOR_YOLO_DATASET_DIR" in script assert "YOLO_BASE_MODEL_PATH" in script assert "TRAIN_MODEL_OUTPUT_PATH" in script assert "TRAIN_EPOCHS" in script assert "TRAIN_IMGSZ" in script assert "/opt/geointel/venv/bin/python" in script assert 'PYTHON_BIN="python3"' in script assert "dataset.yaml" in script assert "from ultralytics import YOLO" in script assert "model.train" in script assert "plots=False" in script assert "seed_ultralytics_font" in script assert "DejaVuSans.ttf" in script assert "Arial.ttf" in script assert "training_summary.json" in script assert '"dataset_yaml_sha256"' in script assert '"dataset_summary_sha256"' in script assert '"base_model_sha256"' in script assert '"trained_model_sha256"' in script assert "training_release_manifest.py" in script assert "NO_TRAINING.json" in script assert "Training is prohibited for this evaluation-only dataset" in script assert "verify" in script assert "download" not in script.lower() assert "fixture_mode" not in script def test_operator_yolo_train_rejects_evaluation_only_marker(tmp_path: Path) -> None: dataset_dir = tmp_path / "evaluation-only" dataset_dir.mkdir() (dataset_dir / "dataset.yaml").write_text("val: images/val\n", encoding="utf-8") (dataset_dir / "NO_TRAINING.json").write_text( '{"training_prohibited": true}\n', encoding="utf-8" ) def shell_path(path: Path) -> str: if path.drive: return f"/mnt/{path.drive[0].lower()}/{path.as_posix()[3:]}" return str(path) dataset_shell_path = shell_path(dataset_dir) model_shell_path = shell_path(tmp_path / "missing.pt") script_shell_path = shell_path(ROOT / "scripts" / "train_operator_yolo_detector.sh") command = ( f"OPERATOR_YOLO_DATASET_DIR={shlex.quote(dataset_shell_path)} " f"YOLO_BASE_MODEL_PATH={shlex.quote(model_shell_path)} " f"bash {shlex.quote(script_shell_path)}" ) result = subprocess.run( ["bash", "-lc", command], capture_output=True, text=True, check=False, ) assert result.returncode == 1 assert "Training is prohibited for this evaluation-only dataset" in result.stderr assert "Base model file not found" not in result.stderr