fixes and modelgen insert

This commit is contained in:
2026-02-04 09:53:48 -03:00
parent b88f75fce0
commit 30b2e1cf44
52 changed files with 5317 additions and 178 deletions

290
tools/__main__.py Normal file
View File

@@ -0,0 +1,290 @@
"""
Modelgen - Generic Model Generation Tool
Generates typed models from various sources to various formats.
Input sources:
- from-config: Configuration files (soleprint config.json style)
- from-schema: Python dataclasses in schema/ folder
- extract: Existing codebases (Django, SQLAlchemy, Prisma)
Output formats:
- pydantic: Pydantic BaseModel classes
- django: Django ORM models
- typescript: TypeScript interfaces
- protobuf: Protocol Buffer definitions
- prisma: Prisma schema
Usage:
python -m soleprint.station.tools.modelgen --help
python -m soleprint.station.tools.modelgen from-config -c config.json -o models.py
python -m soleprint.station.tools.modelgen from-schema -o models/ --targets pydantic,typescript
python -m soleprint.station.tools.modelgen extract --source /path/to/django --targets pydantic
"""
import argparse
import sys
from pathlib import Path
from .generator import GENERATORS
def cmd_from_config(args):
"""Generate models from a configuration file (soleprint config.json style)."""
from .loader import load_config
from .model_generator import ModelGenerator
config_path = Path(args.config)
if not config_path.exists():
print(f"Error: Config file not found: {config_path}", file=sys.stderr)
sys.exit(1)
output_path = Path(args.output)
print(f"Loading config: {config_path}")
config = load_config(config_path)
print(f"Generating {args.format} models to: {output_path}")
generator = ModelGenerator(
config=config,
output_path=output_path,
output_format=args.format,
)
result_path = generator.generate()
print(f"Models generated: {result_path}")
def cmd_from_schema(args):
"""Generate models from Python dataclasses in schema/ folder."""
from .loader import load_schema
from .writer import write_file
# Determine schema path
schema_path = Path(args.schema) if args.schema else Path.cwd() / "schema"
if not schema_path.exists():
print(f"Error: Schema folder not found: {schema_path}", file=sys.stderr)
print(
"Create a schema/ folder with Python dataclasses and an __init__.py",
file=sys.stderr,
)
print("that exports DATACLASSES and ENUMS lists.", file=sys.stderr)
sys.exit(1)
print(f"Loading schema: {schema_path}")
schema = load_schema(schema_path)
print(f"Found {len(schema.models)} models, {len(schema.enums)} enums")
# Parse targets
targets = [t.strip() for t in args.targets.split(",")]
output_dir = Path(args.output)
for target in targets:
if target not in GENERATORS:
print(f"Warning: Unknown target '{target}', skipping", file=sys.stderr)
continue
generator = GENERATORS[target]()
ext = generator.file_extension()
# Determine output filename (use target name to avoid overwrites)
if len(targets) == 1 and args.output.endswith(ext):
output_file = output_dir
else:
output_file = output_dir / f"models_{target}{ext}"
print(f"Generating {target} to: {output_file}")
generator.generate(schema, output_file)
print("Done!")
def cmd_extract(args):
"""Extract models from existing codebase."""
from .loader.extract import EXTRACTORS
source_path = Path(args.source)
if not source_path.exists():
print(f"Error: Source path not found: {source_path}", file=sys.stderr)
sys.exit(1)
# Auto-detect or use specified framework
framework = args.framework
extractor = None
if framework == "auto":
for name, extractor_cls in EXTRACTORS.items():
ext = extractor_cls(source_path)
if ext.detect():
framework = name
extractor = ext
print(f"Detected framework: {framework}")
break
if not extractor:
print("Error: Could not auto-detect framework", file=sys.stderr)
print(f"Available frameworks: {list(EXTRACTORS.keys())}", file=sys.stderr)
sys.exit(1)
else:
if framework not in EXTRACTORS:
print(f"Error: Unknown framework: {framework}", file=sys.stderr)
print(f"Available: {list(EXTRACTORS.keys())}", file=sys.stderr)
sys.exit(1)
extractor = EXTRACTORS[framework](source_path)
print(f"Extracting from: {source_path}")
models, enums = extractor.extract()
print(f"Extracted {len(models)} models, {len(enums)} enums")
# Parse targets
targets = [t.strip() for t in args.targets.split(",")]
output_dir = Path(args.output)
for target in targets:
if target not in GENERATORS:
print(f"Warning: Unknown target '{target}', skipping", file=sys.stderr)
continue
generator = GENERATORS[target]()
ext = generator.file_extension()
# Determine output filename (use target name to avoid overwrites)
if len(targets) == 1 and args.output.endswith(ext):
output_file = output_dir
else:
output_file = output_dir / f"models_{target}{ext}"
print(f"Generating {target} to: {output_file}")
generator.generate((models, enums), output_file)
print("Done!")
def cmd_list_formats(args):
"""List available output formats."""
print("Available output formats:")
for fmt in GENERATORS.keys():
print(f" - {fmt}")
def main():
parser = argparse.ArgumentParser(
description="Modelgen - Generic Model Generation Tool",
formatter_class=argparse.RawDescriptionHelpFormatter,
)
subparsers = parser.add_subparsers(dest="command", required=True)
# Available formats for help text
formats = list(GENERATORS.keys())
formats_str = ", ".join(formats)
# from-config command
config_parser = subparsers.add_parser(
"from-config",
help="Generate models from soleprint configuration file",
)
config_parser.add_argument(
"--config",
"-c",
type=str,
required=True,
help="Path to configuration file (e.g., config.json)",
)
config_parser.add_argument(
"--output",
"-o",
type=str,
required=True,
help="Output path (file or directory)",
)
config_parser.add_argument(
"--format",
"-f",
type=str,
default="pydantic",
choices=["pydantic"], # Only pydantic for config mode
help="Output format (default: pydantic)",
)
config_parser.set_defaults(func=cmd_from_config)
# from-schema command
schema_parser = subparsers.add_parser(
"from-schema",
help="Generate models from Python dataclasses in schema/ folder",
)
schema_parser.add_argument(
"--schema",
"-s",
type=str,
default=None,
help="Path to schema folder (default: ./schema)",
)
schema_parser.add_argument(
"--output",
"-o",
type=str,
required=True,
help="Output path (file or directory)",
)
schema_parser.add_argument(
"--targets",
"-t",
type=str,
default="pydantic",
help=f"Comma-separated output targets ({formats_str})",
)
schema_parser.set_defaults(func=cmd_from_schema)
# extract command
extract_parser = subparsers.add_parser(
"extract",
help="Extract models from existing codebase",
)
extract_parser.add_argument(
"--source",
"-s",
type=str,
required=True,
help="Path to source codebase",
)
extract_parser.add_argument(
"--framework",
"-f",
type=str,
choices=["django", "sqlalchemy", "prisma", "auto"],
default="auto",
help="Source framework (default: auto-detect)",
)
extract_parser.add_argument(
"--output",
"-o",
type=str,
required=True,
help="Output path (file or directory)",
)
extract_parser.add_argument(
"--targets",
"-t",
type=str,
default="pydantic",
help=f"Comma-separated output targets ({formats_str})",
)
extract_parser.set_defaults(func=cmd_extract)
# list-formats command
formats_parser = subparsers.add_parser(
"list-formats",
help="List available output formats",
)
formats_parser.set_defaults(func=cmd_list_formats)
args = parser.parse_args()
args.func(args)
if __name__ == "__main__":
main()