Advanced Application Framework for Python with a focus on Command Line Interfaces
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
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
"""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 statusfrom 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 exportfrom 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 metricsfrom 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 %}
"""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 yamlfrom 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.csvInstall with Tessl CLI
npx tessl i tessl/pypi-cement