Skip to main content

Convert data structures to HTML for any Python web framework

Project description

PyStructUI 🎨

Transform data structures into beautiful UIs for any Python web framework

PyStructUI is a universal presentation layer that lets you build web UIs using pure data structures instead of HTML templates. Works with Flask, Django, FastAPI, and any Python web framework.

Why PyStructUI?

Traditional web development:

<!-- 100s of HTML template files -->
<div class="card">
  <div class="card-header">{{ title }}</div>
  <div class="card-body">{{ content }}</div>
</div>

With PyStructUI:

{'type': 'card', 'title': 'Hello', 'body': 'World'}

Benefits:

  • No HTML templates - Define UI as data
  • Framework agnostic - Works with Flask, Django, FastAPI, etc.
  • UI framework swappable - Switch between Bootstrap, Tailwind, Material with one line
  • 90% less code - Data structures are more concise than HTML
  • AI-friendly - LLMs understand data better than HTML
  • Testable - Test data structures, not HTML strings

Installation

pip install pystructui

Or install with framework support:

pip install pystructui[flask]
pip install pystructui[django]
pip install pystructui[fastapi]

Quick Start

Basic Usage

from pystructui import render

# Define UI as data
ui_data = {
    'type': 'page',
    'title': 'My App',
    'components': [
        {'type': 'navbar', 'brand': 'PyStructUI'},
        {'type': 'hero', 'title': 'Welcome!', 'subtitle': 'Build UIs with data'},
        {'type': 'button', 'text': 'Get Started', 'variant': 'primary'}
    ]
}

# Render to HTML
html = render(ui_data)

Flask Integration

from flask import Flask
from pystructui import flask_integration

app = Flask(__name__)
ui = flask_integration(app)

@app.route('/')
@ui.render
def index():
    return {
        'type': 'page',
        'title': 'Flask App',
        'components': [
            {'type': 'card', 'title': 'Hello Flask!', 'body': 'No templates needed!'}
        ]
    }

Django Integration

# views.py
from pystructui import django_integration

ui = django_integration()

def index(request):
    data = {
        'type': 'page',
        'title': 'Django App',
        'components': [
            {'type': 'navbar', 'brand': 'Django + PyStructUI'},
            {'type': 'hero', 'title': 'No templates!'}
        ]
    }
    return ui.render_response(data)

FastAPI Integration

from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pystructui import fastapi_integration

app = FastAPI()
ui = fastapi_integration()

@app.get("/", response_class=HTMLResponse)
async def index():
    data = {
        'type': 'page',
        'components': [{'type': 'card', 'title': 'FastAPI + PyStructUI'}]
    }
    return ui.render(data)

Component Reference

Page Structure

{
    'type': 'page',
    'title': 'Page Title',
    'components': [...]  # List of components
}

Navigation

{
    'type': 'navbar',
    'brand': 'My App',
    'links': [
        {'text': 'Home', 'url': '/'},
        {'text': 'About', 'url': '/about'}
    ]
}

Cards

{
    'type': 'card',
    'title': 'Card Title',
    'body': 'Card content or nested component',
    'footer': {'type': 'button', 'text': 'Action'}
}

Forms

{
    'type': 'form',
    'method': 'POST',
    'action': '/submit',
    'fields': [
        {
            'type': 'text',
            'name': 'username',
            'label': 'Username',
            'required': True
        },
        {
            'type': 'textarea',
            'name': 'message',
            'label': 'Message'
        }
    ]
}

Tables

{
    'type': 'table',
    'headers': ['Name', 'Email', 'Status'],
    'rows': [
        ['John', 'john@example.com', 'Active'],
        ['Jane', 'jane@example.com', 'Pending']
    ]
}

Grids

{
    'type': 'grid',
    'columns': 3,
    'items': [
        {'type': 'card', 'title': 'Card 1'},
        {'type': 'card', 'title': 'Card 2'},
        {'type': 'card', 'title': 'Card 3'}
    ]
}

Alerts

{
    'type': 'alert',
    'message': 'Operation successful!',
    'variant': 'success',  # success, danger, warning, info
    'dismissible': True
}

Switching UI Frameworks

from pystructui import PresentationLayer
from pystructui.renderers import BootstrapRenderer, TailwindRenderer

pl = PresentationLayer()

# Use Bootstrap
pl.add_renderer('bootstrap', BootstrapRenderer())
html = pl.render(data, 'bootstrap')

# Switch to Tailwind - same data, different output!
pl.add_renderer('tailwind', TailwindRenderer())
html = pl.render(data, 'tailwind')

Custom Renderers

Create your own renderer for any UI framework:

from pystructui import Renderer

class CustomRenderer(Renderer):
    def render(self, data):
        # Your rendering logic
        return html

    def render_component(self, component):
        # Component rendering
        return html

# Use it
pl.add_renderer('custom', CustomRenderer())

Advanced Features

Nested Components

Components can be nested infinitely:

{
    'type': 'card',
    'body': {
        'type': 'grid',
        'columns': 2,
        'items': [
            {'type': 'button', 'text': 'Yes'},
            {'type': 'button', 'text': 'No'}
        ]
    }
}

Raw HTML

When needed, include raw HTML:

{
    'type': 'raw',
    'content': '<custom-element>Custom HTML</custom-element>'
}

Dynamic Rendering

Use Python to generate dynamic UIs:

def dashboard(user_data):
    return {
        'type': 'grid',
        'columns': 3,
        'items': [
            {
                'type': 'card',
                'title': metric['name'],
                'body': metric['value']
            }
            for metric in user_data.metrics
        ]
    }

Why Data Structures?

  1. Simplicity - No template syntax to learn
  2. Portability - Same structure works with any renderer
  3. Testability - Assert on data, not HTML strings
  4. AI-friendly - LLMs excel at data transformation
  5. Version control - Data diffs are cleaner than HTML diffs
  6. Performance - No template compilation overhead

Comparison

Traditional Django Template

{% extends "base.html" %}
{% block content %}
<div class="container">
  <div class="row">
    {% for item in items %}
    <div class="col-md-4">
      <div class="card">
        <div class="card-body">
          <h5 class="card-title">{{ item.title }}</h5>
          <p class="card-text">{{ item.description }}</p>
          <a href="{{ item.url }}" class="btn btn-primary">View</a>
        </div>
      </div>
    </div>
    {% endfor %}
  </div>
</div>
{% endblock %}

With PyStructUI

{
    'type': 'grid',
    'columns': 3,
    'items': [
        {
            'type': 'card',
            'title': item['title'],
            'body': item['description'],
            'footer': {'type': 'button', 'text': 'View', 'url': item['url']}
        }
        for item in items
    ]
}

Real-World Example

Building a complete todo app:

from flask import Flask
from pystructui import flask_integration

app = Flask(__name__)
ui = flask_integration(app)

todos = []

@app.route('/')
@ui.render
def index():
    return {
        'type': 'page',
        'components': [
            {'type': 'navbar', 'brand': 'Todo App'},
            {
                'type': 'card',
                'title': 'My Todos',
                'body': {
                    'type': 'table',
                    'headers': ['Task', 'Status'],
                    'rows': [[t['text'], t['status']] for t in todos]
                }
            }
        ]
    }

# That's it! No templates needed!

Contributing

We welcome contributions! PyStructUI is designed to be extensible:

  • Add new component types
  • Create renderers for more UI frameworks
  • Add framework integrations
  • Improve documentation

License

MIT License - Use PyStructUI in any project!

Philosophy

"Code is about data structures. UI should be too."

PyStructUI embraces the fundamental truth that all programming is data transformation. Instead of mixing logic with presentation through templates, we keep them separate: logic produces data, renderers transform data to UI.

This is the future of web development - where humans define intent through data structures, and machines handle the implementation details.

Support


Built with ❤️ by the DBBasic team. Part of the movement to make web development simpler, faster, and more enjoyable.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pystructui-0.1.0.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pystructui-0.1.0-py3-none-any.whl (11.1 kB view details)

Uploaded Python 3

File details

Details for the file pystructui-0.1.0.tar.gz.

File metadata

  • Download URL: pystructui-0.1.0.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.1

File hashes

Hashes for pystructui-0.1.0.tar.gz
Algorithm Hash digest
SHA256 65b770a9a57c1d7d1f6938df4fcc1ed5acf0b152eda0fe726f447c054b948ae6
MD5 d183beef59a50e6309e43abf77a0c52d
BLAKE2b-256 a188b7aa3341847a97dc5391d3e8a9148a5a6fd0ca805045d9cf05cb696ea69d

See more details on using hashes here.

File details

Details for the file pystructui-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: pystructui-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.1

File hashes

Hashes for pystructui-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 849fc5f21f14ac2834ea5b752f08fc55f8add62cd407cf87a364941300d9d1da
MD5 0f16c19fb72e56f539285f59c82eab7c
BLAKE2b-256 96e1351c8c4ace9363c26254a1012d08e8078b2ff66eb19d4c5df98b15da3a5c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page