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

output.mddocs/

Output Rendering

The output rendering system provides flexible output formatting and presentation capabilities supporting multiple formats including JSON, tabular, and template-based output. It ensures consistent data presentation across different output handlers.

Capabilities

Output Handler Interface

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

class OutputHandler:
    """
    Output handler interface for rendering application data.
    
    Provides methods for rendering data structures into formatted
    output using various presentation formats and templates.
    """
    
    def render(self, data: Dict[str, Any], template: str = None) -> str:
        """
        Render data using the output handler.
        
        Args:
            data: Dictionary of data to render
            template: Optional template name for template-based rendering
            
        Returns:
            Rendered output string
        """

Usage Examples

Basic Output Rendering

from cement import App, Controller, ex

class BaseController(Controller):
    class Meta:
        label = 'base'
    
    @ex(help='show user information')
    def user_info(self):
        """Show user information with basic rendering."""
        user_data = {
            'id': 12345,
            'name': 'John Doe',
            'email': 'john@example.com',
            'status': 'active',
            'last_login': '2023-01-15T10:30:00Z',
            'permissions': ['read', 'write', 'admin']
        }
        
        # Render using configured output handler
        output = self.app.render(user_data)
        print(output)
    
    @ex(help='show system status')
    def status(self):
        """Show system status information."""
        status_data = {
            'system': 'MyApp',
            'version': '1.0.0',
            'uptime': '5 days, 3 hours',
            'memory_usage': '256MB',
            'cpu_usage': '15%',
            'active_users': 42,
            'services': {
                'database': 'online',
                'cache': 'online',
                'queue': 'online'
            }
        }
        
        output = self.app.render(status_data)
        print(output)

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [BaseController]

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

# Usage:
# myapp user-info
# myapp status

JSON Output Handler

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['output.json'] = {
    'indent': 2,
    'sort_keys': True
}

class DataController(Controller):
    class Meta:
        label = 'data'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='export data as JSON')
    def export(self):
        """Export application data as JSON."""
        export_data = {
            'export_info': {
                'timestamp': '2023-01-15T10:30:00Z',
                'format': 'json',
                'version': '1.0'
            },
            'users': [
                {'id': 1, 'name': 'Alice', 'role': 'admin'},
                {'id': 2, 'name': 'Bob', 'role': 'user'},
                {'id': 3, 'name': 'Charlie', 'role': 'user'}
            ],
            'settings': {
                'theme': 'dark',
                'notifications': True,
                'auto_backup': False
            }
        }
        
        # Render as JSON
        json_output = self.app.render(export_data)
        print(json_output)

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

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['json']
        output_handler = 'json'
        config_defaults = CONFIG
        handlers = [BaseController, DataController]

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

# Usage:
# myapp data export

Tabular Output Handler

from cement import App, Controller, ex, init_defaults

CONFIG = init_defaults('myapp')
CONFIG['output.tabulate'] = {
    'tablefmt': 'grid',  # grid, simple, plain, html, etc.
    'headers': 'keys'
}

class ReportController(Controller):
    class Meta:
        label = 'report'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    @ex(help='show user report')
    def users(self):
        """Show user report in tabular format."""
        # Data structured for tabular output
        user_report = {
            'users': [
                {'ID': 1, 'Name': 'Alice Johnson', 'Email': 'alice@example.com', 'Status': 'Active'},
                {'ID': 2, 'Name': 'Bob Smith', 'Email': 'bob@example.com', 'Status': 'Inactive'},
                {'ID': 3, 'Name': 'Charlie Brown', 'Email': 'charlie@example.com', 'Status': 'Active'},
                {'ID': 4, 'Name': 'Diana Prince', 'Email': 'diana@example.com', 'Status': 'Active'}
            ]
        }
        
        # Render as table
        table_output = self.app.render(user_report)
        print(table_output)
    
    @ex(help='show system metrics')
    def metrics(self):
        """Show system metrics in tabular format."""
        metrics_data = {
            'metrics': [
                {'Metric': 'CPU Usage', 'Value': '15%', 'Threshold': '80%', 'Status': 'OK'},
                {'Metric': 'Memory Usage', 'Value': '256MB', 'Threshold': '1GB', 'Status': 'OK'},
                {'Metric': 'Disk Usage', 'Value': '45GB', 'Threshold': '100GB', 'Status': 'Warning'},
                {'Metric': 'Active Users', 'Value': '42', 'Threshold': '100', 'Status': 'OK'}
            ]
        }
        
        output = self.app.render(metrics_data)
        print(output)

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

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

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

# Usage:
# myapp report users
# myapp report metrics

Template-Based Output

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 user report')
    def user_report(self):
        """Generate user report using template."""
        report_data = {
            'title': 'User Activity Report',
            'generated_at': '2023-01-15 10:30:00',
            'users': [
                {
                    'name': 'Alice Johnson',
                    'email': 'alice@example.com',
                    'last_login': '2023-01-14',
                    'actions': 25,
                    'status': 'active'
                },
                {
                    'name': 'Bob Smith', 
                    'email': 'bob@example.com',
                    'last_login': '2023-01-10',
                    'actions': 12,
                    'status': 'inactive'
                }
            ],
            'summary': {
                'total_users': 2,
                'active_users': 1,
                'total_actions': 37
            }
        }
        
        # Render using template
        output = self.app.render(report_data, template='user_report.txt')
        print(output)
    
    @ex(help='generate system summary')
    def system_summary(self):
        """Generate system summary using template."""
        system_data = {
            'system_name': 'MyApp Production',
            'version': '1.0.0',
            'environment': 'production',
            'services': [
                {'name': 'Web Server', 'status': 'running', 'uptime': '5d 3h'},
                {'name': 'Database', 'status': 'running', 'uptime': '10d 2h'},
                {'name': 'Cache', 'status': 'running', 'uptime': '5d 3h'},
                {'name': 'Queue', 'status': 'running', 'uptime': '3d 1h'}
            ],
            'alerts': [
                {'level': 'warning', 'message': 'Disk usage above 80%'},
                {'level': 'info', 'message': 'Scheduled maintenance in 2 days'}
            ]
        }
        
        output = self.app.render(system_data, template='system_summary.txt')
        print(output)

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

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

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

# Usage:
# myapp template user-report
# myapp template system-summary

# Example template file: templates/user_report.txt
"""
{{ title }}
Generated: {{ generated_at }}

User Summary:
- Total Users: {{ summary.total_users }}
- Active Users: {{ summary.active_users }}
- Total Actions: {{ summary.total_actions }}

User Details:
{% for user in users %}
- {{ user.name }} ({{ user.email }})
  Last Login: {{ user.last_login }}
  Actions: {{ user.actions }}
  Status: {{ user.status }}
{% endfor %}
"""

Dynamic Output Handler Selection

from cement import App, Controller, ex

class OutputController(Controller):
    class Meta:
        label = 'output'
        stacked_on = 'base'
        stacked_type = 'nested'
        arguments = [
            (['--format'], {
                'choices': ['json', 'table', 'yaml'],
                'default': 'json',
                'help': 'output format'
            })
        ]
    
    @ex(help='show data in different formats')
    def show(self):
        """Show data in user-specified format."""
        data = {
            'application': 'MyApp',
            'users': [
                {'id': 1, 'name': 'Alice', 'active': True},
                {'id': 2, 'name': 'Bob', 'active': False}
            ],
            'stats': {
                'total_users': 2,
                'active_users': 1
            }
        }
        
        # Get desired format from arguments
        output_format = self.app.pargs.format
        
        # Temporarily switch output handler
        original_handler = self.app._meta.output_handler
        
        if output_format == 'json':
            self.app._setup_output_handler('json')
        elif output_format == 'table':
            self.app._setup_output_handler('tabulate')
        elif output_format == 'yaml':
            self.app._setup_output_handler('yaml')
        
        # Render with selected handler
        output = self.app.render(data)
        print(output)
        
        # Restore original handler
        self.app._setup_output_handler(original_handler)

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

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        extensions = ['json', 'tabulate', 'yaml']
        handlers = [BaseController, OutputController]

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

# Usage:
# myapp output show --format json
# myapp output show --format table
# myapp output show --format yaml

Custom Output Processing

from cement import App, Controller, ex
import csv
import io

class CsvController(Controller):
    class Meta:
        label = 'csv'
        stacked_on = 'base'
        stacked_type = 'nested'
    
    def render_csv(self, data):
        """Custom CSV rendering method."""
        if not isinstance(data, dict) or 'rows' not in data:
            raise ValueError("CSV data must contain 'rows' key")
        
        output = io.StringIO()
        
        # Get headers from first row or use provided headers
        rows = data['rows']
        if not rows:
            return ''
        
        headers = data.get('headers', list(rows[0].keys()))
        
        writer = csv.DictWriter(output, fieldnames=headers)
        writer.writeheader()
        
        for row in rows:
            writer.writerow(row)
        
        return output.getvalue()
    
    @ex(help='export data as CSV')
    def export(self):
        """Export data in CSV format."""
        csv_data = {
            'headers': ['ID', 'Name', 'Email', 'Status'],
            'rows': [
                {'ID': 1, 'Name': 'Alice Johnson', 'Email': 'alice@example.com', 'Status': 'Active'},
                {'ID': 2, 'Name': 'Bob Smith', 'Email': 'bob@example.com', 'Status': 'Inactive'},
                {'ID': 3, 'Name': 'Charlie Brown', 'Email': 'charlie@example.com', 'Status': 'Active'}
            ]
        }
        
        # Use custom CSV rendering
        csv_output = self.render_csv(csv_data)
        print(csv_output)
    
    @ex(
        help='save data to CSV file',
        arguments=[
            (['--output', '-o'], {
                'help': 'output file path',
                'default': 'data.csv'
            })
        ]
    )
    def save(self):
        """Save data to CSV file."""
        csv_data = {
            'rows': [
                {'Product': 'Widget A', 'Price': 19.99, 'Stock': 100},
                {'Product': 'Widget B', 'Price': 29.99, 'Stock': 50},
                {'Product': 'Widget C', 'Price': 39.99, 'Stock': 25}
            ]
        }
        
        csv_output = self.render_csv(csv_data)
        
        output_file = self.app.pargs.output
        with open(output_file, 'w') as f:
            f.write(csv_output)
        
        print(f'Data saved to {output_file}')

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

class MyApp(App):
    class Meta:
        label = 'myapp'
        base_controller = 'base'
        handlers = [BaseController, CsvController]

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

# Usage:
# myapp csv export
# myapp csv save --output users.csv

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