Skip to main content

SimpleSite

Host a website in three lines of Python. SimpleSite is a thin, ergonomic layer over Quart that removes the boilerplate of serving static pages, without hiding Quart underneath if you ever need it.

from SimpleSite.easyhost import App

app = App()
app.hostStatic("/", "index.html")
app.hostStatic("/about", "<h1>About us</h1>")
app.run(port=8000)

Why?

Serving a simple static page or two with Quart/Flask normally means writing a route, a view function and wiring up templates by hand. Every time. SimpleSite collapses that down to one call per page, while still giving you:

  • File or inline HTML: point hostStatic at a file, a folder or just pass raw HTML directly

  • Automatic error pages: Drop a 404.html / 500.html / etc. into your templates/ folder and SimpleSite serves it automatically on the matching error. No file? You get a built-in fallback instead of a stack trace.

  • Still just Quart: The underlying app is a real quart.Quart instance. Nothing is hidden. More on how to still use quart.Quart later. You can reach in and use Quart/Jinja features directly whenever you need to.

Install

Requires Python>=3.10

pip install quart-simplesite

The PyPI distribution is named quart-simplesite (the name SimpleSite was already taken), but the import stays the same:

from SimpleSite.easyhost import App

Quick start

from SimpleSite.easyhost import App

app = App()

# Serve a file
app.hostStatic("/", "index.html")

# Serve a whole folder (looks for index.html inside it)
app.hostStatic("/docs", "docs/")

# Serve raw HTML directly, no file needed
app.hostStatic("/hello", "<h1>Hello, world!</h1>")

# Finally host the page
app.run(host="127.0.0.1", port=8000)

Custom error pages

SimpleSite scans your templates/ folder at startup for files named after HTTP status codes:

templates/
├── 404.html
├── 500.html
└── 403.html

If a matching file exists, it's served automatically when that error occurs. If not, SimpleSite falls back to a built-in error page. Your site never shows a raw traceback to visitors thanks to the fallbacks.

Supported codes out of the box: 400, 401, 403, 404, 405, 500, 502, 503

API reference

App

Creates a new SimpleSite application, wrapping a Quart app internally.

app.hostStatic(route: str, source: str, secure: bool = False)

Registers a route

source is... Behaviour
a file path Serves that file at route
a directory path Serves index.html from that directory
a raw HTML string Serves the string directly as the page content

To distinguish those three types, SimpleSite checks if the source is a file. If that check misses, it checks if the path is a directory. If that misses too, it currently assumes that it is a raw HTML string.


route should be named /<route> as a naming convention, but can also be <route>.

super duper route to my site
will be parsed as
/super-duper-route-to-my-site.


Hosts with the secure=True attribute will require being logged in. For that one has to create a .env-file within the project directory (see Auth / login below), and html has to point at a real template file rather than a raw string or directory.

app.createLogin(route: str, html: str = None, admin: bool = False)

Registers a login endpoint at route: GET serves the login form, POST checks the submitted user / password form fields and, on success, logs the user in.

  • html: optional path to a custom login-page template. If omitted, a minimal built-in form is served.
  • Requires auth to be configured (see below) — raises if DEF_USER/DEF_PASS/SECRET_KEY aren't set.
app.createLogin("/login")
app.hostStatic("/dashboard", "dashboard.html", secure=True)

app.run(host="127.0.0.1", port=5000)

Starts the server (via uvicorn under the hood)

How to still use Quart if needed?

from SimpleSite.easyhost import App

app = App()

# Use the Quart component to create a specific endpoint
@app.app.route("/")
async def index():
    return await app.quart.render_template("index.html")
Name What it is What it can be used for
app The Quart-Object Used to add more routes or websockets
quart The thing Call any function requires the application context, but not the object (e.g. render_template())

Structure

SimpleSite

SimpleSite/
├── conf/
│   ├── paths.toml
│   └── customs.toml
├── requirements.txt
├── ReadMe.md
├── .gitignore
├── templates/
├── .env
├── easyhost.py
└── error_registry.py

Content for .env:

DEF_USER='Admin-Username'
DEF_PASS='super-secure-admin-pass'
SECRET_KEY='some-long-random-string'
USE_DB=True
Fieldname What it is used for IsRequired What happens without?
DEF_USER The username you need for any login added using SimpleSite False Auth is considered disabled: createLogin() and secure=True both raise, since there's no login to check against
DEF_PASS The password you need for any login added using SimpleSite False Same as above
SECRET_KEY Signs the login session cookie (via quart-auth) Only if DEF_USER/DEF_PASS are set The app refuses to start (RuntimeError) — a login without a secret key can't be trusted
USE_DB Determine if the DB should be used False The database won't be used. However, if DEF_PASS and DEF_USER are given it uses plain-text comparison. With DB an Argon2 hash will be used.

Auth / login

Set DEF_USER and DEF_PASS in .env to turn auth on. Once that's done, SECRET_KEY becomes required too — SimpleSite raises at startup if it's missing, rather than starting up with an insecure or broken login.

from SimpleSite.easyhost import App

app = App()
app.createLogin("/login")
app.hostStatic("/", "index.html")
app.hostStatic("/admin", "admin.html", secure=True)
app.run(port=8000)

Without USE_DB, credentials are checked directly against DEF_USER/DEF_PASS. With USE_DB=True, credentials are checked against the database instead (Argon2-hashed).

Project built with SimpleSite

SimpleSite/
Project/
├── main.py
├── templates (folder with all html-files)
├── static (folder with all scripts/stylesheets etc)
└── others

Import for main.py

from SimpleSite.easyhost import App

Roadmap

  • hostFolder(): auto-map an entire directory to routes, file-based-routing style
  • Dev mode with live reload
  • Config file support for error template overrides
  • Login-Templating (createLogin(html=...))

License

MIT

Metadata

Release files for quart-simplesite 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for quart-simplesite 0.1.1
File Size Uploaded Provenance Actions
quart_simplesite-0.1.1.tar.gz 13.4 kB Without provenance Details for quart_simplesite-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for quart-simplesite 0.1.1
File Interpreter ABI Platform Actions
quart_simplesite-0.1.1-py3-none-any.whl Python 3 none any Details for quart_simplesite-0.1.1-py3-none-any.whl

Total release size: 25.8 kB

Release files / quart_simplesite-0.1.1.tar.gz

Download URL quart_simplesite-0.1.1.tar.gz
Size 13.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8f1e0ce24083470e135e9bbe1692baa8aab71d7865f65170aa57fe066740930b
BLAKE2b-256 checksum
How to use checksums
7155de45188f824afd28d47b2c769946c69a5bcb7bdb6e3d3669589fdc43a0e2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.1

Release files / quart_simplesite-0.1.1-py3-none-any.whl

Download URL quart_simplesite-0.1.1-py3-none-any.whl
Size 12.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4b60cda1b54ab46e127b31f6507676847bc0ddf5fa927483231fa7fe13f7b192
BLAKE2b-256 checksum
How to use checksums
9393353e9a25426fc25b952563a43e9432440afeba3e4eb119f79ff921610673
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.1

Security for quart-simplesite 0.1.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page