#!/usr/bin/env python3 """Introspect a Pydantic module and print its declarations as JSON. argv[1] is a JSON object: - module: Python module to import (e.g. "claude_manage.schema") - derives: derive identifiers decoru applies to every emitted struct stdout is a JSON object: - enums: [{"name": , "variants": [, ...]}] - structs: [, ...] as rendered by decoru decoru itself is scoped to BaseModel, so Enum subclasses are reported as shapes for the caller to render; only their variant identifiers go through decoru, which keeps them equal to the ones it bakes into field defaults. """ import importlib import inspect import json import sys from enum import Enum from pathlib import Path from pydantic import BaseModel # type: ignore[import-untyped] from decoru import ( # type: ignore[import-untyped] emit_rust_struct, to_rust_variant_ident, walk_pydantic_model, ) def _declared_in(module, obj) -> bool: return getattr(obj, "__module__", None) == module.__name__ def discover_models(module) -> list[type[BaseModel]]: """BaseModel subclasses declared in this module. Imported helpers are skipped — only own-module declarations qualify.""" return [ obj for _, obj in inspect.getmembers(module, inspect.isclass) if issubclass(obj, BaseModel) and obj is not BaseModel and _declared_in(module, obj) ] def discover_enums(module) -> list[type[Enum]]: """Enum subclasses declared in this module. Filters out the framework's own Enum class and anything imported from elsewhere.""" return [ obj for _, obj in inspect.getmembers(module, inspect.isclass) if issubclass(obj, Enum) and obj is not Enum and _declared_in(module, obj) ] def main() -> int: if len(sys.argv) < 2: sys.stderr.write("run_decoru.py: missing JSON payload argument\n") return 2 payload = json.loads(sys.argv[1]) module_name: str = payload["module"] derives = tuple(payload["derives"]) sys.path.insert(0, str(Path.cwd())) module = importlib.import_module(module_name) enums = discover_enums(module) models = discover_models(module) if not enums and not models: sys.stderr.write( f"run_decoru.py: no Enum or BaseModel subclasses declared in {module_name!r}\n" ) return 3 json.dump( { "enums": [ { "name": enum_class.__name__, "variants": [to_rust_variant_ident(m.name) for m in enum_class], } for enum_class in enums ], "structs": [ emit_rust_struct(walk_pydantic_model(model), derives=derives) for model in models ], }, sys.stdout, ) return 0 if __name__ == "__main__": sys.exit(main())