Coverage for genschema / cli.py: 0%
88 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 22:23 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-03-14 22:23 +0000
1import argparse
2import json
3import sys
4import time
6from rich.console import Console
8from . import Converter, PseudoArrayHandler
9from .comparators import (
10 DeleteElement,
11 EmptyComparator,
12 FormatComparator,
13 RequiredComparator,
14 SchemaVersionComparator,
15)
17console = Console()
20def main() -> None:
21 parser = argparse.ArgumentParser(
22 description="Generate JSON Schema from JSON input using genschema.",
23 formatter_class=argparse.RawDescriptionHelpFormatter,
24 epilog="""
25Examples:
26 genschema input.json -o schema.json
27 genschema input1.json input2.json --base-of oneOf
28 cat input.json | genschema -
29 genschema --base-of anyOf < input.json
30 genschema dir/file1.json dir/file2.json -o schema.json
31 """,
32 )
33 parser.add_argument(
34 "inputs",
35 nargs="*",
36 help="Paths to input JSON files. Use '-' for stdin. "
37 "If no arguments are provided, show this help message.",
38 )
39 parser.add_argument(
40 "-o",
41 "--output",
42 help="Path to output JSON Schema file. If not specified, output to stdout.",
43 )
44 parser.add_argument(
45 "--base-of",
46 choices=["anyOf", "oneOf"],
47 default="anyOf",
48 help="Combinator for differing types (default: anyOf).",
49 )
50 parser.add_argument(
51 "--no-pseudo-array", action="store_true", help="Disable pseudo-array handling."
52 )
53 parser.add_argument("--no-format", action="store_true", help="Disable FormatComparator.")
54 parser.add_argument("--no-required", action="store_true", help="Disable RequiredComparator.")
55 parser.add_argument("--no-empty", action="store_true", help="Disable EmptyComparator.")
56 parser.add_argument(
57 "--no-schema-version",
58 action="store_true",
59 help="Disable SchemaVersionComparator.",
60 )
61 parser.add_argument(
62 "--no-delete-element", action="store_true", help="Disable DeleteElement comparators."
63 )
65 # If no arguments, show help and exit
66 if len(sys.argv) == 1:
67 parser.print_help(sys.stderr)
68 sys.exit(1)
70 args = parser.parse_args()
72 # Collect input data
73 datas = []
74 if not args.inputs:
75 # This case shouldn't happen due to the check above, but for safety
76 try:
77 data = json.load(sys.stdin)
78 datas.append(data)
79 except json.JSONDecodeError as e:
80 console.print(f"[red]Error reading JSON from stdin: {e}[/red]")
81 sys.exit(1)
82 else:
83 for input_path in args.inputs:
84 if input_path == "-":
85 try:
86 data = json.load(sys.stdin)
87 datas.append(data)
88 except json.JSONDecodeError as e:
89 console.print(f"[red]Error reading JSON from stdin: {e}[/red]")
90 sys.exit(1)
91 else:
92 try:
93 with open(input_path, "r", encoding="utf-8") as f:
94 data = json.load(f)
95 datas.append(data)
96 except FileNotFoundError:
97 console.print(f"[red]File not found: {input_path}[/red]")
98 sys.exit(1)
99 except json.JSONDecodeError as e:
100 console.print(f"[red]Invalid JSON in file {input_path}: {e}[/red]")
101 sys.exit(1)
103 if not datas:
104 console.print("[red]No valid JSON provided.[/red]")
105 sys.exit(1)
107 # Converter setup
108 pseudo_handler = None if args.no_pseudo_array else PseudoArrayHandler()
109 conv = Converter(pseudo_handler=pseudo_handler, base_of=args.base_of)
111 for data in datas:
112 conv.add_json(data)
114 # Register comparators conditionally
115 if not args.no_format:
116 conv.register(FormatComparator())
117 if not args.no_schema_version:
118 conv.register(SchemaVersionComparator())
119 if not args.no_required:
120 conv.register(RequiredComparator())
121 if not args.no_empty:
122 conv.register(EmptyComparator())
123 if not args.no_delete_element:
124 conv.register(DeleteElement())
125 conv.register(DeleteElement("isPseudoArray"))
127 # Generate schema
128 start_time = time.time()
129 try:
130 result = conv.run()
131 except Exception as e:
132 console.print(f"[red]Error generating schema: {e}[/red]")
133 sys.exit(1)
134 elapsed = round(time.time() - start_time, 4)
136 # Output result
137 if args.output:
138 try:
139 with open(args.output, "w", encoding="utf-8") as f:
140 json.dump(result, f, indent=2, ensure_ascii=False)
141 console.print(f"[green]Schema successfully written to {args.output}[/green]")
142 except Exception as e:
143 console.print(f"[red]Error writing file {args.output}: {e}[/red]")
144 sys.exit(1)
145 else:
146 console.print(result)
148 # Execution info
149 instances_word = "instance" if len(datas) == 1 else "instances"
150 console.print(f"Generated from {len(datas)} JSON {instances_word}.")
151 console.print(f"Elapsed time: {elapsed} sec.")
154if __name__ == "__main__":
155 main()