<p align="center"><img width="150" height="150" src="https://data-star.dev/static/images/rocket-512x512.png"></p>
# Datastar Python SDK
The `datastar-py` package provides a Python SDK for working with [Datastar](https://data-star.dev).
Datastar sends responses back to the browser using SSE. This allows the backend to
send any number of events, from zero to infinity in response to a single request.
`datastar-py` has helpers for creating those responses, formatting the events,
reading signals from the frontend, and generating the data-* HTML attributes.
The event generator can be used with any framework. There are also custom
helpers included for the following frameworks:
* [Django](https://www.djangoproject.com/)
* [FastAPI](https://fastapi.tiangolo.com/)
* [FastHTML](https://fastht.ml/)
* [Litestar](https://litestar.dev/)
* [Quart](https://quart.palletsprojects.com/en/stable/)
* [Sanic](https://sanic.dev/en/)
* [Starlette](https://www.starlette.io/)
Framework-specific helpers are kept in their own packages. e.g. `datastar_py.quart`
Make sure to use the helpers from the package of the framework you are using.
Here is a full example using the quart framework showing many of the features
available in this package.
```python
import asyncio
from datetime import datetime
from datastar_py import ServerSentEventGenerator as SSE, attribute_generator as data
from datastar_py.quart import datastar_response, read_signals
from quart import Quart
app = Quart(__name__)
# Import frontend library via Content Distribution Network, create targets for Server Sent Events
@app.route("/")
def index():
return f"""
<html>
<head>
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"></script>
</head>
<body {data.on_load("@get('/updates')")}>
<span id="currentTime"></span><br>
<span data-text="$currentTime"></span>
</body>
</html>
"""
@app.route("/updates")
@datastar_response
async def updates():
# Retrieve a dictionary with the current state of the signals from the frontend
signals = await read_signals()
# Alternate updating an element from the backend, and updating a signal from the backend
while True:
yield SSE.patch_elements(
f"""<span id="currentTime">{datetime.now().isoformat()}"""
)
await asyncio.sleep(1)
yield SSE.patch_signals({"currentTime": f"{datetime.now().isoformat()}"})
await asyncio.sleep(1)
app.run()
```
Starting examples for each framework can be found in the [examples](/examples)
directory.
## Event Generation Helpers
This helper is used to generate the actual events that are sent over SSE. They
are just text blobs that can be sent using any framework. These can even be
used by frameworks not directly supported in this library if you set up the
headers of the SSE response yourself.
## Response Helpers
A datastar response consists of 0..N datastar events. There are response
classes included to make this easy in all of the supported frameworks.
The following examples will work across all supported frameworks when the
response class is imported from the appropriate framework package.
e.g. `from datastar_py.quart import DatastarResponse` The containing functions
are not shown here, as they will differ per framework.
```python
# per framework Response import. (Replace 'fastapi' with your framework.) e.g.:
# from datastar_py.fastapi import DatastarResponse
from datastar_py import ServerSentEventGenerator as SSE
# 0 events, a 204
@app.get("zero")
def zero_event():
return DatastarResponse()
# 1 event
@app.get("one")
def one_event():
return DatastarResponse(SSE.patch_elements("<div id='mydiv'></div>"))
# 2 events
@app.get("two")
def two_event():
return DatastarResponse([
SSE.patch_elements("<div id='mydiv'></div>"),
SSE.patch_signals({"mysignal": "myval"}),
])
# N events, a long lived stream (for all frameworks but sanic)
@app.get("/updates")
async def updates():
async def _():
while True:
yield SSE.patch_elements("<div id='mydiv'></div>")
await asyncio.sleep(1)
return DatastarResponse(_())
# A long lived stream for sanic
@app.get("/updates")
async def updates(request):
response = await datastar_respond(request)
# which is just a helper for the following
# response = await request.respond(DatastarResponse())
while True:
await response.send(SSE.patch_elements("<div id='mydiv'></div>"))
await asyncio.sleep(1)
```
### Response Decorator
To make returning a `DatastarResponse` simpler, there is a decorator
`datastar_response` available that automatically wraps a function result in
`DatastarResponse`. It works on async and regular functions and generator
functions. The main use case is when using a generator function, as you can
avoid a second generator function inside your response function. The decorator
works the same for any of the supported frameworks, and should be used under
any routing decorator from the framework.
```python
# Import the decorator from the package specific to your framework
from datastar_py.sanic import datastar_response, ServerSentEventGenerator as SSE
@app.get('/my_route')
@datastar_response
async def my_route(request):
while True:
yield SSE.patch_elements("<div id='mydiv'></div>")
await asyncio.sleep(1)
```
## Signal Helpers
The current state of the datastar signals is included by default in every
datastar request. A helper is included to load those signals for each
framework. `read_signals`. The usage varies per framework so check the
signature for your framework. You usually need to pass the request in.
```python
from datastar_py.quart import read_signals
@app.route("/updates")
async def updates():
signals = await read_signals()
```
## Attribute Generation Helper
Datastar allows HTML generation to be done on the backend. datastar-py includes
a helper to generate data-* attributes in your HTML with IDE completion and
type checking. It can be used with many different HTML generation libraries.
```python
from datastar_py import attribute_generator as data
# htpy
button(data.on("click", "console.log('clicked')").debounce(1000).stop)["My Button"]
# FastHTML
Button("My Button", data.on("click", "console.log('clicked')").debounce(1000).stop)
Button(data.on("click", "console.log('clicked')").debounce(1000).stop)("My Button")
# f-strings
f"<button {data.on("click", "console.log('clicked')").debounce(1000).stop}>My Button</button>"
# Jinja, but no editor completion :(
<button {{data.on("click", "console.log('clicked')").debounce(1000).stop}}>My Button</button>
```
When using datastar with a different alias, you can instantiate the class yourself.
```python
from datastar_py.attributes import AttributeGenerator
data = AttributeGenerator(alias="data-star-")
# htmy (htmy will transform _ into - unless the attribute starts with _, which will be stripped)
data = AttributeGenerator(alias="_data-")
html.button("My Button", **data.on("click", "console.log('clicked')").debounce("1s").stop)
```
Raw data
{
"_id": null,
"home_page": null,
"name": "datastar-py",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": null,
"keywords": "datastar, django, fastapi, fasthtml, flask, html, litestar, quart, sanic, starlette",
"author": null,
"author_email": "Felix Ingram <f.ingram@gmail.com>, Lucian Knock <git@lucianknock.com>, Chase Sterling <chase.sterling@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/1b/47/42b6d24b6170320ecf49e6cd331624804c7a9d655dd1c16866e12858e031/datastar_py-0.6.5.tar.gz",
"platform": null,
"description": "<p align=\"center\"><img width=\"150\" height=\"150\" src=\"https://data-star.dev/static/images/rocket-512x512.png\"></p>\n\n# Datastar Python SDK\n\nThe `datastar-py` package provides a Python SDK for working with [Datastar](https://data-star.dev).\n\nDatastar sends responses back to the browser using SSE. This allows the backend to\nsend any number of events, from zero to infinity in response to a single request.\n\n`datastar-py` has helpers for creating those responses, formatting the events,\nreading signals from the frontend, and generating the data-* HTML attributes.\n\nThe event generator can be used with any framework. There are also custom\nhelpers included for the following frameworks:\n\n* [Django](https://www.djangoproject.com/)\n* [FastAPI](https://fastapi.tiangolo.com/)\n* [FastHTML](https://fastht.ml/)\n* [Litestar](https://litestar.dev/)\n* [Quart](https://quart.palletsprojects.com/en/stable/)\n* [Sanic](https://sanic.dev/en/)\n* [Starlette](https://www.starlette.io/)\n\nFramework-specific helpers are kept in their own packages. e.g. `datastar_py.quart`\nMake sure to use the helpers from the package of the framework you are using.\n\nHere is a full example using the quart framework showing many of the features\navailable in this package.\n\n```python\nimport asyncio\nfrom datetime import datetime\n\nfrom datastar_py import ServerSentEventGenerator as SSE, attribute_generator as data\nfrom datastar_py.quart import datastar_response, read_signals\nfrom quart import Quart\n\napp = Quart(__name__)\n\n# Import frontend library via Content Distribution Network, create targets for Server Sent Events\n@app.route(\"/\")\ndef index():\n return f\"\"\"\n <html>\n <head>\n <script type=\"module\" src=\"https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js\"></script>\n </head>\n <body {data.on_load(\"@get('/updates')\")}>\n <span id=\"currentTime\"></span><br>\n <span data-text=\"$currentTime\"></span>\n </body>\n </html>\n \"\"\"\n\n\n@app.route(\"/updates\")\n@datastar_response\nasync def updates():\n # Retrieve a dictionary with the current state of the signals from the frontend\n signals = await read_signals()\n # Alternate updating an element from the backend, and updating a signal from the backend\n while True:\n yield SSE.patch_elements(\n f\"\"\"<span id=\"currentTime\">{datetime.now().isoformat()}\"\"\"\n )\n await asyncio.sleep(1)\n yield SSE.patch_signals({\"currentTime\": f\"{datetime.now().isoformat()}\"})\n await asyncio.sleep(1)\n\n\napp.run()\n```\n\nStarting examples for each framework can be found in the [examples](/examples)\ndirectory.\n\n## Event Generation Helpers\n\nThis helper is used to generate the actual events that are sent over SSE. They\nare just text blobs that can be sent using any framework. These can even be\nused by frameworks not directly supported in this library if you set up the\nheaders of the SSE response yourself.\n\n## Response Helpers\n\nA datastar response consists of 0..N datastar events. There are response\nclasses included to make this easy in all of the supported frameworks.\n\nThe following examples will work across all supported frameworks when the\nresponse class is imported from the appropriate framework package.\ne.g. `from datastar_py.quart import DatastarResponse` The containing functions\nare not shown here, as they will differ per framework.\n\n```python\n# per framework Response import. (Replace 'fastapi' with your framework.) e.g.:\n# from datastar_py.fastapi import DatastarResponse\nfrom datastar_py import ServerSentEventGenerator as SSE\n\n# 0 events, a 204\n@app.get(\"zero\")\ndef zero_event():\n return DatastarResponse()\n# 1 event\n@app.get(\"one\")\ndef one_event():\n return DatastarResponse(SSE.patch_elements(\"<div id='mydiv'></div>\"))\n# 2 events\n@app.get(\"two\")\ndef two_event():\n return DatastarResponse([\n SSE.patch_elements(\"<div id='mydiv'></div>\"),\n SSE.patch_signals({\"mysignal\": \"myval\"}),\n ])\n\n# N events, a long lived stream (for all frameworks but sanic)\n@app.get(\"/updates\")\nasync def updates():\n async def _():\n while True:\n yield SSE.patch_elements(\"<div id='mydiv'></div>\")\n await asyncio.sleep(1)\n return DatastarResponse(_())\n\n# A long lived stream for sanic\n@app.get(\"/updates\")\nasync def updates(request):\n response = await datastar_respond(request)\n # which is just a helper for the following\n # response = await request.respond(DatastarResponse())\n while True:\n await response.send(SSE.patch_elements(\"<div id='mydiv'></div>\"))\n await asyncio.sleep(1)\n```\n\n### Response Decorator\nTo make returning a `DatastarResponse` simpler, there is a decorator\n`datastar_response` available that automatically wraps a function result in\n`DatastarResponse`. It works on async and regular functions and generator\nfunctions. The main use case is when using a generator function, as you can\navoid a second generator function inside your response function. The decorator\nworks the same for any of the supported frameworks, and should be used under\nany routing decorator from the framework.\n\n```python\n# Import the decorator from the package specific to your framework\nfrom datastar_py.sanic import datastar_response, ServerSentEventGenerator as SSE\n\n@app.get('/my_route')\n@datastar_response\nasync def my_route(request):\n while True:\n yield SSE.patch_elements(\"<div id='mydiv'></div>\")\n await asyncio.sleep(1)\n```\n\n## Signal Helpers\nThe current state of the datastar signals is included by default in every\ndatastar request. A helper is included to load those signals for each\nframework. `read_signals`. The usage varies per framework so check the\nsignature for your framework. You usually need to pass the request in.\n\n```python\nfrom datastar_py.quart import read_signals\n\n@app.route(\"/updates\")\nasync def updates():\n signals = await read_signals()\n```\n\n## Attribute Generation Helper\nDatastar allows HTML generation to be done on the backend. datastar-py includes\na helper to generate data-* attributes in your HTML with IDE completion and\ntype checking. It can be used with many different HTML generation libraries.\n\n```python\nfrom datastar_py import attribute_generator as data\n\n# htpy\nbutton(data.on(\"click\", \"console.log('clicked')\").debounce(1000).stop)[\"My Button\"]\n# FastHTML\nButton(\"My Button\", data.on(\"click\", \"console.log('clicked')\").debounce(1000).stop)\nButton(data.on(\"click\", \"console.log('clicked')\").debounce(1000).stop)(\"My Button\")\n# f-strings\nf\"<button {data.on(\"click\", \"console.log('clicked')\").debounce(1000).stop}>My Button</button>\"\n# Jinja, but no editor completion :(\n<button {{data.on(\"click\", \"console.log('clicked')\").debounce(1000).stop}}>My Button</button>\n```\n\nWhen using datastar with a different alias, you can instantiate the class yourself.\n\n```python\nfrom datastar_py.attributes import AttributeGenerator\n\ndata = AttributeGenerator(alias=\"data-star-\")\n\n# htmy (htmy will transform _ into - unless the attribute starts with _, which will be stripped)\ndata = AttributeGenerator(alias=\"_data-\")\nhtml.button(\"My Button\", **data.on(\"click\", \"console.log('clicked')\").debounce(\"1s\").stop)\n```\n",
"bugtrack_url": null,
"license": null,
"summary": "Helper functions and classes for the Datastar library (https://data-star.dev/)",
"version": "0.6.5",
"project_urls": {
"Documentation": "https://github.com/starfederation/datastar-python/blob/develop/README.md",
"GitHub": "https://github.com/starfederation/datastar-python"
},
"split_keywords": [
"datastar",
" django",
" fastapi",
" fasthtml",
" flask",
" html",
" litestar",
" quart",
" sanic",
" starlette"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "7b23410f8598579c891a27d73f58767d39cecf356b280162f1d53d25e05dc3f1",
"md5": "5d03674c501f54b0bced3ce51472e0e4",
"sha256": "db51e4e4a7f87f11f3bafa8153cdc54ee79df6da59964904217fdb67da55d324"
},
"downloads": -1,
"filename": "datastar_py-0.6.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "5d03674c501f54b0bced3ce51472e0e4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 21338,
"upload_time": "2025-08-15T02:28:27",
"upload_time_iso_8601": "2025-08-15T02:28:27.804268Z",
"url": "https://files.pythonhosted.org/packages/7b/23/410f8598579c891a27d73f58767d39cecf356b280162f1d53d25e05dc3f1/datastar_py-0.6.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "1b4742b6d24b6170320ecf49e6cd331624804c7a9d655dd1c16866e12858e031",
"md5": "0d57f9fd1e26c9f62bfd55a71b307d45",
"sha256": "a8ec90077b455b0870586ae5f454ae3b0c2c392cf8cdf6853a03adb1c9158b54"
},
"downloads": -1,
"filename": "datastar_py-0.6.5.tar.gz",
"has_sig": false,
"md5_digest": "0d57f9fd1e26c9f62bfd55a71b307d45",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 72274,
"upload_time": "2025-08-15T02:28:28",
"upload_time_iso_8601": "2025-08-15T02:28:28.874059Z",
"url": "https://files.pythonhosted.org/packages/1b/47/42b6d24b6170320ecf49e6cd331624804c7a9d655dd1c16866e12858e031/datastar_py-0.6.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-15 02:28:28",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "starfederation",
"github_project": "datastar-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "datastar-py"
}