fix: resolve CI mypy type checking issues
This commit is contained in:
234
patternforge/src/patternforge/template.py
Normal file
234
patternforge/src/patternforge/template.py
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
from jinja2 import Environment, FileSystemLoader, TemplateSyntaxError
|
||||||
|
|
||||||
|
from patternforge.config import Config
|
||||||
|
|
||||||
|
|
||||||
|
class TemplateManager:
|
||||||
|
def __init__(self, config: Config) -> None:
|
||||||
|
self.config = config
|
||||||
|
self._ensure_templates_dir()
|
||||||
|
|
||||||
|
def _ensure_templates_dir(self) -> None:
|
||||||
|
self.config.templates_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
def _get_template_path(self, name: str) -> Path:
|
||||||
|
return self.config.templates_dir / f"{name}.yaml"
|
||||||
|
|
||||||
|
def _get_pattern_path(self, name: str) -> Path:
|
||||||
|
return self.config.patterns_dir / f"{name}.yaml"
|
||||||
|
|
||||||
|
def create_template(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
pattern_file: str,
|
||||||
|
custom_template: str | None = None,
|
||||||
|
description: str = "",
|
||||||
|
) -> None:
|
||||||
|
pattern_path = Path(pattern_file)
|
||||||
|
if not pattern_path.exists():
|
||||||
|
raise FileNotFoundError(f"Pattern file not found: {pattern_file}")
|
||||||
|
|
||||||
|
with open(pattern_path) as f:
|
||||||
|
patterns = yaml.safe_load(f)
|
||||||
|
|
||||||
|
template_content = ""
|
||||||
|
if custom_template:
|
||||||
|
with open(custom_template) as f:
|
||||||
|
template_content = f.read()
|
||||||
|
else:
|
||||||
|
template_content = self._generate_default_template(patterns)
|
||||||
|
|
||||||
|
template_data = {
|
||||||
|
"name": name,
|
||||||
|
"description": description,
|
||||||
|
"created": datetime.now().isoformat(),
|
||||||
|
"language": patterns.get("language", "unknown"),
|
||||||
|
"patterns": patterns,
|
||||||
|
"template": template_content,
|
||||||
|
}
|
||||||
|
|
||||||
|
template_path = self._get_template_path(name)
|
||||||
|
with open(template_path, "w") as f:
|
||||||
|
yaml.dump(template_data, f, default_flow_style=False)
|
||||||
|
|
||||||
|
def _generate_default_template(self, patterns: dict[str, Any]) -> str:
|
||||||
|
language = patterns.get("language", "python")
|
||||||
|
|
||||||
|
if language in ["python"]:
|
||||||
|
return '''# Generated by PatternForge
|
||||||
|
# Based on analyzed patterns from {{ project_name }}
|
||||||
|
|
||||||
|
{% if class_name %}
|
||||||
|
class {{ class_name }}:
|
||||||
|
"""{{ class_docstring }}"""
|
||||||
|
|
||||||
|
def __init__(self{% if init_params %}, {{ init_params }}{% endif %}):
|
||||||
|
{% for field in fields %}
|
||||||
|
self.{{ field }} = {{ field }}
|
||||||
|
{% endfor %}
|
||||||
|
{%- if methods %}
|
||||||
|
{% for method in methods %}
|
||||||
|
def {{ method.name }}(self{% if method.params %}, {{ method.params }}{% endif %}):
|
||||||
|
"""{{ method.docstring }}"""
|
||||||
|
pass
|
||||||
|
{% endfor %}
|
||||||
|
{%- endif %}
|
||||||
|
{% elif function_name %}
|
||||||
|
def {{ function_name }}({% if params %}{{ params }}{% endif %}):
|
||||||
|
"""{{ docstring }}"""
|
||||||
|
pass
|
||||||
|
{% else %}
|
||||||
|
# {{ entity_name }} - generated boilerplate
|
||||||
|
{% endif %}
|
||||||
|
'''
|
||||||
|
elif language in ["javascript", "typescript"]:
|
||||||
|
return '''// Generated by PatternForge
|
||||||
|
{% if class_name %}
|
||||||
|
export class {{ class_name }} {
|
||||||
|
{% for field in fields %}
|
||||||
|
private {{ field }};
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
constructor({% if params %}{{ params }}{% endif %}) {
|
||||||
|
{% for field in fields %}
|
||||||
|
this.{{ field }} = {{ field }};
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
{% if methods %}
|
||||||
|
{% for method in methods %}
|
||||||
|
{{ method.name }}({% if method.params %}{{ method.params }}{% endif %}) {
|
||||||
|
// {{ method.docstring }}
|
||||||
|
}
|
||||||
|
{% endfor %}
|
||||||
|
{%- endif %}
|
||||||
|
}
|
||||||
|
{% elif function_name %}
|
||||||
|
export function {{ function_name }}({% if params %}{{ params }}{% endif %}) {
|
||||||
|
// {{ docstring }}
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
// {{ entity_name }} - generated boilerplate
|
||||||
|
{% endif %}
|
||||||
|
'''
|
||||||
|
else:
|
||||||
|
return '''// Generated by PatternForge
|
||||||
|
// {{ entity_name }}
|
||||||
|
|
||||||
|
{% if class_name %}
|
||||||
|
class {{ class_name }} {
|
||||||
|
{% for field in fields %}
|
||||||
|
{{ field }};
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
constructor({% if params %}{{ params }}{% endif %}) {
|
||||||
|
{% for field in fields %}
|
||||||
|
this.{{ field }} = {{ field }};
|
||||||
|
{% endfor %}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{% else %}
|
||||||
|
// {{ entity_name }}
|
||||||
|
{% endif %}
|
||||||
|
'''
|
||||||
|
|
||||||
|
def list_templates(self) -> list[dict[str, Any]]:
|
||||||
|
templates: list[dict[str, Any]] = []
|
||||||
|
if not self.config.templates_dir.exists():
|
||||||
|
return templates
|
||||||
|
for f in self.config.templates_dir.glob("*.yaml"):
|
||||||
|
with open(f) as fp:
|
||||||
|
data = yaml.safe_load(fp)
|
||||||
|
if data:
|
||||||
|
templates.append({
|
||||||
|
"name": data.get("name", f.stem),
|
||||||
|
"description": data.get("description", ""),
|
||||||
|
"created": data.get("created", ""),
|
||||||
|
"language": data.get("language", ""),
|
||||||
|
})
|
||||||
|
return templates
|
||||||
|
|
||||||
|
def get_template(self, name: str) -> dict[str, Any] | None:
|
||||||
|
path = self._get_template_path(name)
|
||||||
|
if not path.exists():
|
||||||
|
return None
|
||||||
|
with open(path) as f:
|
||||||
|
result = yaml.safe_load(f)
|
||||||
|
return result if isinstance(result, dict) else None
|
||||||
|
|
||||||
|
def remove_template(self, name: str) -> bool:
|
||||||
|
path = self._get_template_path(name)
|
||||||
|
if path.exists():
|
||||||
|
path.unlink()
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def render_template(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
context: dict[str, Any],
|
||||||
|
) -> str:
|
||||||
|
template_data = self.get_template(name)
|
||||||
|
if not template_data:
|
||||||
|
raise ValueError(f"Template not found: {name}")
|
||||||
|
|
||||||
|
template_str = template_data.get("template", "")
|
||||||
|
try:
|
||||||
|
env = Environment(
|
||||||
|
loader=FileSystemLoader(str(self.config.templates_dir)),
|
||||||
|
trim_blocks=True,
|
||||||
|
lstrip_blocks=True,
|
||||||
|
)
|
||||||
|
template = env.from_string(template_str)
|
||||||
|
return template.render(**context)
|
||||||
|
except TemplateSyntaxError as e:
|
||||||
|
raise ValueError(f"Template syntax error: {e}")
|
||||||
|
|
||||||
|
def export_patterns(
|
||||||
|
self,
|
||||||
|
source: str,
|
||||||
|
destination: str,
|
||||||
|
format: str = "yaml",
|
||||||
|
) -> None:
|
||||||
|
src = Path(source)
|
||||||
|
dst = Path(destination)
|
||||||
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
if src.is_file():
|
||||||
|
with open(src) as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
if format == "json":
|
||||||
|
with open(dst, "w") as f:
|
||||||
|
json.dump(data, f, indent=2)
|
||||||
|
else:
|
||||||
|
with open(dst, "w") as f:
|
||||||
|
yaml.dump(data, f, default_flow_style=False)
|
||||||
|
else:
|
||||||
|
for yaml_file in src.glob("*.yaml"):
|
||||||
|
with open(yaml_file) as fp:
|
||||||
|
data = yaml.safe_load(fp)
|
||||||
|
out_path = dst / yaml_file.name
|
||||||
|
if format == "json":
|
||||||
|
with open(out_path.with_suffix(".json"), "w") as fp:
|
||||||
|
json.dump(data, fp, indent=2)
|
||||||
|
else:
|
||||||
|
with open(out_path, "w") as fp:
|
||||||
|
yaml.dump(data, fp, default_flow_style=False)
|
||||||
|
|
||||||
|
def import_patterns(self, source: str) -> None:
|
||||||
|
src = Path(source)
|
||||||
|
if src.is_file():
|
||||||
|
name = src.stem
|
||||||
|
import_path = self._get_pattern_path(name)
|
||||||
|
import_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
import_path.write_bytes(src.read_bytes())
|
||||||
|
else:
|
||||||
|
for f in src.glob("*.yaml"):
|
||||||
|
import_path = self._get_pattern_path(f.stem)
|
||||||
|
import_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
import_path.write_bytes(f.read_bytes())
|
||||||
Reference in New Issue
Block a user