Skip to content

Commit 2d46453

Browse files
Create better_dash_callback
Signed-off-by: Richard Barella <ribab127@gmail.com>
0 parents  commit 2d46453

File tree

8 files changed

+237
-0
lines changed

8 files changed

+237
-0
lines changed

.github/workflows/workflow.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Publish Python Package
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
release:
8+
types: [published]
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v2
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v2
20+
with:
21+
python-version: '3.10.12'
22+
23+
- name: Install dependencies
24+
run: |
25+
python -m pip install --upgrade pip
26+
pip install build setuptools wheel twine
27+
28+
- name: Build package
29+
run: |
30+
python3 -m build
31+
32+
- name: Publish package
33+
run: |
34+
twine upload dist/* -u __token__ -p '${{ secrets.PYPI_TOKEN }}'
35+

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
__pycache__/
2+
*.pyc
3+
.venv/
4+
.env/
5+
env/
6+
venv/
7+
build/
8+
dist/
9+
*.egg-info/

LICENSE

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
MIT License
2+
3+
Copyright (c) 2025 Richard Barella Jr.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
2+
# better-dash-callback
3+
4+
A library that enables running clientside callback functions in Dash applications using Python syntax, eliminating the need for inline JavaScript.
5+
6+
## Problem
7+
8+
When building Dash applications, you often need to write clientside callback functions using inline JavaScript. This can be cumbersome and error-prone, especially for complex logic. Moreover, inline JavaScript code lacks syntax highlighting and debugging capabilities.
9+
10+
## Solution
11+
12+
`better-dash-callback` provides a solution to this problem by allowing you to write clientside callback functions using Python syntax. This makes your code more readable, maintainable, and efficient.
13+
14+
## Example
15+
16+
Let's consider a simple example where we want to update the text of a component based on the value of an input component.
17+
18+
**Using Dash's `clientside_callback`**
19+
20+
```python
21+
import dash
22+
from dash import html
23+
from dash.dependencies import Input, Output
24+
25+
app = dash.Dash(__name__)
26+
27+
app.layout = html.Div([
28+
html.Input(id="input", type="text"),
29+
html.Div(id="output")
30+
])
31+
32+
app.clientside_callback(
33+
"""
34+
function(value) {
35+
return 'You entered: ' + value;
36+
}
37+
""",
38+
Output("output", "children"),
39+
Input("input", "value")
40+
)
41+
42+
if __name__ == "__main__":
43+
app.run_server(debug=True)
44+
```
45+
46+
**Using `better-dash-callback`**
47+
48+
```python
49+
import dash
50+
from dash import html
51+
from better_dash_callback import callback
52+
53+
app = dash.Dash(__name__)
54+
55+
app.layout = html.Div([
56+
html.Input(id="input", type="text"),
57+
html.Div(id="output")
58+
])
59+
60+
@callback(
61+
Output("output", "children"),
62+
Input("input", "value"),
63+
clientside=True
64+
)
65+
def update_output(value):
66+
return f"You entered: {value}"
67+
68+
if __name__ == "__main__":
69+
app.run_server(debug=True)
70+
```
71+
72+
As you can see, the `better-dash-callback` example is more elegant and easier to read. You can write your callback function using Python syntax, without having to worry about inline JavaScript code.
73+
74+
## Installation
75+
76+
To install `better-dash-callback`, you can use `pip`:
77+
78+
```bash
79+
pip3 install better-dash-callback
80+
```
81+
82+
## License
83+
84+
`better-dash-callback` is licensed under the MIT License.

better_dash_callback/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .src import *

better_dash_callback/src.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env python3
2+
import metapensiero.pj.__main__
3+
import dash
4+
import inspect
5+
6+
def callback(*args, clientside=False, **kwargs):
7+
"""
8+
A decorator to register a Dash callback. If `clientside` is True, the python callback
9+
will be executed clientside using jsbuilder, which will convert it to javascript.
10+
11+
If `clientside` is False or not set, the callback will be executed serverside
12+
using Dash's standard callback system.
13+
14+
Other than clientside argument, all other arguments are the same as Dash's @callback function.
15+
16+
:param clientside: Whether to execute the callback clientside. Defaults to False.
17+
"""
18+
19+
def decorator(func):
20+
21+
if clientside:
22+
python_code = inspect.getsource(func)
23+
python_code = python_code[python_code.find("def "):]
24+
js_code = metapensiero.pj.__main__.transform_string(python_code)
25+
dash.clientside_callback(js_code, *args, **kwargs)
26+
else:
27+
@dash.callback(*args, **kwargs)
28+
def wrapper(*values):
29+
return func(*values)
30+
31+
return decorator

examples/fibonacci.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
from dash import Dash, html, dcc, Output, Input, State
3+
from better_dash_callback import callback
4+
5+
@callback(
6+
Output("fibonacci_display", "children"),
7+
Output("fibonacci_values", "data"),
8+
Input("button", "n_clicks"),
9+
State("fibonacci_values", "data"),
10+
prevent_initial_call=True,
11+
clientside=True
12+
)
13+
def compute_next_fibonacci(_, values):
14+
"""
15+
this code will be executed clientside as javascript.
16+
This page shows what syntax is supported: https://github.com/metapensiero/metapensiero.pj
17+
"""
18+
ind = 0
19+
indices = []
20+
while ind < len(values) + 1:
21+
indices.push(ind)
22+
ind += 1
23+
if not values:
24+
values = [1]
25+
elif len(values) < 2:
26+
values.push(1)
27+
else:
28+
values.push(values[-1] + values[-2])
29+
result = ""
30+
for i in indices:
31+
if i > 0:
32+
result += " " + str(values[i])
33+
else:
34+
result += str(values[i])
35+
return result, values
36+
37+
app = Dash(__name__)
38+
app.layout = [
39+
html.Button("Compute Fibonacci", id="button"),
40+
html.Span("1", id="fibonacci_display", style={"marginLeft": "10px"}),
41+
dcc.Store(id="fibonacci_values", data=[1]),
42+
]
43+
44+
if __name__ == "__main__":
45+
app.run_server(debug=True)

setup.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from setuptools import setup, find_packages
2+
3+
setup(
4+
name='better-dash-callback',
5+
version='0.1.0',
6+
description='Runs clientside callback functions in Dash applications using Python syntax, eliminating the need for inline JavaScript.',
7+
author='Richard Barella Jr.',
8+
author_email='codingwithricky@gmail.com',
9+
url='https://github.com/ribab/better-dash-callback',
10+
packages=find_packages(exclude=['tests', 'examples']),
11+
install_requires=[
12+
'dash>=2.0.0',
13+
'javascripthon==0.13'
14+
],
15+
classifiers=[
16+
'Development Status :: 3 - Alpha',
17+
'Intended Audience :: Developers',
18+
'Topic :: Software Development :: Libraries :: Application Frameworks',
19+
'Programming Language :: Python :: 3',
20+
'License :: OSI Approved :: MIT License',
21+
],
22+
include_package_data=True,
23+
)

0 commit comments

Comments
 (0)