-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathpublic_routes.py
105 lines (81 loc) · 3.07 KB
/
public_routes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import inspect
import os
from dash import Dash, callback, get_app
from dash._callback import GLOBAL_CALLBACK_MAP
from werkzeug.routing import Map, MapAdapter, Rule
DASH_PUBLIC_ASSETS_EXTENSIONS = "js,css"
BASE_PUBLIC_ROUTES = [
f"/assets/<path:path>.{ext}"
for ext in os.getenv(
"DASH_PUBLIC_ASSETS_EXTENSIONS",
DASH_PUBLIC_ASSETS_EXTENSIONS,
).split(",")
] + [
"/_dash-component-suites/<path:path>",
"/_dash-layout",
"/_dash-dependencies",
"/_favicon.ico",
"/_reload-hash",
]
PUBLIC_ROUTES = "PUBLIC_ROUTES"
PUBLIC_CALLBACKS = "PUBLIC_CALLBACKS"
def add_public_routes(app: Dash, routes: list):
"""Add routes to the public routes list.
The routes passed should follow the Flask route syntax.
e.g. "/login", "/user/<user_id>/public"
Some routes are made public by default:
* All dash scripts (_dash-dependencies, _dash-component-suites/**)
* All dash mechanics routes (_dash-layout, _reload-hash)
* All assets with extension .css, .js, .svg, .jpg, .png, .gif, .webp
Note: you can modify the extension by setting the
`DASH_ASSETS_PUBLIC_EXTENSIONS` envvar (comma-separated list of
extensions, e.g. "js,css,svg").
* The favicon
If you use callbacks on your public routes, you should use dash_auth's
`public_callback` rather than the standard dash callback.
:param app: Dash app
:param routes: list of public routes to be added
"""
public_routes = get_public_routes(app)
if not public_routes.map._rules:
routes = BASE_PUBLIC_ROUTES + routes
for route in routes:
public_routes.map.add(Rule(route))
app.server.config[PUBLIC_ROUTES] = public_routes
def public_callback(*callback_args, **callback_kwargs):
"""Public Dash callback.
This works by adding the callback id (from the callback map) to a list
of whitelisted callbacks in the Flask server's config.
:param **: all args and kwargs passed to a dash callback
"""
def decorator(func):
wrapped_func = callback(*callback_args, **callback_kwargs)(func)
callback_id = next(
(
k
for k, v in GLOBAL_CALLBACK_MAP.items()
if "callback" in v
and inspect.getsource(v["callback"]) == inspect.getsource(func)
),
None,
)
try:
app = get_app()
app.server.config[PUBLIC_CALLBACKS] = get_public_callbacks(app) + [
callback_id
]
except Exception:
print(
"Could not set up the public callback as the Dash object "
"has not yet been instantiated."
)
def wrap(*args, **kwargs):
return wrapped_func(*args, **kwargs)
return wrap
return decorator
def get_public_routes(app: Dash) -> MapAdapter:
"""Retrieve the public routes."""
return app.server.config.get(PUBLIC_ROUTES, Map([]).bind(""))
def get_public_callbacks(app: Dash) -> list:
"""Retrieve the public callbacks ids."""
return app.server.config.get(PUBLIC_CALLBACKS, [])