/
_get_paths.py
151 lines (134 loc) · 5.58 KB
/
_get_paths.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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
from ._utils import AttributeDict
from . import exceptions
CONFIG = AttributeDict()
def get_asset_url(path):
return app_get_asset_url(CONFIG, path)
def app_get_asset_url(config, path):
if config.assets_external_path:
prefix = config.assets_external_path
else:
prefix = config.requests_pathname_prefix
return "/".join(
[
# Only take the first part of the pathname
prefix.rstrip("/"),
config.assets_url_path.lstrip("/"),
path,
]
)
def get_relative_path(path):
"""
Return a path with `requests_pathname_prefix` prefixed before it.
Use this function when specifying local URL paths that will work
in environments regardless of what `requests_pathname_prefix` is.
In some deployment environments, like Dash Enterprise,
`requests_pathname_prefix` is set to the application name,
e.g. `my-dash-app`.
When working locally, `requests_pathname_prefix` might be unset and
so a relative URL like `/page-2` can just be `/page-2`.
However, when the app is deployed to a URL like `/my-dash-app`, then
`dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2`.
This can be used as an alternative to `get_asset_url` as well with
`dash.get_relative_path('/assets/logo.png')`
Use this function with `dash.strip_relative_path` in callbacks that
deal with `dcc.Location` `pathname` routing.
That is, your usage may look like:
```
app.layout = html.Div([
dcc.Location(id='url'),
html.Div(id='content')
])
@dash.callback(Output('content', 'children'), [Input('url', 'pathname')])
def display_content(path):
page_name = dash.strip_relative_path(path)
if not page_name: # None or ''
return html.Div([
dcc.Link(href=dash.get_relative_path('/page-1')),
dcc.Link(href=dash.get_relative_path('/page-2')),
])
elif page_name == 'page-1':
return chapters.page_1
if page_name == "page-2":
return chapters.page_2
```
"""
return app_get_relative_path(CONFIG.requests_pathname_prefix, path)
def app_get_relative_path(requests_pathname, path):
if requests_pathname == "/" and path == "":
return "/"
if requests_pathname != "/" and path == "":
return requests_pathname
if not path.startswith("/"):
raise exceptions.UnsupportedRelativePath(
f"""
Paths that aren't prefixed with a leading / are not supported.
You supplied: {path}
"""
)
return "/".join([requests_pathname.rstrip("/"), path.lstrip("/")])
def strip_relative_path(path):
"""
Return a path with `requests_pathname_prefix` and leading and trailing
slashes stripped from it. Also, if None is passed in, None is returned.
Use this function with `get_relative_path` in callbacks that deal
with `dcc.Location` `pathname` routing.
That is, your usage may look like:
```
app.layout = html.Div([
dcc.Location(id='url'),
html.Div(id='content')
])
@dash.callback(Output('content', 'children'), [Input('url', 'pathname')])
def display_content(path):
page_name = dash.strip_relative_path(path)
if not page_name: # None or ''
return html.Div([
dcc.Link(href=dash.get_relative_path('/page-1')),
dcc.Link(href=dash.get_relative_path('/page-2')),
])
elif page_name == 'page-1':
return chapters.page_1
if page_name == "page-2":
return chapters.page_2
```
Note that `chapters.page_1` will be served if the user visits `/page-1`
_or_ `/page-1/` since `strip_relative_path` removes the trailing slash.
Also note that `strip_relative_path` is compatible with
`get_relative_path` in environments where `requests_pathname_prefix` set.
In some deployment environments, like Dash Enterprise,
`requests_pathname_prefix` is set to the application name, e.g. `my-dash-app`.
When working locally, `requests_pathname_prefix` might be unset and
so a relative URL like `/page-2` can just be `/page-2`.
However, when the app is deployed to a URL like `/my-dash-app`, then
`dash.get_relative_path('/page-2')` will return `/my-dash-app/page-2`
The `pathname` property of `dcc.Location` will return '`/my-dash-app/page-2`'
to the callback.
In this case, `dash.strip_relative_path('/my-dash-app/page-2')`
will return `'page-2'`
For nested URLs, slashes are still included:
`dash.strip_relative_path('/page-1/sub-page-1/')` will return
`page-1/sub-page-1`
```
"""
return app_strip_relative_path(CONFIG.requests_pathname_prefix, path)
def app_strip_relative_path(requests_pathname, path):
if path is None:
return None
if (
requests_pathname != "/" and not path.startswith(requests_pathname.rstrip("/"))
) or (requests_pathname == "/" and not path.startswith("/")):
raise exceptions.UnsupportedRelativePath(
f"""
Paths that aren't prefixed with requests_pathname_prefix are not supported.
You supplied: {path} and requests_pathname_prefix was {requests_pathname}
"""
)
if requests_pathname != "/" and path.startswith(requests_pathname.rstrip("/")):
path = path.replace(
# handle the case where the path might be `/my-dash-app`
# but the requests_pathname_prefix is `/my-dash-app/`
requests_pathname.rstrip("/"),
"",
1,
)
return path.strip("/")