Metadata-Version: 2.4
Name: swl
Version: 5.0.1
Summary: Interactive web applications in Python, without a JavaScript frontend: Starlette, Jinja and htmx
Author-email: Thijs Janssen <thijs@seecr.nl>, Johan Jonkers <johan@seecr.nl>
License-Expression: MIT
Project-URL: Homepage, https://github.com/seecr/swl
Project-URL: Source, https://github.com/seecr/swl
Project-URL: Issues, https://github.com/seecr/swl/issues
Project-URL: Changelog, https://github.com/seecr/swl/blob/main/CHANGELOG.md
Keywords: web,htmx,starlette,jinja,server-side rendering,forms
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Developers
Classifier: Environment :: Web Environment
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: argon2-cffi<26,>=25.1.0
Requires-Dist: httpx2<3,>=2.16.0
Requires-Dist: pytest<10,>=9.2.0
Requires-Dist: pytest-asyncio<2,>=1.4.1
Requires-Dist: pytest-xdist<4,>=3.8.0
Requires-Dist: seecr-stdlib<1,>=0.6.5
Requires-Dist: seecr-testtools<1,>=0.4.3
Requires-Dist: setuptools-scm<11,>=10.3.4
Requires-Dist: starlette[full]<2,>=1.10.0
Requires-Dist: uvicorn[standard]<1,>=0.54.0
Dynamic: license-file

# SWL (Seecr Web Lib)

[![Tests](https://github.com/seecr/swl/actions/workflows/test.yml/badge.svg)](https://github.com/seecr/swl/actions/workflows/test.yml)
[![PyPI](https://img.shields.io/pypi/v/swl.svg)](https://pypi.org/project/swl/)

Interactive web applications in Python, without a JavaScript frontend.

SWL is a small layer on top of [Starlette](https://www.starlette.io),
[Jinja](https://jinja.palletsprojects.com) and [htmx 4](https://four.htmx.org). The server renders
HTML; an action answers with a short list of instructions ("put this HTML there, reload that list,
close the dialog, show a toast") that SWL carries out in the browser. You write Python and
templates. There is no build step, and no second application to keep in sync.

It is made for the software around data: admin screens, editors, review tools, form builders and
dashboards. These are lots of forms, lists, dialogs and tabs, used every day by people who need
them to work.

## A taste

```jinja
{% from "swl/placeholder.j2" import placeholder %}

<form hx-post="{{ register('note_add') }}">
    <input name="text" class="{{ SWL.ui.input }}">
    <button type="submit" class="{{ SWL.ui.button_primary }}">Add</button>
</form>

{{ placeholder("notes", register('notes_list')) }}
```

```python
async def notes_list(request, swl, db, **kwargs):
    html = swl.template("notes/list.j2").render(notes=db.notes())
    return swl.success().hydrate("notes", html)


async def note_add(request, swl, db, **kwargs):
    async with request.form() as form:
        text = form.get("text", "").strip()
    if not text:
        return swl.fail().message("A note needs some text")
    db.add_note(text)
    return swl.success().reset_form().rehydrate("notes").toast("Note added")


__actions__ = [notes_list, note_add]
```

`note_add` doesn't render the list. It asks the list to reload itself, so `notes_list` stays the
only place that knows how the list looks. And because a response is data, you test an action
without a browser.

## What you get

- **Actions**: async Python functions, registered by module, with login and authorisation checks.
  A template gets an action's url with `register("name")`.
- **A response builder**: `hydrate`, `rehydrate`, `open_modal`, `close_modal`,
  `open_contextmenu`, `toast`, `call` (a JavaScript function), `set_url`, `redirect`,
  `trigger`, and `swl.fail().message(...)` for errors.
- **Placeholders and rehydrate**: parts of the page that load themselves and can be reloaded by
  name from any action.
- **Live updates**: a placeholder can reload when the data it shows changes, also in other
  browser tabs and for other users (over a websocket).
- **Screens you can reload and link to**: actions keep the url up to date, and a page route
  renders the same screen from it.
- **Ready-made parts**: a modal, confirm and error dialogs, toasts and context menus, all
  plain HTML (`<dialog>`, popover). There are also login, "my account" and user management
  screens.
- **Your choice of CSS framework**: `ui.framework` is `"bootstrap"` (the default), `"tabler"`,
  `"bulma"` or `"swl"`, SWL's own small stylesheet with no framework at all. Light and dark
  colours work with each of them.

## Install

```sh
pip install swl
```

Or from a checkout: `pip install -e .`. SWL needs Python 3.11 or newer. Its dependencies, including `seecr-stdlib`, come from PyPI.

## Try the example

The example application is a small task list. It uses nearly everything: dialogs, search as you
type, tabs, a context menu, live updates between browser tabs, screens that survive a reload,
and switches for the CSS framework and dark mode.

```sh
pip install -e .
pip install -e example/
python -m swl_tasks
```

Open <http://127.0.0.1:8000/> and log in as **demo** / **demo-password**.

## Documentation

- [`example/README.md`](https://github.com/seecr/swl/blob/main/example/README.md): a guided walk
  through the example, from one click to the updated list. Start here.
- [`doc/reference.md`](https://github.com/seecr/swl/blob/main/doc/reference.md): everything SWL
  provides, for looking things up. Also covers debugging and troubleshooting.
- [`CHANGELOG.md`](https://github.com/seecr/swl/blob/main/CHANGELOG.md): what changed.

## Tests

```sh
pytest swl example/swl_tasks
```

The JavaScript tests (QUnit) run in a browser: `python -m swl.test.server`, then open
<http://localhost:8000/>. Or headless, as the CI does:

```sh
pip install playwright && python -m playwright install chromium
python -m swl.test.run_js_tests
```

## License

SWL is released under the MIT License; see [LICENSE](https://github.com/seecr/swl/blob/main/LICENSE).

Copyright © Seecr (Seek You Too B.V.), <https://seecr.nl>.
