Skip to content

Commit de4ddb1

Browse files
authored
Merge pull request #7 from Starwort/patch-1
Add URL dynamic variables
2 parents 0be7d85 + 4a4afad commit de4ddb1

1 file changed

Lines changed: 43 additions & 12 deletions

File tree

‎client_code/routing.py‎

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
Source code published at https://github.com/s-cork/HashRouting
1212
"""
1313

14-
1514
import anvil as _anvil
15+
1616
from collections import namedtuple as _namedtuple
1717
from ._logging import logger
1818

@@ -62,7 +62,7 @@ def __init__(self, **properties):
6262
self.on_navigation() # called the first time the form is loaded to start routing...
6363

6464

65-
def on_navigation(self, url_hash=None, url_pattern=None, url_dict=None, path=None):
65+
def on_navigation(self, url_hash=None, url_pattern=None, url_dict=None, path=None, dynamic_vars=None):
6666
# when there is navigation - back/forward navigation
6767
# or when the user changes the url_hash or when you call anvil.set_url_hash in code
6868

@@ -108,7 +108,7 @@ def on_navigation(self, url_hash=None, url_pattern=None, url_dict=None, path=Non
108108

109109
try:
110110
if url_hash not in _cache and path is None:
111-
path = self.find_path(url_hash, url_pattern, url_dict)
111+
path, dynamic_vars = self.find_path(url_hash, url_pattern, url_dict)
112112
except KeyError:
113113
logger.print(f'no route form with url_pattern={url_pattern} and url_keys={url_dict.keys()}')
114114
if _error_form is not None:
@@ -119,31 +119,57 @@ def on_navigation(self, url_hash=None, url_pattern=None, url_dict=None, path=Non
119119
raise # this was an unexpected error so raise it
120120
else:
121121
self.content_panel.clear() # clear the form now just incase we end up with a new to cache form that is slow to load later
122-
self.load_form(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, path=path)
122+
self.load_form(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, path=path, dynamic_vars=dynamic_vars)
123123

124124
_on_navigation_stack_depth -= 1
125125

126126

127127
def find_path(self, url_hash, url_pattern, url_dict):
128128
# this method is called whenever we have form to load from navigation that is not in the cache
129+
given_url_parts = url_pattern.split('/') # determine the individual portions
130+
# of this deep link. N.B. this disallows using a '/' within the dynamic variable
131+
num_given_url_parts = len(given_url_parts)
132+
logger.print(f'[find_path] searching {_paths}')
129133
for path in _paths:
130-
if path.url_pattern == url_pattern and set(url_dict) == set(path.url_keys):
131-
return path
134+
dynamic_vars = {}
135+
target_url_parts = path.url_pattern.split('/')
136+
logger.print(f'[find_path] trying {path.url_pattern} against {url_pattern}'
137+
f'; {given_url_parts} -> {target_url_parts}')
138+
if num_given_url_parts != len(target_url_parts):
139+
# url pattern CANNOT fit, skip deformatting
140+
logger.print('[find_path] pattern cannot fit')
141+
continue
142+
for given, expected in zip(given_url_parts, target_url_parts):
143+
logger.print(f'[find_path] testing {given} against {expected}')
144+
if expected.startswith('{') and expected.endswith('}'):
145+
# dynamic variable
146+
logger.print(f'[find_path] found dynamic variable {expected[1:-1]}')
147+
dynamic_vars[expected[1:-1]] = given
148+
elif given != expected:
149+
logger.print(f"[find_path] {expected} isn't a dynamic variable and doesn't match {given}")
150+
break
151+
else:
152+
# given path matches expected path
153+
logger.print(f'[find_path] {url_pattern} matches {path.url_pattern}')
154+
if set(url_dict) == set(path.url_keys):
155+
# only return if the url_dict matches
156+
logger.print(f'[find_path] {url_dict} matches {path.url_keys}')
157+
return path, dynamic_vars
132158
else:
133159
#if no break we haven't found a valid hash so load the error form
134160
raise KeyError(f'{url_hash} does not exist')
135161

136162

137-
def load_form(self, url_hash, url_pattern, url_dict, path=None):
163+
def load_form(self, url_hash, url_pattern, url_dict, dynamic_vars, path=None):
138164
global _current_form
139165

140166
if url_hash in _cache:
141167
logger.print(_cache)
142168
logger.print(f"loaded {_cache[url_hash].__name__} from cache")
143169
_current_form = _cache[url_hash]
144170
elif path:
145-
title = path.title if path.title is None else path.title.format(**url_dict)
146-
_cache[url_hash] = path.form(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict,
171+
title = path.title if path.title is None else path.title.format(**url_dict, **dynamic_vars)
172+
_cache[url_hash] = path.form(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, dynamic_vars=dynamic_vars,
147173
_route_title=title, f_w_r = path.f_w_r, from_routing=True, **_properties)
148174
logger.print(f"loaded {_cache[url_hash].__name__}, added to cache")
149175
else:
@@ -182,7 +208,7 @@ def __call__(self, Cls):
182208
raise TypeError(f'title must be type str or None not {type(self.title).__name__} in {Cls.__name__}')
183209

184210
class Route(Cls):
185-
def __init__(self, url_hash=None, url_pattern=None, url_dict=None, _route_title=None, f_w_r=False,
211+
def __init__(self, url_hash=None, url_pattern=None, url_dict=None, dynamic_vars=None, _route_title=None, f_w_r=False,
186212
route=True, from_routing=False, **properties):
187213
global _properties
188214
_properties = {} # reset _properties as early as possible
@@ -193,6 +219,7 @@ def __init__(self, url_hash=None, url_pattern=None, url_dict=None, _route_title=
193219
self.url_hash = url_hash
194220
self.url_pattern = url_pattern
195221
self.url_dict = url_dict
222+
self.dynamic_vars = dynamic_vars
196223
self._route_title = _route_title
197224
self._f_w_r = f_w_r
198225

@@ -399,7 +426,9 @@ def load_form(form, url_pattern=None, url_keys=[], *, replace_current_url=False,
399426
except:
400427
raise
401428

402-
url_pattern = path.url_pattern
429+
dynamic_varnames = {i[1:-1] for i in path.url_pattern.split('/') if i.startswith('{') and i.endswith('}')}
430+
dynamic_vars = {key: value for key, value in properties.items() if key in dynamic_varnames}
431+
url_pattern = path.url_pattern.format(**dynamic_vars) # expand dynamic variables
403432
url_dict = _get_url_dict(path.url_keys, form, **properties)
404433
url_hash = _get_url_hash(url_pattern, url_dict)
405434

@@ -427,7 +456,7 @@ def load_form(form, url_pattern=None, url_keys=[], *, replace_current_url=False,
427456
global _properties
428457
_properties = properties
429458

430-
_main_router.on_navigation(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, path=path)
459+
_main_router.on_navigation(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, path=path, dynamic_vars=dynamic_vars)
431460

432461

433462
def load_error_form():
@@ -536,3 +565,5 @@ def set_warning_before_app_unload(warning=True):
536565
_anvil.js.call_js('setAppUnloadBehaviour', warning)
537566

538567

568+
569+

0 commit comments

Comments
 (0)