Skip to main content

LayoutML - a library for creating HTML pages using Python

Project description

LayoutML

LayoutML (Layout Markup Library) is a library that allows you to describe the structure of web pages directly in code, turning Python into a markup language for web interfaces.

Key Features

  • Create HTML elements using Python classes
  • Define CSS styles programmatically
  • Component-based approach (reusable layout blocks)
  • Clean and declarative syntax
  • Generate pure HTML/CSS without unnecessary code
  • Easy integration with FastAPI, Flask, Django
  • Lightweight with no external dependencies

Who is it for

  • Python developers who don’t want to write HTML manually
  • Backend developers (FastAPI / Django / Flask)
  • Educational projects
  • Generating HTML reports and interfaces
  • Building custom web frameworks on top of LayoutML

Contents

Core Classes

Base Elements

Semantic Elements

  • Header - Semantic <header> element
  • Main - Semantic <main> element
  • Footer - Semantic <footer> element
  • Nav - Semantic <nav> element
  • Section - Semantic <section> element
  • Article - Semantic <article> element
  • Aside - Semantic <aside> element

Text Elements

Media Elements

Form Elements

Layout

Document Structure

Routing

Application

Quick Start

Installation

pip install layoutml

Example Usage

This section provides examples of building web applications using LayoutML. You will learn how to create pages, add elements, and run the server.

Basic Run

The simplest way to run a LayoutML application:

from layoutml import LayoutML, Page
from layoutml.elements import Header, Paragraph, Button

class BasePage(Page):
    def __init__(self, doctype="html", title="LayoutML", lang="en", object_name=None, **kwargs):
        super().__init__(doctype, title, lang, object_name, **kwargs)
        self.head.set_icon("ico/logo.ico")


# Create the application
app = LayoutML()

# Define a route
@app.route("/")
def home():
    page = BasePage(title="Home")

    # Create elements
    header = Header()
    header.get_html(content="<h1>Welcome!</h1>")

    paragraph = Paragraph(text="This is an example of using LayoutML")

    button = Button(text="Click me", onclick="alert('Hello!')")

    # Add elements to the page
    page.body.add_element(header)
    page.body.add_element(paragraph)
    page.body.add_element(button)

    return page

# Run the application
if __name__ == "__main__":
    app.start(host="localhost", port=3700)

Running via Uvicorn from the Command Line

You can run the application using Uvicorn from the terminal:

pip install uvicorn
uvicorn main:app --host localhost --port 3700 --reload

Where main is the name of your Python file, and app is the name of your LayoutML application instance.

Running via Uvicorn from Python Code

You can also run Uvicorn directly from a Python script:

if __name__ == "__main__":
    uvicorn.run(app, host="localhost", port=3700)

Creating Multiple Routes

Example of an application with multiple pages:

from layoutml import LayoutML, Page
from layoutml.elements import Header, Paragraph, Button, Anchor

app = LayoutML()

@app.route("/")
def home():
    page = Page(title="Home")

    header = Header()
    header.get_html(content="<h1>Home Page</h1>")

    paragraph = Paragraph(text="Welcome to our website!")

    link = Anchor(href="/about", text="About Us")

    page.body.add_element(header)
    page.body.add_element(paragraph)
    page.body.add_element(link)

    return page

@app.route("/about")
def about():
    page = Page(title="About")

    header = Header()
    header.get_html(content="<h1>About Our Company</h1>")

    paragraph = Paragraph(text="We build web applications using LayoutML")

    back_link = Anchor(href="/", text="Back to Home")

    page.body.add_element(header)
    page.body.add_element(paragraph)
    page.body.add_element(back_link)

    return page

if __name__ == "__main__":
    app.start()

Using Route Parameters

You can create dynamic pages with parameters in the URL:

from layoutml import LayoutML, Page
from layoutml.elements import Header, Paragraph

app = LayoutML()

@app.route("/user/<username>")
def user_profile(username: str):
    page = Page(title=f"Profile {username}")

    header = Header()
    header.get_html(content=f"<h1>User Profile: {username}</h1>")

    paragraph = Paragraph(text=f"Welcome, {username}!")

    page.body.add_element(header)
    page.body.add_element(paragraph)

    return page

if __name__ == "__main__":
    app.start()

Adding CSS Styles

Example of a page with custom styles:

from layoutml import LayoutML, Page
from layoutml.elements import Header, Paragraph, Button

app = LayoutML()

@app.route("/")
def styled_page():
    page = Page(title="Styled Page")

    # Create an element with CSS classes
    header = Header(class_="main-header")
    header.get_html(content="<h1>Styled Page</h1>")

    paragraph = Paragraph(
        text="This text is styled using CSS",
        class_="highlight-text"
    )

    button = Button(
        text="Styled Button",
        class_="custom-button",
        style="padding: 10px 20px; background: #007bff; color: white; border: none; border-radius: 5px;"
    )

    # Add CSS styles via the head object
    page.head.selectors_styles.add_selector(".main-header")\
        .set_background_color("#f8f9fa")\
        .set_padding("20px")\
        .set_text_align("center")

    page.head.selectors_styles.add_selector(".highlight-text")\
        .set_color("#007bff")\
        .set_font_size("18px")\
        .set_font_weight("bold")

    page.head.selectors_styles.add_selector(".custom-button:hover")\
        .set_background_color("#0056b3")\
        .set_transform("scale(1.05)")

    page.body.add_element(header)
    page.body.add_element(paragraph)
    page.body.add_element(button)

    return page

if __name__ == "__main__":
    app.start()

Using Layouts

Creating a page using horizontal and vertical layouts:

from layoutml import LayoutML, Page
from layoutml.elements import Header, Paragraph, Button
from layoutml.layout import HorizontalLayout, VerticalLayout

app = LayoutML()

@app.route("/")
def layout_example():
    page = Page(title="Layout Example")

    # Vertical layout for the entire page
    main_layout = VerticalLayout(object_name="mainLayout")
    main_layout.object_styles.set_gap("20px").set_padding("20px")

    # Horizontal layout for navigation
    nav_layout = HorizontalLayout(object_name="navLayout")
    nav_layout.object_styles.set_justify_content("space-between")

    nav_layout.add_element(Button(text="Home"))
    nav_layout.add_element(Button(text="About"))
    nav_layout.add_element(Button(text="Contacts"))

    # Horizontal layout for cards
    cards_layout = HorizontalLayout(object_name="cardsLayout")
    cards_layout.object_styles.set_gap("20px").set_justify_content("center")

    for i in range(3):
        card = VerticalLayout(object_name=f"card{i}")
        card.object_styles.set_border("1px solid #ddd")\
                          .set_padding("15px")\
                          .set_border_radius("8px")\
                          .set_width("200px")

        card.add_element(Paragraph(text=f"Card {i+1}"))
        card.add_element(Button(text="Learn More"))
        cards_layout.add_element(card)

    main_layout.add_elements(nav_layout, cards_layout)
    page.body.add_element(main_layout)

    return page

if __name__ == "__main__":
    app.start()

Handling Forms

Example of creating a page with a form and handling data:

from layoutml import LayoutML, Page
from layoutml.elements import Input, Button, Label, Paragraph

app = LayoutML()

@app.route("/contact", methods=["GET", "POST"])
def contact_page():
    page = Page(title="Contacts")

    page.body.add_element(Paragraph(text="Get in touch with us"))

    # Create a form
    form = BaseElement(tag="form", method="post", action="/submit")

    # Name field
    form.add_element(Label(for_id="name", text="Name:"))
    form.add_element(Input(id="name", name="name", required=True))

    # Email field
    form.add_element(Label(for_id="email", text="Email:"))
    form.add_element(Input(type="email", id="email", name="email", required=True))

    # Submit button
    form.add_element(Button(text="Submit", type="submit"))

    page.body.add_element(form)

    return page

if __name__ == "__main__":
    app.start()

Development Tips

  1. Development mode: Use the --reload flag when running via Uvicorn for automatic server reload on code changes.

  2. Debugging: You can print route information using the print_routes() method:

app.print_routes()
  1. Code organization: For larger applications, it is recommended to split routes into modules:
# routes.py
from layoutml import LayoutML

app = LayoutML()

# Import routes from other modules
from .home_routes import home_router
from .api_routes import api_router

app.include_router(home_router)
app.include_router(api_router, prefix="/api")
  1. Asynchronous handlers: LayoutML supports async functions for route handling:
@app.route("/async-data")
async def async_data():
    data = await fetch_data_from_db()
    page = Page(title="Data")
    page.body.add_element(Paragraph(text=str(data)))
    return page

))())()()() After запуск the server will be available at http://localhost:3700

Project Status

LayoutML is under active development.

📄 License

MIT License

Feedback

I am always happy to receive your feedback and suggestions for improving LayoutML. Please leave your comments.

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

layoutml-1.0.2.tar.gz (39.9 kB view details)

Uploaded Source

Built Distribution

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

layoutml-1.0.2-py3-none-any.whl (49.6 kB view details)

Uploaded Python 3

File details

Details for the file layoutml-1.0.2.tar.gz.

File metadata

  • Download URL: layoutml-1.0.2.tar.gz
  • Upload date:
  • Size: 39.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for layoutml-1.0.2.tar.gz
Algorithm Hash digest
SHA256 5ba1b8f449ff2a73e84eb7427ea228481502a4a3604d5384d01bda7049e1a88d
MD5 05a7234f661e19f00f70da349e512dab
BLAKE2b-256 235f4e987d1e406a6d5f64f7600fb6e1a2ee25edbe9d31e63ce63116ae768987

See more details on using hashes here.

File details

Details for the file layoutml-1.0.2-py3-none-any.whl.

File metadata

  • Download URL: layoutml-1.0.2-py3-none-any.whl
  • Upload date:
  • Size: 49.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.2

File hashes

Hashes for layoutml-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 9b386c98a27cd9047adbba884065553aca34e751f321c277b898a88e8a5f7d32
MD5 a9d1091067d31e51098d0de745585a0e
BLAKE2b-256 99fa5f8e81085ba60c34ff772c255d08580a3f5234f47e2fce964bf8064daa67

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