PyLage
PyLage is a Python-first framework for building reactive web interfaces with components, state, routing, layouts, forms, navigation, dashboards, charts, themes, and application-level page patterns.
Current release: 1.0.7
PyLage is designed around a simple idea:
import pylage as pl
count = pl.state(0)
app = pl.column(
pl.heading("Counter"),
pl.text(count),
pl.button("Increment", on_click=lambda: count.set(count.value + 1)),
)
pl.run(app)
Why PyLage?
- Python-first UI development
- Reactive state and derived state
- Composable components
- Built-in layouts and page patterns
- Forms and input components
- Navigation and Drawer components
- File-system routing
- Charts and data components
- Themes and styling
- Local development server
- Production-oriented serving options
- Public API available directly from
pylage
The recommended application style is:
import pylage as pl
PyLage's internal ENGINE and UI packages are implementation details and should not be required by application code.
Installation
Install the released package:
pip install pylage
Then create an application:
import pylage as pl
app = pl.column(
pl.heading("Hello, PyLage"),
pl.text("My first PyLage application."),
)
pl.run(app)
Quickstart
A minimal application:
import pylage as pl
app = pl.column(
pl.heading("Welcome"),
pl.text("Built with PyLage."),
pl.button("Get Started"),
)
pl.run(app)
A reactive application:
import pylage as pl
count = pl.state(0)
app = pl.column(
pl.heading("Counter"),
pl.text(count),
pl.button(
"Increment",
on_click=lambda: count.set(count.value + 1),
),
)
pl.run(app)
A complete application can also be split into pages and launched through the router:
import pylage as pl
pl.run(
pages_dir="pages",
title="My PyLage App",
serve=True,
port=3000,
)
Core Concepts
State
state() creates reactive state.
import pylage as pl
name = pl.state("PyLage")
app = pl.column(
pl.heading("Hello"),
pl.text(name),
)
State can be changed from event handlers:
count = pl.state(0)
pl.button(
"Increment",
on_click=lambda: count.set(count.value + 1),
)
Derived State
Use derived() when a value depends on other state values.
import pylage as pl
first = pl.state("Py")
second = pl.state("Lage")
full_name = pl.derived(
first,
second,
compute=lambda a, b: a + b,
)
app = pl.column(
pl.text(first),
pl.text(second),
pl.heading(full_name),
)
Conditional Rendering
cond() selects between two branches using reactive state.
import pylage as pl
logged_in = pl.state(False)
app = pl.column(
pl.button(
"Toggle",
on_click=lambda: logged_in.set(not logged_in.value),
),
pl.cond(
logged_in,
pl.text("Welcome back!"),
pl.text("Please sign in."),
),
)
Reactive Lists
reactive_list() creates a reactive collection.
import pylage as pl
items = pl.reactive_list(["Python", "PyLage", "Web"])
Render the collection with for_each():
app = pl.column(
pl.for_each(
items,
lambda item: pl.text(item),
),
)
Layout
PyLage provides several composable layout primitives.
Column
pl.column(
pl.heading("Column"),
pl.text("Item one"),
pl.text("Item two"),
)
Row
pl.row(
pl.button("Save"),
pl.button("Cancel"),
)
Stack
pl.stack(
pl.text("Background"),
pl.button("Action"),
)
Grid
pl.grid(
pl.card(pl.text("One")),
pl.card(pl.text("Two")),
pl.card(pl.text("Three")),
)
Center
pl.center(
pl.heading("Centered content"),
)
Container
pl.container(
pl.heading("Content"),
pl.text("Contained content"),
)
Section
pl.section(
pl.heading("Section"),
pl.text("Section content"),
)
Split
pl.split(
pl.column(pl.heading("Left")),
pl.column(pl.heading("Right")),
)
Two Column
pl.two_column(
pl.card(pl.text("Left")),
pl.card(pl.text("Right")),
)
Three Column
pl.three_column(
pl.card(pl.text("One")),
pl.card(pl.text("Two")),
pl.card(pl.text("Three")),
)
Basic UI Components
Text
pl.text("Hello PyLage")
pl.text("Muted text", muted=True)
pl.text("Caption", caption=True)
Heading
pl.heading("Dashboard")
Card
pl.card(
heading="Profile",
body=pl.text("User information"),
footer=pl.button("Edit"),
)
Cards can also be composed:
pl.card(
pl.heading("Card title"),
pl.text("Card content"),
)
Badge
pl.badge("Active")
pl.badge("Warning", variant="warning")
Avatar
pl.avatar(
pl.image(src="/avatar.png", alt="User"),
)
Icon
pl.icon(name="home")
Image
pl.image(
src="/images/hero.png",
alt="PyLage application",
)
Divider
pl.divider()
List
pl.list(
"Python",
"PyLage",
"Reactive UI",
)
Menu
pl.menu(
pl.navigation_item("Home"),
pl.navigation_item("Settings"),
)
Buttons and Links
Button
pl.button("Save")
Variants and sizes can be specified:
pl.button(
"Delete",
variant="danger",
size="sm",
)
Link
pl.link(
"Documentation",
href="/docs",
)
Forms & Inputs
Input
name = pl.state("")
pl.input(
value=name,
placeholder="Your name",
)
Textarea
pl.textarea(
value="",
placeholder="Write something...",
)
Checkbox
pl.checkbox(
value=False,
label="Accept terms",
)
Switch
pl.switch(
value=False,
label="Enable notifications",
)
Select
pl.select(
pl.option("Python", value="python"),
pl.option("JavaScript", value="javascript"),
pl.option("Rust", value="rust"),
)
Option
pl.option("Python", value="python")
Radio Group
pl.radio_group(
pl.option("Small", value="sm"),
pl.option("Medium", value="md"),
pl.option("Large", value="lg"),
)
Slider
pl.slider(
value=50,
min=0,
max=100,
)
Datepicker
pl.datepicker()
Form Field
Wrap an input with a label and validation information:
pl.form_field(
pl.input(),
label="Username",
help_text="Choose a unique username.",
required=True,
)
Form
pl.form(
pl.form_field(
pl.input(),
label="Name",
required=True,
),
pl.form_field(
pl.input(input_type="email"),
label="Email",
required=True,
),
pl.button("Submit"),
)
Search Bar
pl.search_bar(
placeholder="Search projects...",
button_text="Search",
)
Feedback, Dialogs & Overlays
Alert
pl.alert(
"Your changes were saved.",
variant="success",
)
Toast
pl.toast(
"Saved successfully.",
variant="success",
)
Modal
pl.modal(
pl.text("Modal content"),
open=True,
title="Example Modal",
)
Dialog
pl.dialog(
pl.heading("Dialog"),
pl.text("Dialog content"),
)
Confirmation Dialog
pl.confirmation_dialog(
"Delete this item?",
title="Confirm deletion",
open=True,
confirm_text="Delete",
cancel_text="Cancel",
)
Popover
pl.popover(
pl.button("Open details"),
pl.text("Additional information"),
)
Tooltip
pl.tooltip(
pl.button("Help"),
)
Loading
pl.loading()
Custom loading text:
pl.loading("Loading projects...")
Loading State
pl.loading_state(
"Loading dashboard...",
description="Fetching the latest data.",
)
Loading Overlay
pl.loading_overlay(
"Saving...",
open=True,
)
Spinner
pl.spinner()
Skeleton
pl.skeleton()
Empty State
pl.empty_state(
"No projects",
"Create a project to get started.",
)
Error State
pl.error_state(
"Unable to load projects",
"Please try again.",
)
Progress Bar
pl.progress_bar(value=65)
Navigation
Navigation
pl.navigation(
pl.navigation_item("Home", current_path="/"),
pl.navigation_item("Projects", current_path="/projects"),
pl.navigation_item("Settings", current_path="/settings"),
)
Navigation Item
pl.navigation_item(
"Dashboard",
active=True,
)
With a path:
pl.navigation_item(
"Projects",
current_path="/projects",
)
With reactive routing state:
current_path = pl.state("/dashboard")
pl.navigation_item(
"Dashboard",
current_path=current_path,
)
Navigation Controls
pl.navigation_controls(
on_prev=lambda: None,
on_next=lambda: None,
)
Navbar
pl.navbar(
pl.link("Home", href="/"),
pl.link("Projects", href="/projects"),
)
Topbar
pl.topbar(
pl.heading("My Application"),
)
Top Header
pl.top_header(
pl.heading("Dashboard"),
)
Breadcrumb Trail
pl.breadcrumb_trail(
pl.link("Home", href="/"),
pl.link("Projects", href="/projects"),
current_path="/projects",
)
Sidebar Layout
pl.sidebar_layout(
sidebar=pl.navigation(
pl.navigation_item("Home", current_path="/"),
pl.navigation_item("Projects", current_path="/projects"),
),
content=pl.text("Page content"),
)
Drawer Navigation
PyLage provides three public Drawer-oriented APIs.
Drawer
pl.drawer(
pl.heading("Menu"),
pl.navigation_item("Home"),
pl.navigation_item("Projects"),
)
Navigation Drawer
pl.navigation_drawer(
pl.navigation_item("Dashboard"),
pl.navigation_item("Projects"),
pl.navigation_item("Settings"),
)
Mobile Sidebar
pl.mobile_sidebar(
pl.navigation_item("Home"),
pl.navigation_item("Projects"),
responsive_mode={
"base": "overlay",
"md": "persistent",
},
)
A Drawer can contain arbitrary PyLage content:
pl.drawer(
pl.heading("Workspace"),
pl.text("Navigation"),
pl.button("New project"),
)
The same public components can therefore be used for both application navigation and custom side panels.
Pagination
pl.pagination(
pl.button("Previous"),
pl.text("Page 2"),
pl.button("Next"),
)
Tables & Data
Table
pl.table(
[
["Alice", "Admin"],
["Bob", "Developer"],
],
headers=["Name", "Role"],
)
Dataframe
pl.dataframe(
[
["Alice", 10],
["Bob", 20],
],
headers=["Name", "Score"],
)
Data List
pl.data_list(
[
("Name", "Alice"),
("Role", "Developer"),
("Status", "Active"),
],
)
Charts
PyLage exposes both Chart and the lowercase chart API.
Chart
pl.Chart(
data=[
{"month": "Jan", "sales": 100},
{"month": "Feb", "sales": 140},
{"month": "Mar", "sales": 180},
],
type="line",
x="month",
y="sales",
title="Monthly Sales",
)
chart
pl.chart(
data=[
{"month": "Jan", "sales": 100},
{"month": "Feb", "sales": 140},
{"month": "Mar", "sales": 180},
],
type="bar",
x="month",
y="sales",
)
Charts can also receive an existing figure:
figure = ...
pl.Chart(
figure=figure,
title="Existing Figure",
)
Metrics & Statistics
Metric
pl.metric(
"Revenue",
"$24,500",
delta="+12%",
)
Metric Card
pl.metric_card(
"Users",
"12,480",
delta="+8%",
)
Metric Grid
pl.metric_grid(
pl.metric("Users", "12,480"),
pl.metric("Revenue", "$24K"),
pl.metric("Orders", "842"),
)
Stat Group
pl.stat_group(
pl.metric("Users", "12K"),
pl.metric("Orders", "842"),
pl.metric("Revenue", "$24K"),
)
Stats Section
pl.stats_section(
title="Overview",
stats=(
pl.metric("Users", "12K"),
pl.metric("Orders", "842"),
),
)
Trend
pl.trend(
12.5,
direction="up",
)
Dashboard Components
Dashboard Card
pl.dashboard_card(
title="Revenue",
body=pl.metric("Revenue", "$24K"),
)
Dashboard Grid
pl.dashboard_grid(
pl.dashboard_card(title="Users", body=pl.text("12K")),
pl.dashboard_card(title="Orders", body=pl.text("842")),
)
Dashboard Header
pl.dashboard_header(
"Analytics",
"Business performance overview",
)
Dashboard Section
pl.dashboard_section(
pl.metric("Revenue", "$24K"),
title="Revenue",
description="Current monthly revenue.",
)
Dashboard
pl.dashboard(
title="Analytics",
content=pl.dashboard_grid(
pl.dashboard_card(
title="Users",
body=pl.text("12,480"),
),
pl.dashboard_card(
title="Revenue",
body=pl.text("$24K"),
),
),
)
Dashboard Page
pl.dashboard_page(
title="Dashboard",
header=pl.dashboard_header("Overview"),
content=pl.dashboard_grid(
pl.dashboard_card(
title="Revenue",
body=pl.text("$24K"),
),
),
)
Application & Page Patterns
PyLage includes higher-level page-building components.
App Shell
pl.app_shell(
header=pl.top_header(
pl.heading("My App"),
),
sidebar=pl.navigation(
pl.navigation_item("Home"),
pl.navigation_item("Settings"),
),
content=pl.text("Main content"),
footer=pl.footer(
pl.text("© My App"),
),
)
Hero
pl.hero(
"Build with Python",
"Create reactive web applications with PyLage.",
actions=pl.button("Get Started"),
)
Feature Section
pl.feature_section(
pl.card(pl.heading("Reactive")),
pl.card(pl.heading("Composable")),
title="Features",
)
Content Section
pl.content_section(
"About PyLage",
content=pl.text(
"A Python-first reactive web framework."
),
)
CTA
pl.cta(
"Ready to build?",
"Start your next application with PyLage.",
actions=pl.button("Get Started"),
)
Landing Page
pl.landing_page(
hero=pl.hero(
"PyLage",
"Python-first reactive web applications.",
),
features=pl.feature_section(
pl.card(pl.text("Reactive state")),
pl.card(pl.text("Composable UI")),
),
cta=pl.cta(
"Start building",
actions=pl.button("Get Started"),
),
)
Pricing Section
pl.pricing_section()
Profile Page
pl.profile_page(
name="Rachit",
role="Developer",
email="user@example.com",
)
Contact Section
pl.contact_section(
title="Contact Us",
description="Send us a message.",
)
Newsletter Section
pl.newsletter_section(
title="Stay Updated",
description="Get the latest PyLage updates.",
)
FAQ
pl.faq()
Testimonial
pl.testimonial(
"PyLage makes Python UI composition simple.",
"Developer",
role="Engineer",
)
Admin Panel
pl.admin_panel(
title="Admin",
sidebar=pl.navigation(
pl.navigation_item("Users"),
pl.navigation_item("Settings"),
),
content=pl.text("Administration"),
)
Authentication
pl.authentication(
title="Welcome back",
description="Sign in to continue.",
)
Media & Interactive Components
Audio
pl.audio(
src="/media/example.mp3",
)
Video
pl.video(
src="/media/example.mp4",
)
Canvas
pl.canvas(
width=800,
height=400,
)
Carousel
pl.carousel(
pl.image(src="/images/one.png", alt="One"),
pl.image(src="/images/two.png", alt="Two"),
)
Tabs
pl.tabs(
pl.text("Overview"),
pl.text("Activity"),
pl.text("Settings"),
)
Accordion
pl.accordion(
pl.heading("Frequently Asked Question"),
pl.text("Answer"),
)
Styling
style
Use style() to create reusable style definitions.
card_style = pl.style(
padding="1rem",
border_radius="12px",
)
app = pl.card(
pl.text("Styled card"),
style=card_style,
)
Inline style properties can also be passed directly:
pl.text(
"Styled text",
style=pl.style(
font_weight="bold",
padding="0.5rem",
),
)
Themes
theme
theme is part of PyLage's public theme API.
import pylage as pl
current_theme = pl.theme
colors
The public colors API provides the framework's color definitions.
import pylage as pl
palette = pl.colors
Use theme-aware styling instead of depending on internal implementation details.
set_theme
pl.set_theme("dark")
A theme object can also be supplied:
theme = pl.theme
pl.set_theme(theme)
get_current_theme
current = pl.get_current_theme()
Routing
PyLage supports file-system based routing.
A typical application structure is:
pages/
├── index.py
├── dashboard.py
├── projects.py
└── settings.py
A page can be a normal PyLage component tree:
import pylage as pl
page = pl.column(
pl.heading("Projects"),
pl.text("Project list"),
)
router
Create a router from a pages directory:
router = pl.router("pages")
route
A route can be represented explicitly:
from pathlib import Path
import pylage as pl
pl.route(
"/projects",
Path("pages/projects.py"),
label="Projects",
)
routing_runtime
Connect routing to a root component:
import pylage as pl
router = pl.router("pages")
root = pl.app_shell(
header=pl.top_header(
pl.heading("My Application"),
),
content=pl.container(),
)
pl.routing_runtime(
router,
root,
)
app
The public app() API provides application-level composition:
import pylage as pl
application = pl.app(
pages="pages",
)
The application can then be passed to run():
pl.run(application)
For a file-system routed application, run() can also configure the pages directory directly.
Running Applications
run
Run a component tree:
import pylage as pl
app = pl.column(
pl.heading("Hello"),
pl.text("Running locally."),
)
pl.run(app)
Run an application factory:
pl.run(
app_factory=lambda: pl.column(
pl.heading("New session"),
),
)
Run a pages directory:
pl.run(
pages_dir="pages",
title="PyLage Application",
)
Start a development server:
pl.run(
pages_dir="pages",
title="PyLage Application",
serve=True,
host="127.0.0.1",
port=3000,
)
For a production-oriented runtime:
pl.run(
pages_dir="pages",
serve=True,
host="0.0.0.0",
port=3000,
runtime="granian",
)
Complete Example
The following example combines state, layout, navigation, forms, metrics, and a table.
import pylage as pl
name = pl.state("")
tasks = pl.reactive_list([
"Review documentation",
"Build dashboard",
"Run tests",
])
app = pl.app_shell(
header=pl.top_header(
pl.row(
pl.heading("Project Dashboard"),
pl.navigation(
pl.navigation_item("Dashboard", active=True),
pl.navigation_item("Projects"),
pl.navigation_item("Settings"),
),
),
),
sidebar=pl.navigation_drawer(
pl.navigation_item("Overview"),
pl.navigation_item("Projects"),
pl.navigation_item("Settings"),
),
content=pl.container(
pl.column(
pl.heading("Welcome"),
pl.text(name),
pl.form(
pl.form_field(
pl.input(
value=name,
placeholder="Your name",
),
label="Name",
required=True,
),
pl.button("Save"),
),
pl.metric_grid(
pl.metric("Projects", "24"),
pl.metric("Tasks", "142"),
pl.metric("Progress", "78%"),
),
pl.dashboard_section(
pl.heading("Tasks"),
pl.for_each(
tasks,
lambda task: pl.card(
pl.text(task),
),
),
title="Current Tasks",
),
),
),
footer=pl.footer(
pl.text("Built with PyLage"),
),
)
pl.run(app)
Public API Cookbook
The following index covers the complete public API exported from the root pylage package.
| Public API | Example |
|---|---|
Chart |
pl.Chart(data=data, type="line") |
__version__ |
pl.__version__ |
app |
pl.app(pages="pages") |
accordion |
pl.accordion(pl.text("Content")) |
admin_panel |
pl.admin_panel(title="Admin") |
alert |
pl.alert("Saved", variant="success") |
app_shell |
pl.app_shell(content=pl.text("Content")) |
audio |
pl.audio(src="/media/example.mp3") |
authentication |
pl.authentication() |
avatar |
pl.avatar(pl.image(src="/avatar.png")) |
badge |
pl.badge("Active") |
breadcrumb_trail |
pl.breadcrumb_trail(...) |
button |
pl.button("Save") |
canvas |
pl.canvas(width=800, height=400) |
card |
pl.card(pl.text("Content")) |
carousel |
pl.carousel(...) |
center |
pl.center(pl.text("Centered")) |
chart |
pl.chart(data=data, type="bar") |
checkbox |
pl.checkbox(value=False) |
colors |
pl.colors |
column |
pl.column(...) |
cond |
pl.cond(condition, true_branch, false_branch) |
confirmation_dialog |
pl.confirmation_dialog("Delete?") |
contact_section |
pl.contact_section() |
container |
pl.container(...) |
content_section |
pl.content_section("About", content=...) |
cta |
pl.cta("Get started") |
dashboard |
pl.dashboard(title="Dashboard") |
dashboard_card |
pl.dashboard_card(title="Users") |
dashboard_grid |
pl.dashboard_grid(...) |
dashboard_header |
pl.dashboard_header("Dashboard") |
dashboard_page |
pl.dashboard_page(title="Dashboard") |
dashboard_section |
pl.dashboard_section(..., title="Stats") |
data_list |
pl.data_list(data) |
dataframe |
pl.dataframe(data) |
datepicker |
pl.datepicker() |
derived |
pl.derived(a, b, compute=lambda x, y: x + y) |
dialog |
pl.dialog(pl.text("Dialog")) |
divider |
pl.divider() |
drawer |
pl.drawer(...) |
empty_state |
pl.empty_state("Nothing here") |
error_state |
pl.error_state("Something went wrong") |
faq |
pl.faq() |
feature_section |
pl.feature_section(...) |
footer |
pl.footer(...) |
for_each |
pl.for_each(items, render_item) |
form |
pl.form(...) |
form_field |
pl.form_field(pl.input(), label="Name") |
get_current_theme |
pl.get_current_theme() |
grid |
pl.grid(...) |
header |
pl.header(...) |
heading |
pl.heading("Title") |
hero |
pl.hero("Title") |
icon |
pl.icon(name="home") |
image |
pl.image(src="/image.png", alt="Image") |
input |
pl.input() |
landing_page |
pl.landing_page(...) |
link |
pl.link("Home", href="/") |
list |
pl.list("One", "Two") |
loading |
pl.loading() |
loading_overlay |
pl.loading_overlay(open=True) |
loading_state |
pl.loading_state() |
menu |
pl.menu(...) |
metric |
pl.metric("Users", "100") |
metric_card |
pl.metric_card("Users", "100") |
metric_grid |
pl.metric_grid(...) |
mobile_sidebar |
pl.mobile_sidebar(...) |
modal |
pl.modal(pl.text("Content")) |
navbar |
pl.navbar(...) |
navigation |
pl.navigation(...) |
navigation_controls |
pl.navigation_controls(...) |
navigation_drawer |
pl.navigation_drawer(...) |
navigation_item |
pl.navigation_item("Home") |
newsletter_section |
pl.newsletter_section() |
option |
pl.option("Python", value="python") |
pagination |
pl.pagination(...) |
popover |
pl.popover(...) |
pricing_section |
pl.pricing_section() |
profile_page |
pl.profile_page(name="Rachit") |
progress_bar |
pl.progress_bar(value=50) |
radio_group |
pl.radio_group(...) |
reactive_list |
pl.reactive_list(["A", "B"]) |
route |
pl.route("/about", source, label="About") |
router |
pl.router("pages") |
routing_runtime |
pl.routing_runtime(router, root) |
row |
pl.row(...) |
run |
pl.run(app) |
search_bar |
pl.search_bar() |
section |
pl.section(...) |
select |
pl.select(pl.option("Python")) |
set_theme |
pl.set_theme("dark") |
sidebar_layout |
pl.sidebar_layout(...) |
skeleton |
pl.skeleton() |
slider |
pl.slider() |
spinner |
pl.spinner() |
split |
pl.split(...) |
stack |
pl.stack(...) |
stat_group |
pl.stat_group(...) |
state |
pl.state(0) |
stats_section |
pl.stats_section(...) |
style |
pl.style(padding="1rem") |
switch |
pl.switch() |
table |
pl.table(data) |
tabs |
pl.tabs(...) |
testimonial |
pl.testimonial("Great framework", "Developer") |
text |
pl.text("Hello") |
textarea |
pl.textarea() |
theme |
pl.theme |
three_column |
pl.three_column(...) |
toast |
pl.toast("Saved") |
tooltip |
pl.tooltip(pl.button("Help")) |
top_header |
pl.top_header(...) |
topbar |
pl.topbar(...) |
trend |
pl.trend(12.5, direction="up") |
two_column |
pl.two_column(...) |
video |
pl.video(src="/media/example.mp4") |
Session-Isolated Applications
For applications where each session should receive a fresh component tree, use app_factory.
import pylage as pl
def create_app():
count = pl.state(0)
return pl.column(
pl.heading("Session Counter"),
pl.text(count),
pl.button(
"Increment",
on_click=lambda: count.set(count.value + 1),
),
)
pl.run(
app_factory=create_app,
serve=True,
)
This keeps application state isolated per created application instance.
CLI & Development
PyLage applications can be run directly from Python:
python app.py
For a pages-based application:
pl.run(
pages_dir="pages",
serve=True,
host="127.0.0.1",
port=3000,
)
For development, keep the application code under normal Python modules and use the public pylage API.
Testing
Run the complete test suite with:
.venv/bin/python -m pytest -q
A focused test file can be run with:
.venv/bin/python -m pytest -q test/path/to/test_file.py
Useful final checks:
.venv/bin/python -m pytest -q
git diff --check
git status --short
The latest completed full regression in the v1.0.7 development cycle reached 1,537 passing tests.
Documentation
PyLage documentation is organized around the public framework surface.
Important component documentation includes:
docs/
├── component/
│ ├── drawer.md
│ └── navigation_item.md
├── benchmark.md
└── releases/
└── tracker_v1.0.7.md
The public API should be preferred over internal implementation modules when writing applications or examples.
Benchmark
PyLage includes browser-level comparative benchmarks covering representative application scenarios.
The benchmark compares PyLage with other Python web UI frameworks under the same test methodology.
The current benchmark documentation covers:
- Counter
- Form
- startup timing
- interaction latency
- P50 latency
- P95 latency
- mean latency
Example benchmark results from the documented browser benchmark:
| Framework | Counter startup | Counter P50 | Counter P95 |
|---|---|---|---|
| PyLage | 409.48 ms | 60.61 ms | 74.33 ms |
| NiceGUI | 1015.95 ms | 79.99 ms | 96.51 ms |
| Reflex | 709.79 ms | 61.18 ms | 68.06 ms |
| Streamlit | 3329.76 ms | 255.36 ms | 316.59 ms |
Form scenario:
| Framework | Form startup | Form P50 | Form P95 |
|---|---|---|---|
| PyLage | 597.09 ms | 116.42 ms | 129.34 ms |
| NiceGUI | 1049.05 ms | 143.04 ms | 175.01 ms |
| Reflex | 722.71 ms | 85.41 ms | 108.14 ms |
| Streamlit | 3232.20 ms | 563.77 ms | 639.92 ms |
These measurements describe the tested environments and scenarios. They should not be interpreted as universal performance rankings.
Project Structure
A typical PyLage project can be organized as:
pylage-project/
├── app.py
├── pages/
│ ├── index.py
│ ├── dashboard.py
│ ├── projects.py
│ └── settings.py
├── tests/
├── docs/
└── pyproject.toml
The framework itself contains the implementation and public API layers, but application code should normally import from:
import pylage as pl
Deployment
For a served application:
import pylage as pl
pl.run(
pages_dir="pages",
title="Production App",
serve=True,
host="0.0.0.0",
port=3000,
)
The runtime option can be selected when the deployment environment calls for a different serving runtime:
pl.run(
pages_dir="pages",
serve=True,
runtime="granian",
)
Production deployments should use the deployment process appropriate to the target infrastructure.
Release Status
PyLage 1.0.7 is the current release.
The release includes the finalized public Drawer/navigation work, routing and runtime improvements, accessibility behavior, responsive behavior, live showcase coverage, documentation, and comprehensive testing completed during the v1.0.7 development cycle.
Contributing
Contributions should:
- Preserve the public API.
- Prefer public
pylageimports in examples. - Include tests for behavior changes.
- Keep documentation synchronized with public APIs.
- Run the relevant focused tests.
- Run the complete regression suite before release.
- Check formatting and repository state before committing.
Recommended final validation:
.venv/bin/python -m pytest -q
git diff --check
git status --short
License
PyLage is distributed under the project's configured license. See the repository license file for the authoritative terms.
Links
- Repository: GitHub
- PyPI: PyPI
- Issues: GitHub Issues
- Playground: Live Playground
- Docs: PyLage Documentation git diff --check
Metadata
Release files for pylage 1.0.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pylage-1.0.8.tar.gz | 1.5 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pylage-1.0.8-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 3.0 MB
Release files / pylage-1.0.8.tar.gz
| Download URL | pylage-1.0.8.tar.gz |
|---|---|
| Size | 1.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7fff267cd1295018c50ead8f98050afee205a8344681fe4b14737e2e84d0e53a
|
|
BLAKE2b-256 checksum How to use checksums |
b2e71597061955ff9f5a7fa6e41235587ddeb698a775a55ea53873322e96d800
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency logRelease files / pylage-1.0.8-py3-none-any.whl
| Download URL | pylage-1.0.8-py3-none-any.whl |
|---|---|
| Size | 1.5 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7724d267d9a62b8effad99d4266b7e01be4da4b041e6911f719e46c483a676e3
|
|
BLAKE2b-256 checksum How to use checksums |
0825e9b887be26f2779365a265cf0618542e399523f549164fe313125acaa9b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 28, 2026.
Transparency log