Files
dbyaml/scripts/generate_schema.py
T
2026-09-20 02:08:11 +02:00

79 lines
2.2 KiB
Python

import json
from typing import Any
import click
import dbyaml.cli
def generate_schema_from_click(ctx, additional_properties=False):
"""Command or Group (no nested Groups)"""
schema: dict[str, Any] = {
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": ("./src/dbyaml/resources/dbyaml.schema.json"),
"$comment": "tool.dbyaml table in pyproject.toml",
}
schema_ctx = generate_node_from_click(ctx, additional_properties)
schema.update(schema_ctx)
if isinstance(ctx, click.Group):
for name, cmd in ctx.commands.items():
assert name
name = name.replace("_", "-")
schema_cmd = generate_node_from_click(cmd, additional_properties)
schema["properties"][name] = schema_cmd
return schema
def generate_node_from_click(ctx, additional_properties=False):
"""Ignores eager options"""
props = {}
for param in ctx.params:
if not isinstance(param, click.Option) or param.is_eager:
continue
assert param.name
name = param.name.replace("_", "-")
props[name] = {}
match param.type:
case click.types.IntParamType():
props[name]["type"] = "integer"
case click.types.StringParamType() | click.types.Path():
props[name]["type"] = "string"
case click.types.Choice(choices=choices):
props[name]["enum"] = choices
case click.types.BoolParamType():
props[name]["type"] = "boolean"
case _:
msg = f"{param.type!r} not a known type for {param}"
raise TypeError(msg)
if param.multiple:
props[name] = {"type": "array", "items": props[name]}
props[name]["description"] = param.help
default = param.to_info_dict()["default"]
if default is not None and not param.multiple:
props[name]["default"] = default
schema = {
"type": "object",
"additionalProperties": additional_properties,
"properties": props,
}
return schema
@click.command(context_settings={"help_option_names": ["-h", "--help"]})
@click.option("--outfile", type=click.File(mode="w"), help="Write to file")
def main(outfile):
schema = generate_schema_from_click(dbyaml.cli.main, False)
print(json.dumps(schema, indent=2), file=outfile)
if __name__ == "__main__":
main()