CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cement

Advanced Application Framework for Python with a focus on Command Line Interfaces

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

templates.mddocs/

Template System

The template system provides template rendering framework supporting multiple template engines including Jinja2 and Mustache. It enables consistent template-based output generation for applications.

Capabilities

Template Handler Interface

Base interface for template rendering functionality that defines the contract for template operations.

class TemplateHandler:
    """
    Template handler interface for rendering templates with data.
    
    Provides methods for loading template files and rendering them
    with data contexts to produce formatted output.
    """
    
    def load(self, template_path: str) -> Any:
        """
        Load a template from file path.
        
        Args:
            template_path: Path to template file to load
            
        Returns:
            Loaded template object
        """
    
    def render(self, content: str, data: Dict[str, Any]) -> str:
        """
        Render template content with data context.
        
        Args:
            content: Template content string or template object
            data: Dictionary of data to render with template
            
        Returns:
            Rendered template output string
        """

Usage Examples

Basic Template Usage

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['template.jinja2'] = {
    'template_dirs': ['./templates']
}

class TemplateController(Controller):
    class Meta:
        label = 'template'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='generate report')
    def report(self):
        """Generate report using template."""
        report_data = {
            'title': 'Monthly Report',
            'date': '2023-01-15',
            'items': [
                {'name': 'Sales', 'value': 15000, 'change': '+5%'},
                {'name': 'Expenses', 'value': 8000, 'change': '+2%'},
                {'name': 'Profit', 'value': 7000, 'change': '+8%'}
            ],
            'summary': 'Overall performance improved this month'
        }
        
        # Load and render template
        template = self.app.template.load('report.html')
        output = self.app.template.render(template, report_data)
        print(output)

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['jinja2']
        template_handler = 'jinja2'
        config_defaults = CONFIG
        handlers = [BaseController, TemplateController]

with MyApp() as app:
    app.run()

# Usage:
# myapp template report

Jinja2 Template Engine

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['template.jinja2'] = {
    'template_dirs': ['./templates', './shared_templates'],
    'auto_reload': True,
    'cache_size': 50
}

class EmailController(Controller):
    class Meta:
        label = 'email'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(
        help='send welcome email',
        arguments=[
            (['--user'], {'help': 'username', 'required': True}),
            (['--email'], {'help': 'email address', 'required': True})
        ]
    )
    def welcome(self):
        """Send welcome email using Jinja2 template."""
        user_data = {
            'username': self.app.pargs.user,
            'email': self.app.pargs.email,
            'company': 'MyCompany',
            'support_email': 'support@mycompany.com',
            'features': [
                'Dashboard access',
                'Real-time notifications', 
                'Advanced reporting',
                '24/7 support'
            ]
        }
        
        # Render email template
        template = self.app.template.load('welcome_email.html')
        email_html = self.app.template.render(template, user_data)
        
        print(f"Welcome email generated for {user_data['username']}")
        print("=" * 50)
        print(email_html)

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['jinja2']
        template_handler = 'jinja2'
        config_defaults = CONFIG
        handlers = [BaseController, EmailController]

with MyApp() as app:
    app.run()

# Example template: templates/welcome_email.html
"""
<!DOCTYPE html>
<html>
<head>
    <title>Welcome to {{ company }}</title>
</head>
<body>
    <h1>Welcome, {{ username }}!</h1>
    
    <p>Thank you for joining {{ company }}. Your account ({{ email }}) is now active.</p>
    
    <h2>Available Features:</h2>
    <ul>
    {% for feature in features %}
        <li>{{ feature }}</li>
    {% endfor %}
    </ul>
    
    <p>Need help? Contact us at {{ support_email }}</p>
    
    <p>Best regards,<br>
    The {{ company }} Team</p>
</body>
</html>
"""

# Usage:
# myapp email welcome --user johndoe --email john@example.com

Mustache Template Engine

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['template.mustache'] = {
    'template_dirs': ['./mustache_templates']
}

class ConfigController(Controller):
    class Meta:
        label = 'config'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='generate configuration file')
    def generate(self):
        """Generate configuration file using Mustache template."""
        config_data = {
            'app_name': 'MyApplication',
            'version': '1.0.0',
            'database': {
                'host': 'localhost',
                'port': 5432,
                'name': 'myapp_db'
            },
            'features': [
                {'name': 'authentication', 'enabled': True},
                {'name': 'caching', 'enabled': True},
                {'name': 'logging', 'enabled': True},
                {'name': 'monitoring', 'enabled': False}
            ],
            'debug_mode': False
        }
        
        # Render configuration template
        template = self.app.template.load('app_config.mustache')
        config_output = self.app.template.render(template, config_data)
        
        print("Generated configuration:")
        print("=" * 40)
        print(config_output)

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['mustache']
        template_handler = 'mustache'
        config_defaults = CONFIG
        handlers = [BaseController, ConfigController]

with MyApp() as app:
    app.run()

# Example template: mustache_templates/app_config.mustache
"""
# {{ app_name }} Configuration
# Version: {{ version }}

[application]
name = {{ app_name }}
version = {{ version }}
debug = {{ debug_mode }}

[database]
host = {{ database.host }}
port = {{ database.port }}
name = {{ database.name }}

[features]
{{#features}}
{{name}} = {{enabled}}
{{/features}}
"""

# Usage:
# myapp config generate

Template with Custom Filters

from cement import App, Controller, ex, init_defaults
import datetime

CONFIG = init_defaults('myapp')
CONFIG['template.jinja2'] = {
    'template_dirs': ['./templates']
}

def datetime_filter(timestamp, format='%Y-%m-%d %H:%M:%S'):
    """Custom Jinja2 filter for datetime formatting."""
    if isinstance(timestamp, str):
        dt = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
    else:
        dt = timestamp
    return dt.strftime(format)

def currency_filter(amount, symbol='$'):
    """Custom Jinja2 filter for currency formatting."""
    return f"{symbol}{amount:,.2f}"

class ReportController(Controller):
    class Meta:
        label = 'report'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='generate sales report')
    def sales(self):
        """Generate sales report with custom filters."""
        sales_data = {
            'report_title': 'Q1 Sales Report',
            'generated_at': '2023-01-15T10:30:00Z',
            'total_sales': 125000.50,
            'transactions': [
                {
                    'date': '2023-01-10T14:30:00Z',
                    'customer': 'Acme Corp',
                    'amount': 15000.00,
                    'status': 'completed'
                },
                {
                    'date': '2023-01-12T09:15:00Z', 
                    'customer': 'Beta LLC',
                    'amount': 8500.75,
                    'status': 'completed'
                }
            ]
        }
        
        # Add custom filters to Jinja2 environment
        self.app.template.env.filters['datetime'] = datetime_filter
        self.app.template.env.filters['currency'] = currency_filter
        
        # Render report
        template = self.app.template.load('sales_report.html')
        report_html = self.app.template.render(template, sales_data)
        
        print(report_html)

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['jinja2']
        template_handler = 'jinja2'
        config_defaults = CONFIG
        handlers = [BaseController, ReportController]

with MyApp() as app:
    app.run()

# Example template using custom filters: templates/sales_report.html
"""
<h1>{{ report_title }}</h1>
<p>Generated: {{ generated_at | datetime('%B %d, %Y at %I:%M %p') }}</p>

<h2>Summary</h2>
<p>Total Sales: {{ total_sales | currency }}</p>

<h2>Transactions</h2>
<table>
    <tr>
        <th>Date</th>
        <th>Customer</th>
        <th>Amount</th>
        <th>Status</th>
    </tr>
    {% for transaction in transactions %}
    <tr>
        <td>{{ transaction.date | datetime('%m/%d/%Y') }}</td>
        <td>{{ transaction.customer }}</td>
        <td>{{ transaction.amount | currency }}</td>
        <td>{{ transaction.status | title }}</td>
    </tr>
    {% endfor %}
</table>
"""

# Usage:
# myapp report sales

Template Inheritance

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['template.jinja2'] = {
    'template_dirs': ['./templates']
}

class PageController(Controller):
    class Meta:
        label = 'page'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='generate dashboard page')
    def dashboard(self):
        """Generate dashboard page using template inheritance."""
        dashboard_data = {
            'page_title': 'Dashboard',
            'user': {
                'name': 'John Doe',
                'role': 'Administrator'
            },
            'stats': [
                {'label': 'Total Users', 'value': 1250, 'trend': 'up'},
                {'label': 'Active Sessions', 'value': 89, 'trend': 'up'},
                {'label': 'System Load', 'value': '65%', 'trend': 'stable'}
            ],
            'recent_activity': [
                'User johndoe logged in',
                'New user registered: alice',
                'System backup completed'
            ]
        }
        
        template = self.app.template.load('dashboard.html')
        page_html = self.app.template.render(template, dashboard_data)
        
        print(page_html)

class BaseController(Controller):
    class Meta:
        label = 'base'

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['jinja2']
        template_handler = 'jinja2'
        config_defaults = CONFIG
        handlers = [BaseController, PageController]

with MyApp() as app:
    app.run()

# Base template: templates/base.html
"""
<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}MyApp{% endblock %}</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        .header { background: #f0f0f0; padding: 10px; }
        .content { margin: 20px 0; }
        .footer { border-top: 1px solid #ccc; padding: 10px; }
    </style>
</head>
<body>
    <div class="header">
        <h1>{% block header %}MyApp{% endblock %}</h1>
        {% block nav %}
        <nav>
            <a href="/">Home</a> |
            <a href="/dashboard">Dashboard</a> |
            <a href="/settings">Settings</a>
        </nav>
        {% endblock %}
    </div>
    
    <div class="content">
        {% block content %}{% endblock %}
    </div>
    
    <div class="footer">
        {% block footer %}
        <p>&copy; 2023 MyApp. All rights reserved.</p>
        {% endblock %}
    </div>
</body>
</html>
"""

# Dashboard template: templates/dashboard.html
"""
{% extends "base.html" %}

{% block title %}{{ page_title }} - MyApp{% endblock %}

{% block header %}{{ page_title }}{% endblock %}

{% block content %}
<p>Welcome back, {{ user.name }} ({{ user.role }})</p>

<h2>System Statistics</h2>
<div class="stats">
    {% for stat in stats %}
    <div class="stat-item">
        <strong>{{ stat.label }}:</strong> {{ stat.value }}
        <span class="trend-{{ stat.trend }}">{{ stat.trend }}</span>
    </div>
    {% endfor %}
</div>

<h2>Recent Activity</h2>
<ul>
    {% for activity in recent_activity %}
    <li>{{ activity }}</li>
    {% endfor %}
</ul>
{% endblock %}
"""

# Usage:
# myapp page dashboard

Install with Tessl CLI

npx tessl i tessl/pypi-cement

docs

arguments.md

caching.md

configuration.md

controllers.md

extensions.md

foundation.md

hooks.md

index.md

interface-handler.md

logging.md

mail.md

output.md

plugins.md

templates.md

utilities.md

tile.json