refactor: remove jinja2 dependency, use simple template engine
- Replace jinja2 with custom render_template() helper
- Support {{ var }} substitution and {% if %}...{% endif %} conditionals
- Remove jinja2 from pyproject.toml and requirements.txt
- Simplifies dependency tree and reduces install size
This commit is contained in:
4 files changed
+65
-38
No files matched your search
@@ -33,8 +33,8 @@ from devgen.utils import (
|
|||||||
extract_commit_messages,
|
extract_commit_messages,
|
||||||
get_commit_dry_run_path,
|
get_commit_dry_run_path,
|
||||||
is_file_recent,
|
is_file_recent,
|
||||||
load_template_env,
|
load_template,
|
||||||
render_custom_template,
|
render_template,
|
||||||
sanitize_ai_commit_message,
|
sanitize_ai_commit_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,13 +74,13 @@ class CommitMessageBuilder:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
template_env,
|
template_str: str,
|
||||||
config: Dict[str, Any],
|
config: Dict[str, Any],
|
||||||
provider: str,
|
provider: str,
|
||||||
model: str,
|
model: str,
|
||||||
debug: bool = False,
|
debug: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.template_env = template_env
|
self.template_str = template_str
|
||||||
self.config = config
|
self.config = config
|
||||||
self.provider = provider
|
self.provider = provider
|
||||||
self.model = model
|
self.model = model
|
||||||
@@ -97,25 +97,14 @@ class CommitMessageBuilder:
|
|||||||
use_emoji = self.config.get("emoji", True)
|
use_emoji = self.config.get("emoji", True)
|
||||||
ollama_host = self.config.get("ollama_host")
|
ollama_host = self.config.get("ollama_host")
|
||||||
|
|
||||||
if custom_template:
|
template = custom_template or self.template_str
|
||||||
prompt = render_custom_template(
|
prompt = render_template(
|
||||||
custom_template,
|
template,
|
||||||
group_name=group,
|
group_name=group,
|
||||||
diff_text=diff,
|
diff_text=diff,
|
||||||
use_emoji=use_emoji,
|
use_emoji=use_emoji,
|
||||||
context=manifest_context,
|
context=manifest_context,
|
||||||
)
|
).strip()
|
||||||
else:
|
|
||||||
prompt = (
|
|
||||||
self.template_env.get_template("commit_message.tpl")
|
|
||||||
.render(
|
|
||||||
group_name=group,
|
|
||||||
diff_text=diff,
|
|
||||||
use_emoji=use_emoji,
|
|
||||||
context=manifest_context,
|
|
||||||
)
|
|
||||||
.strip()
|
|
||||||
)
|
|
||||||
|
|
||||||
provider = (
|
provider = (
|
||||||
extra_kwargs.get("provider") or self.config.get("provider") or self.provider
|
extra_kwargs.get("provider") or self.config.get("provider") or self.provider
|
||||||
@@ -198,10 +187,10 @@ class CommitEngine:
|
|||||||
),
|
),
|
||||||
logger=self.logger,
|
logger=self.logger,
|
||||||
)
|
)
|
||||||
self.template_env = load_template_env("commit")
|
self.template_str = load_template("commit", "commit_message.tpl")
|
||||||
self.cache = CacheManager(get_commit_dry_run_path())
|
self.cache = CacheManager(get_commit_dry_run_path())
|
||||||
self.message_builder = CommitMessageBuilder(
|
self.message_builder = CommitMessageBuilder(
|
||||||
self.template_env,
|
self.template_str,
|
||||||
self.config,
|
self.config,
|
||||||
provider=self.provider,
|
provider=self.provider,
|
||||||
model=self.model,
|
model=self.model,
|
||||||
|
|||||||
+51
-11
@@ -6,7 +6,6 @@ from pathlib import Path
|
|||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, Optional
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from jinja2 import Environment, FileSystemLoader
|
|
||||||
|
|
||||||
|
|
||||||
def ensure_log_directory() -> Path:
|
def ensure_log_directory() -> Path:
|
||||||
@@ -216,21 +215,61 @@ def delete_file(filepath: Path | str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def load_template_env(sub_dir: str) -> Environment:
|
def load_template(sub_dir: str, name: str) -> str:
|
||||||
|
"""Load a template file from the templates directory."""
|
||||||
template_dir = Path(__file__).parent / "templates" / sub_dir
|
template_dir = Path(__file__).parent / "templates" / sub_dir
|
||||||
if not template_dir.is_dir():
|
template_path = template_dir / name
|
||||||
|
if not template_path.is_file():
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Template directory not found: {template_dir}. "
|
f"Template not found: {template_path}. "
|
||||||
"The installation may be corrupted."
|
"The installation may be corrupted."
|
||||||
)
|
)
|
||||||
return Environment(loader=FileSystemLoader(template_dir))
|
return template_path.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
def render_custom_template(template_str: str, **context) -> str:
|
def render_template(template_str: str, **context) -> str:
|
||||||
"""Renders a Jinja2 template from a string."""
|
"""Render a simple template with variable substitution and conditionals.
|
||||||
env = Environment()
|
|
||||||
template = env.from_string(template_str)
|
Supports:
|
||||||
return template.render(**context)
|
- {{ variable }} - variable substitution
|
||||||
|
- {% if condition %}...{% endif %} - conditional blocks
|
||||||
|
- {% if condition %}...{% else %}...{% endif %} - conditional with else
|
||||||
|
"""
|
||||||
|
result = template_str
|
||||||
|
|
||||||
|
# Process conditional blocks: {% if var %}...{% endif %}
|
||||||
|
# and {% if var %}...{% else %}...{% endif %}
|
||||||
|
if_pattern = re.compile(
|
||||||
|
r"\{%\s*if\s+(\w+)\s*%\}(.*?)\{%\s*endif\s*%\}",
|
||||||
|
re.DOTALL,
|
||||||
|
)
|
||||||
|
|
||||||
|
def replace_if(match):
|
||||||
|
var_name = match.group(1)
|
||||||
|
content = match.group(2)
|
||||||
|
value = context.get(var_name)
|
||||||
|
if value:
|
||||||
|
# Check for else block
|
||||||
|
else_pattern = re.compile(r"\{%\s*else\s*%\}", re.DOTALL)
|
||||||
|
parts = else_pattern.split(content, 1)
|
||||||
|
return parts[0]
|
||||||
|
else:
|
||||||
|
else_pattern = re.compile(r"\{%\s*else\s*%\}", re.DOTALL)
|
||||||
|
parts = else_pattern.split(content, 1)
|
||||||
|
return parts[1] if len(parts) > 1 else ""
|
||||||
|
|
||||||
|
result = if_pattern.sub(replace_if, result)
|
||||||
|
|
||||||
|
# Process variable substitutions: {{ variable }}
|
||||||
|
var_pattern = re.compile(r"\{\{\s*(\w+)\s*\}\}")
|
||||||
|
|
||||||
|
def replace_var(match):
|
||||||
|
var_name = match.group(1)
|
||||||
|
return str(context.get(var_name, ""))
|
||||||
|
|
||||||
|
result = var_pattern.sub(replace_var, result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def load_config() -> Dict[str, Any]:
|
def load_config() -> Dict[str, Any]:
|
||||||
@@ -338,7 +377,8 @@ __all__ = [
|
|||||||
"get_git_staged_files",
|
"get_git_staged_files",
|
||||||
"read_file_content",
|
"read_file_content",
|
||||||
"delete_file",
|
"delete_file",
|
||||||
"load_template_env",
|
"load_template",
|
||||||
|
"render_template",
|
||||||
"load_config",
|
"load_config",
|
||||||
"get_questionary_style",
|
"get_questionary_style",
|
||||||
"is_token_limit_error",
|
"is_token_limit_error",
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ classifiers = [
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anthropic>=0.75.0",
|
"anthropic>=0.75.0",
|
||||||
"google-genai>=0.1.0",
|
"google-genai>=0.1.0",
|
||||||
"jinja2>=3.1.6",
|
|
||||||
"openai>=2.11.0",
|
"openai>=2.11.0",
|
||||||
"pyyaml>=6.0.3",
|
"pyyaml>=6.0.3",
|
||||||
"questionary>=2.1.1",
|
"questionary>=2.1.1",
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
anthropic==0.109.1
|
anthropic==0.109.1
|
||||||
google-genai==2.8.0
|
google-genai==2.8.0
|
||||||
jinja2==3.1.6
|
|
||||||
openai==2.41.1
|
openai==2.41.1
|
||||||
pre-commit==4.6.0
|
pre-commit==4.6.0
|
||||||
pyyaml==6.0.3
|
pyyaml==6.0.3
|
||||||
|
|||||||
Reference in new issue
Block a user