# Sundash
**Python & JS micro framework for realtime web UI applications**
* **ASGI-based** -- minimal 3rd party dependencies and clean core part
* **Flexible and extensible** -- easy to customize, add 3rd party integrations
* **Realtime** -- operating through websockets bus, client & backend in app
* **Crafted with ❤️**
Link to project on PyPi: https://pypi.org/project/sundash/
### Installation
```bash
pip install sundash
```
### Examples
```bash
python -m examples <num | name>
```
To run Hello World example:
```bash
python -m examples hello # passing 01 also works
```
Available examples:
* `01 hello` - show plain HTML string
* `02 buttons` - counter with clickable buttons
* `03 clock` - realtime clock (scheduler events)
* `04 menu` - simple page routing
* `05 search` - handling signle form input
* `06 tables` - static tables
**Client interaction example:**
```python
from dataclasses import dataclass
from sundash import App
from sundash import Component
from sundash import on
from sundash.app import ButtonClick
app = App()
class Counter(Component):
html = '''
<button id="minus">-</button>
<b>{{ count }}</b>
<button id="plus">+</button>
'''
@dataclass
class Vars:
count: int = 0
@on(ButtonClick)
async def on_click(self, event: ButtonClick):
if 'plus' == event.button_id:
self.vars.count += 1
elif 'minus' == event.button_id:
self.vars.count -= 1
await self.update_var('count')
app.run_sync(['<h1>🧮 Counter</h1>', Counter])
```
**Server Interaction Example:**
```python
import dataclasses as dc
import datetime as dt
from sundash import Component
from sundash import on
from sundash.scheduler import EverySecond
from sundash.scheduler import SchedulerApp
app = SchedulerApp()
now = lambda: dt.datetime.now().strftime('%H:%M:%S')
class Clock(Component):
html = '<p><b>Time:</b> {{ time }}<p/>'
@dc.dataclass
class Vars:
time: str = dc.field(default_factory=now)
@on(EverySecond)
async def update(self, _):
self.vars.time = now()
await self.update_var('time')
app.run_sync(['<h1>🕰️ Clock</h1>', Clock])
```
### В чем идея?
Хочу пробрасывать real-time интерфейс к JS либам, чтобы была возможность
написать любую веб-морду для любых системных инструментов.
**Примеры использования:** любые админки, торговые терминалы, дашборды мониторинга, тулзы для аналитики.
Все кастомное и интерактивное, что хочется нарисовать, но ты бэкендер и хочешь писать
преимущественно на Python с минимальным использованием JavaScript-а,
без тяжеловесного инструментария фронтендеров (React и пр).
### Development
* Required: python 3.12, poetry, virtualenv
* Install Python dependencies: `poetry install --with=dev`
* Run local linters: `poe q`
* Publish package: `poetry publish --build`
Raw data
{
"_id": null,
"home_page": "https://github.com/ruthus18/sundash",
"name": "sundash",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.12",
"maintainer_email": null,
"keywords": "backend, frontend, server, client, ws, framework",
"author": "Danil Tryapchev",
"author_email": "ruthus18@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/00/76/f09b038901eb5a00bf802d1793c15de5d4fe1a76dcb92f0afd92218ffda2/sundash-0.0.7.tar.gz",
"platform": null,
"description": "# Sundash\n\n**Python & JS micro framework for realtime web UI applications**\n\n* **ASGI-based** -- minimal 3rd party dependencies and clean core part\n* **Flexible and extensible** -- easy to customize, add 3rd party integrations\n* **Realtime** -- operating through websockets bus, client & backend in app\n* **Crafted with \u2764\ufe0f**\n\nLink to project on PyPi: https://pypi.org/project/sundash/\n\n\n### Installation\n\n```bash\n pip install sundash\n```\n\n\n### Examples\n\n```bash\n python -m examples <num | name>\n```\n\nTo run Hello World example:\n\n```bash\n python -m examples hello # passing 01 also works\n```\n\nAvailable examples:\n\n* `01 hello` - show plain HTML string\n* `02 buttons` - counter with clickable buttons\n* `03 clock` - realtime clock (scheduler events)\n* `04 menu` - simple page routing\n* `05 search` - handling signle form input\n* `06 tables` - static tables\n\n\n**Client interaction example:**\n\n```python\nfrom dataclasses import dataclass\n\nfrom sundash import App\nfrom sundash import Component\nfrom sundash import on\nfrom sundash.app import ButtonClick\n\napp = App()\n\n\nclass Counter(Component):\n html = '''\n <button id=\"minus\">-</button>\n <b>{{ count }}</b>\n <button id=\"plus\">+</button>\n '''\n\n @dataclass\n class Vars:\n count: int = 0\n\n @on(ButtonClick)\n async def on_click(self, event: ButtonClick):\n if 'plus' == event.button_id:\n self.vars.count += 1\n\n elif 'minus' == event.button_id:\n self.vars.count -= 1\n\n await self.update_var('count')\n\n\napp.run_sync(['<h1>\ud83e\uddee Counter</h1>', Counter])\n```\n\n\n**Server Interaction Example:**\n\n```python\nimport dataclasses as dc\nimport datetime as dt\n\nfrom sundash import Component\nfrom sundash import on\nfrom sundash.scheduler import EverySecond\nfrom sundash.scheduler import SchedulerApp\n\napp = SchedulerApp()\n\n\nnow = lambda: dt.datetime.now().strftime('%H:%M:%S')\n\n\nclass Clock(Component):\n html = '<p><b>Time:</b> {{ time }}<p/>'\n\n @dc.dataclass\n class Vars:\n time: str = dc.field(default_factory=now)\n\n @on(EverySecond)\n async def update(self, _):\n self.vars.time = now()\n await self.update_var('time')\n\n\napp.run_sync(['<h1>\ud83d\udd70\ufe0f Clock</h1>', Clock])\n```\n\n\n### \u0412 \u0447\u0435\u043c \u0438\u0434\u0435\u044f?\n\n\u0425\u043e\u0447\u0443 \u043f\u0440\u043e\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0442\u044c real-time \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u043a JS \u043b\u0438\u0431\u0430\u043c, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u043b\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\n\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u043b\u044e\u0431\u0443\u044e \u0432\u0435\u0431-\u043c\u043e\u0440\u0434\u0443 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.\n\n**\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f:** \u043b\u044e\u0431\u044b\u0435 \u0430\u0434\u043c\u0438\u043d\u043a\u0438, \u0442\u043e\u0440\u0433\u043e\u0432\u044b\u0435 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u044b, \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u044b \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430, \u0442\u0443\u043b\u0437\u044b \u0434\u043b\u044f \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0438.\n\u0412\u0441\u0435 \u043a\u0430\u0441\u0442\u043e\u043c\u043d\u043e\u0435 \u0438 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435, \u0447\u0442\u043e \u0445\u043e\u0447\u0435\u0442\u0441\u044f \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c, \u043d\u043e \u0442\u044b \u0431\u044d\u043a\u0435\u043d\u0434\u0435\u0440 \u0438 \u0445\u043e\u0447\u0435\u0448\u044c \u043f\u0438\u0441\u0430\u0442\u044c\n\u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043d\u0430 Python \u0441 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u044b\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c JavaScript-\u0430,\n\u0431\u0435\u0437 \u0442\u044f\u0436\u0435\u043b\u043e\u0432\u0435\u0441\u043d\u043e\u0433\u043e \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435\u0440\u043e\u0432 (React \u0438 \u043f\u0440).\n\n\n### Development\n\n* Required: python 3.12, poetry, virtualenv\n* Install Python dependencies: `poetry install --with=dev`\n* Run local linters: `poe q`\n* Publish package: `poetry publish --build`\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python & JS micro framework for realtime web UI applications",
"version": "0.0.7",
"project_urls": {
"Homepage": "https://github.com/ruthus18/sundash",
"Repository": "https://github.com/ruthus18/sundash"
},
"split_keywords": [
"backend",
" frontend",
" server",
" client",
" ws",
" framework"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "b91bdd2346810cd0eb9b9520b317feba5d634943ffe477ee653f32dc42fdac02",
"md5": "418a583882f71dfb184d9a43135f44e4",
"sha256": "58417cbc772897e6b064b2a54fdf13f1c995a5a7df85c15e0248faa96b1bb65e"
},
"downloads": -1,
"filename": "sundash-0.0.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "418a583882f71dfb184d9a43135f44e4",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.12",
"size": 16327,
"upload_time": "2024-04-10T05:24:56",
"upload_time_iso_8601": "2024-04-10T05:24:56.077680Z",
"url": "https://files.pythonhosted.org/packages/b9/1b/dd2346810cd0eb9b9520b317feba5d634943ffe477ee653f32dc42fdac02/sundash-0.0.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0076f09b038901eb5a00bf802d1793c15de5d4fe1a76dcb92f0afd92218ffda2",
"md5": "1a08dc3ec91d634890a99448af098d97",
"sha256": "20805fc8fd571916eb7767b8b14af3fa0be2fda5309aa5d568b29492022ff94d"
},
"downloads": -1,
"filename": "sundash-0.0.7.tar.gz",
"has_sig": false,
"md5_digest": "1a08dc3ec91d634890a99448af098d97",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.12",
"size": 15650,
"upload_time": "2024-04-10T05:24:58",
"upload_time_iso_8601": "2024-04-10T05:24:58.636198Z",
"url": "https://files.pythonhosted.org/packages/00/76/f09b038901eb5a00bf802d1793c15de5d4fe1a76dcb92f0afd92218ffda2/sundash-0.0.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-10 05:24:58",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ruthus18",
"github_project": "sundash",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "sundash"
}