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.3.tar.gz (39.8 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.3-py3-none-any.whl (49.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: layoutml-1.0.3.tar.gz
  • Upload date:
  • Size: 39.8 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.3.tar.gz
Algorithm Hash digest
SHA256 e5ca231082e5cba56dd5544af4a1ad7e220a6de0ed3ec63a10ed5a32f40ce6dd
MD5 17bf05873ea110e64bba4850b66e7379
BLAKE2b-256 84cd240bfa86a403ae1aa65ae02cdcc67956b7366e34f334d82f4ad4fbbcd417

See more details on using hashes here.

File details

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

File metadata

  • Download URL: layoutml-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 49.5 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.3-py3-none-any.whl
Algorithm Hash digest
SHA256 84ae9d36ddb27d110c2cab30c1feb6df2993d3c803b09e2131f6e7275aea2449
MD5 24c37bb57b9ab8f8889e1195e029462f
BLAKE2b-256 f1946ae49c26f3542f1aa44f722ef8d18e4f9ad4e702b1deafba10883a9105a9

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