from __future__ import annotations import json import subprocess import sys import pandas as pd from .helpers import build_ambiguous_smiles, build_macrolactone def run_cli(*args: str) -> subprocess.CompletedProcess[str]: return subprocess.run( [sys.executable, "-m", "macro_lactone_toolkit.cli", *args], capture_output=True, text=True, check=False, ) def test_cli_smoke_commands(): built = build_macrolactone(16, {5: "methyl"}) analyze = run_cli("analyze", "--smiles", built.smiles) assert analyze.returncode == 0, analyze.stderr analyze_payload = json.loads(analyze.stdout) assert analyze_payload["valid_ring_sizes"] == [16] number = run_cli("number", "--smiles", built.smiles) assert number.returncode == 0, number.stderr number_payload = json.loads(number.stdout) assert number_payload["ring_size"] == 16 assert number_payload["position_to_atom"]["1"] >= 0 fragment = run_cli("fragment", "--smiles", built.smiles, "--parent-id", "cli_1") assert fragment.returncode == 0, fragment.stderr fragment_payload = json.loads(fragment.stdout) assert fragment_payload["parent_id"] == "cli_1" assert fragment_payload["ring_size"] == 16 assert fragment_payload["fragments"][0]["fragment_smiles_labeled"] def test_cli_fragment_csv_skips_ambiguous_and_records_errors(tmp_path): valid = build_macrolactone(14, {4: "methyl"}) ambiguous = build_ambiguous_smiles() input_path = tmp_path / "molecules.csv" output_path = tmp_path / "fragments.csv" errors_path = tmp_path / "errors.csv" pd.DataFrame( [ {"id": "valid_1", "smiles": valid.smiles}, {"id": "ambiguous_1", "smiles": ambiguous}, ] ).to_csv(input_path, index=False) completed = run_cli( "fragment", "--input", str(input_path), "--output", str(output_path), "--errors-output", str(errors_path), ) assert completed.returncode == 0, completed.stderr fragments = pd.read_csv(output_path) errors = pd.read_csv(errors_path) assert set(fragments["parent_id"]) == {"valid_1"} assert errors.loc[0, "parent_id"] == "ambiguous_1" assert errors.loc[0, "error_type"] == "AmbiguousMacrolactoneError"