Skip to content

zimmer-yan/py-template-engine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

9 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸš€ Python Template Engine

A powerful, lightweight template engine for Python with support for variables, functions, conditionals, loops, and file includes. Built for simplicity and extensibility.

PyPI version Tests Coverage Python License Downloads

✨ Features

  • πŸ”€ Variable substitution - {{name}}, {{user.email}}
  • ⚑ Function calls - {{get_time()}}, {{utils.format()}}
  • πŸ”€ Conditionals - {{#IF condition}}...{{#ELSE}}...{{/IF}}
  • πŸ”„ Loops - {{#EACH items AS item}}...{{/EACH}}
  • πŸ“„ File includes - {{#INCLUDE file_path}}
  • 🎨 Template rendering - {{#RENDER template_path}}
  • πŸ§ͺ Fully tested - Comprehensive test suite with 73 tests
  • 🎯 Type hints - Full type annotation support
  • πŸ—οΈ Extensible - Modular architecture for custom engines

πŸš€ Quick Start

Installation

From PyPI (Recommended)

# Install from PyPI
pip install py-template-engine

From Source

# Clone the repository
git clone https://github.com/zimmer-yan/py-template-engine.git
cd py-template-engine

# Create virtual environment (recommended)
python3 -m venv .venv
source .venv/bin/activate  # On Windows: .venv\Scripts\activate

# Install in development mode
pip install -e .

Direct from GitHub

# Install directly from GitHub
pip install git+https://github.com/zimmer-yan/py-template-engine.git

Basic Usage

from py_template_engine import TemplateEngine

# Simple variable substitution
template = "Hello {{name}}!"
engine = TemplateEngine(template_string=template)
result = engine.render(name="World")
print(result)  # Output: Hello World!

πŸ“– Template Syntax

Variables

<!-- Basic variables -->
<h1>{{title}}</h1>
<p>Welcome {{user.name}}!</p>

<!-- Nested object access -->
<span>{{user.profile.email}}</span>

Functions

<!-- Function calls -->
<p>Current time: {{get_time()}}</p>
<p>Formatted date: {{utils.format_date()}}</p>

Conditionals

<!-- IF/ELSE statements -->
{{#IF user_logged_in}}
    <p>Welcome back, {{username}}!</p>
{{#ELSE}}
    <p>Please log in to continue</p>
{{/IF}}

<!-- Nested conditions -->
{{#IF user}}
    {{#IF user.is_premium}}
        <span class="premium">Premium User</span>
    {{/IF}}
{{/IF}}

Loops

<!-- EACH loops -->
<ul>
{{#EACH items AS item}}
    <li>{{item}}</li>
{{/EACH}}
</ul>

<!-- Loop with objects -->
{{#EACH users AS user}}
    <div class="user">
        <h3>{{user.name}}</h3>
        <p>{{user.email}}</p>
    </div>
{{/EACH}}

File Operations

<!-- Include raw file content -->
{{#INCLUDE includes/header.html}}

<!-- Render template with full processing -->
{{#RENDER user_template}}

πŸ’‘ Advanced Examples

Complete Web Page Template

<!DOCTYPE html>
<html>
<head>
    <title>{{page_title}}</title>
</head>
<body>
    {{#INCLUDE header.html}}
    
    <main>
        {{#IF featured_posts}}
            <section class="featured">
                <h2>Featured Posts</h2>
                {{#EACH featured_posts AS post}}
                    <article>
                        <h3>{{post.title}}</h3>
                        <p>{{post.excerpt}}</p>
                        <time>{{post.format_date()}}</time>
                    </article>
                {{/EACH}}
            </section>
        {{/IF}}
        
        {{#RENDER templates/blog_content.html}}
    </main>
    
    {{#INCLUDE footer.html}}
</body>
</html>
from py_template_engine import TemplateEngine

engine = TemplateEngine(template_path="page.html")
result = engine.render(
    page_title="My Blog",
    featured_posts=[
        {
            "title": "Getting Started",
            "excerpt": "Learn the basics...",
            "format_date": lambda: "2024-01-15"
        }
    ],
)

Dynamic Dashboard

# Context data
dashboard_data = {
    "user": {
        "name": "Alice Johnson",
        "role": "admin",
        "notifications": 5
    },
    "stats": [
        {"label": "Users", "value": 1247},
        {"label": "Revenue", "value": "$52,340"},
        {"label": "Orders", "value": 89}
    ],
    "is_admin": True,
    "get_alert_class": lambda count: "danger" if count > 10 else "info"
}

template = """
<div class="dashboard">
    <h1>Welcome {{user.name}}</h1>
    
    {{#IF is_admin}}
        <div class="admin-panel">
            <h2>Admin Controls</h2>
            <p>Notifications: <span class="{{get_alert_class()}}">{{user.notifications}}</span></p>
        </div>
    {{/IF}}
    
    <div class="stats">
        {{#EACH stats AS stat}}
            <div class="stat-card">
                <h3>{{stat.label}}</h3>
                <p class="value">{{stat.value}}</p>
            </div>
        {{/EACH}}
    </div>
</div>
"""

engine = TemplateEngine(template_string=template)
result = engine.render(**dashboard_data)

πŸ—οΈ API Reference

TemplateEngine

class TemplateEngine:
    def __init__(self, template_path: Optional[str] = None, 
                 template_string: Optional[str] = None) -> None:
        """
        Initialize template engine with either file path or string.
        
        Args:
            template_path: Path to template file
            template_string: Template content as string
            
        Raises:
            ValueError: If neither template_path nor template_string provided
        """
    
    def render(self, **kwargs) -> str:
        """
        Render template with provided context variables.
        
        Args:
            **kwargs: Template context variables
            
        Returns:
            Rendered template as string
        """

πŸ§ͺ Testing

Run the comprehensive test suite:

# Activate virtual environment
source .venv/bin/activate

# Run all tests with pytest
pytest tests -v

# Run specific test file
python tests/test_template_engine.py

# Run with coverage
pytest tests --cov=py_template_engine

Test Coverage: 63 tests covering all features:

  • Variable substitution (basic + nested)
  • Function calls (simple + nested objects)
  • Conditional logic (IF/ELSE + nested)
  • Loop processing (EACH + complex data)
  • File operations (INCLUDE + RENDER)
  • Error handling & edge cases

πŸ”§ Development

Project Structure

py-templater/
β”œβ”€β”€ py_template_engine/          # Main package
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ TemplateEngine.py        # Main engine
β”‚   β”œβ”€β”€ TemplaterInterface.py
β”‚   └── sub_engines/             # Individual processors
β”‚       β”œβ”€β”€ VariableTemplater.py
β”‚       β”œβ”€β”€ FunctionTemplater.py
β”‚       β”œβ”€β”€ IfTemplater.py
β”‚       β”œβ”€β”€ EachTemplater.py
β”‚       β”œβ”€β”€ IncludeTemplater.py
β”‚       └── RenderTemplater.py
β”œβ”€β”€ tests/                       # Test suite
β”œβ”€β”€ examples/                    # Usage examples
└── pyproject.toml              # Project configuration

Adding Custom Engines

Create custom template processors by extending TemplaterInterface:

from py_template_engine.TemplaterInterface import TemplaterInterface
import re

class CustomTemplater(TemplaterInterface):
    def render(self, template: str, **kwargs) -> str:
        return re.sub(
            r'{{#CUSTOM (.*?)}}',
            lambda m: self.process(m.group(1), **kwargs),
            template
        )
    
    def process(self, content: str, **kwargs) -> str:
        # Custom processing logic
        return f"Processed: {content}"

🀝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (pytest tests)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.


Happy templating! πŸŽ‰

About

A Python template engine with support for variables, functions, conditionals, loops, and includes

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages