ollie/data/tools/_lib/args.py

76 lines
2.1 KiB
Python

"""Shared argument parsing for ollie tool scripts.
Tools receive a JSON object on stdin. This module reads and parses it,
providing a simple interface for extracting required and optional fields.
Usage:
from _lib.args import parse_args
args = parse_args()
path = args.require("path")
start = args.get("start") # None if missing
"""
import json
import sys
class Args:
"""Parsed tool arguments from stdin JSON."""
def __init__(self, data: dict):
self._data = data
def require(self, key: str) -> str:
"""Get a required argument. Exits with error if missing."""
if key not in self._data or self._data[key] is None:
print(f"error: missing required argument: {key}", file=sys.stderr)
sys.exit(1)
return str(self._data[key])
def get(self, key: str, default=None):
"""Get an optional argument."""
v = self._data.get(key)
if v is None:
return default
return str(v) if isinstance(v, (str, int, float, bool)) else v
def get_list(self, key: str) -> list:
"""Get an argument expected to be a list."""
v = self._data.get(key)
if v is None:
return []
if isinstance(v, list):
return v
return [v]
def get_bool(self, key: str, default=False) -> bool:
"""Get a boolean argument."""
v = self._data.get(key)
if v is None:
return default
if isinstance(v, bool):
return v
return str(v).lower() in ("true", "1", "yes")
def get_int(self, key: str, default=None):
"""Get an integer argument."""
v = self._data.get(key)
if v is None:
return default
return int(v)
def raw(self) -> dict:
"""Return the raw parsed dict."""
return self._data
def parse_args() -> Args:
"""Read JSON args from stdin and return an Args instance."""
try:
data = json.load(sys.stdin)
except (json.JSONDecodeError, ValueError):
data = {}
if not isinstance(data, dict):
data = {}
return Args(data)