Python framework to build reactive web apps with seamless server-client interaction
Project description
PRET
Pret is a library for building full-stack reactive user interfaces in Python, using React as a rendering engine.
Installation
pip install pret pret-joy
To use it with Jupyter, if you install the library in a custom environment (conda, venv, or other), you will likely need to tell Jupyter where to find the front-end files. You can do this by running the following command (only once):
pret update-jupyter-config --apply
Features
- Python, only Python: pret is written in Python: you can write your both your UI and server actions Python. No need to learn a new language.
- Client-side rendering: unlike other Python UI frameworks, pret runs primarily in the browser. This enables a fast response time to user actions (like hover events), and a better user experience under degraded network conditions.
- Built on React: pret uses React as a rendering engine, and benefits from its ecosystem.
- Reactive: unlike other solutions like ipywidgets, pret is reactive. Only the parts of the UI that need to be updated are re-rendered.
- State management: in addition to React's local state management (i.e.
use_state), pret provides a global and modular state management solution that is synchronized between components, between the browser and the server, and can even be persisted to a file for collaborative editing. - Modular: pret is designed to be modular. You can easily create your own components, and reuse them in other pret-based projects.
- Integrated with Jupyter: pret components can be used in Jupyter notebooks, as well as in standalone web applications.
- Remote execution: pret can call and use the result of Python functions on the server from the browser
Use it in a notebook
Let's write a simple todo app that should:
- display a list of todos, that can be checked as done
- display the number remaining todos
- change the font to bold as a todo is hovered
- allow editing the todo list directly in Python
Copy and paste the following code in a notebook:
from pret import component, create_store, run, use_state, use_store_snapshot
from pret_joy import Checkbox, Input, Stack, Typography
store = create_store(
{
"faire à manger": True,
"faire la vaisselle": False,
},
sync=True,
)
@component
def TodoApp():
todos = use_store_snapshot(store)
typed, set_typed = use_state("")
num_remaining = sum(not ok for ok in todos.values())
plural = "s" if num_remaining > 1 else ""
def on_key_down(event):
if event.key == "Enter":
store[typed] = False
set_typed("")
return Stack(
*(
Checkbox(
label=todo,
checked=ok,
on_change=lambda e, t=todo: store.update({t: e.target.checked}),
)
for todo, ok in todos.items()
),
Input(
value=typed,
on_change=lambda event: set_typed(event.target.value),
on_key_down=on_key_down,
placeholder="Add a todo",
),
Typography(
f"Number of unfinished todo{plural}: {num_remaining}",
sx={"minWidth": "230px"}, # just to avoid jittering when it's centered
),
spacing=2,
sx={"m": 1},
)
TodoApp()
In comparison, the closest alternative using ipywidgets looks like the following snippet:
IPyWidget's implementation
import ipywidgets as widgets
state = {
"faire à manger": True,
"faire la vaisselle": False,
}
class IPWTodoApp:
def __init__(self):
self.box = widgets.VBox()
self.render()
def _repr_mimebundle_(self, *args, **kwargs):
return self.box._repr_mimebundle_(*args, **kwargs)
def render(self, *args, **kwargs):
num_remaining = sum([not checked for _, checked in state.items()])
plural = "s" if num_remaining > 1 else ""
def on_input_submit(sender):
state[input_widget.value] = False
self.render()
def create_todo_item(todo, checked):
def update_todo_status(*args, **kwargs):
state[todo] = checkbox.value
self.render()
checkbox = widgets.Checkbox(
value=checked,
description=todo,
disabled=False,
indent=False,
)
checkbox.observe(update_todo_status, names="value")
return checkbox
input_widget = widgets.Text(
placeholder="Add a todo",
description="",
disabled=False,
)
input_widget.on_submit(on_input_submit)
self.box.children = [
*(create_todo_item(todo, checked) for todo, checked in state.items()),
input_widget,
widgets.Label(value=f"Number of unfinished todo{plural}: {num_remaining}"),
]
IPWTodoApp()
You also lose some features:
- the app stops working if the server shuts down
- hover events cannot be listened to
- no React dom diffing: the app must either be re-rendered entirely (as in the example), or you must determine specifically which field of which widget to update
Use it in a standalone app
You can also use pret to build standalone web applications. Copy the above code in a file
named app.py, and change the last line to
if __name__ == "__main__":
run(TodoApp)
Then, run the following command, and voilà !
python app.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pret-0.5.1-py3-none-any.whl.
File metadata
- Download URL: pret-0.5.1-py3-none-any.whl
- Upload date:
- Size: 9.4 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8a1cfc6547dc19588082204d115cdee5205d6ead99ab7e5c927b95e55720475
|
|
| MD5 |
809cf763ed8b43f158ec1352fabf6d28
|
|
| BLAKE2b-256 |
4817ff81564d8614bb2bca2474aad06c684a452f1ad68668ab39cc7218e560ca
|