testsAndMisc/python_pkg/sql_drills/__main__.py
Krzysztof kuhy Rudnicki ee78ae44cc
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (mypy, mypy) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (pylint, pylint) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (rest, ) (push) Waiting to run
Pre-commit checks / pre-commit (${{ matrix.group }}) (shellcheck, shellcheck) (push) Waiting to run
Python tests / test (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / lib-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Add sql_drills MySQL exact-match harness
Docker mysql:8.0.33 container, judge-style output grading, 12 original drills with live-verified references kept in tests only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WzxdWZewj4WS5X6AZyjWDp
2026-11-01 21:13:18 +01:00

69 lines
2.2 KiB
Python

"""CLI: ``python3 -m python_pkg.sql_drills start|stop|list|show|check``."""
from __future__ import annotations
import argparse
from pathlib import Path
import sys
from python_pkg.sql_drills import _check, _drills, _engine
_EXIT_CODES = {"pass": 0, "fail": 1, "error": 2}
def _out(line: str) -> None:
sys.stdout.write(f"{line}\n")
def _err(line: str) -> None:
sys.stderr.write(f"{line}\n")
def _build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(prog="sql_drills", description=__doc__)
sub = parser.add_subparsers(dest="cmd", required=True)
sub.add_parser("start", help="start the MySQL 8.0.33 container and wait")
sub.add_parser("stop", help="remove the container")
sub.add_parser("list", help="list drills in priority order")
show = sub.add_parser("show", help="print task, schema, expected sample")
show.add_argument("drill", help="drill id or number, e.g. 03")
check = sub.add_parser("check", help="grade a .sql file against a drill")
check.add_argument("drill", help="drill id or number, e.g. 03")
check.add_argument("sql_file", type=Path)
return parser
def _dispatch(args: argparse.Namespace) -> int:
if args.cmd == "start":
_engine.start()
_out(f"{_engine.CONTAINER} ready ({_engine.IMAGE})")
elif args.cmd == "stop":
_engine.stop()
_out(f"{_engine.CONTAINER} removed")
elif args.cmd == "list":
for drill in _drills.list_drills():
_out(f"{drill.id} {_drills.title_of(drill)}")
elif args.cmd == "show":
sys.stdout.write(_drills.render_show(_drills.get_drill(args.drill)))
else:
result = _check.run_check(_drills.get_drill(args.drill), args.sql_file)
_out(result.message)
return _EXIT_CODES[result.status]
return 0
def main(argv: list[str] | None = None) -> int:
"""Entry point; returns the process exit code."""
args = _build_parser().parse_args(argv)
try:
return _dispatch(args)
except _drills.UnknownDrillError as exc:
_err(exc.args[0])
except _engine.EngineError as exc:
_err(f"error: {exc}")
return 2
if __name__ == "__main__":
sys.exit(main())