Mercurial > piecrust2
diff piecrust/routing.py @ 723:606f6d57b5df
routing: Cleanup URL routing and improve page matching.
* Add new types of route parameters for integers (int4, int2, int).
* Remove hard-coded hacks around converting year/month/day values.
* Make the blog post routes use the new typed parameters.
* Fix problems with matching routes with integer parameters when they can
get confused with a sub-page number.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Sun, 29 May 2016 20:19:28 -0700 |
parents | ab5c6a8ae90a |
children | 8c3c2b949b82 |
line wrap: on
line diff
--- a/piecrust/routing.py Sun May 29 20:15:56 2016 -0700 +++ b/piecrust/routing.py Sun May 29 20:19:28 2016 -0700 @@ -9,8 +9,8 @@ logger = logging.getLogger(__name__) -route_re = re.compile(r'%((?P<qual>path):)?(?P<name>\w+)%') -route_esc_re = re.compile(r'\\%((?P<qual>path)\\:)?(?P<name>\w+)\\%') +route_re = re.compile(r'%((?P<qual>[\w\d]+):)?(?P<name>\w+)%') +route_esc_re = re.compile(r'\\%((?P<qual>[\w\d]+)\\:)?(?P<name>\w+)\\%') template_func_re = re.compile(r'^(?P<name>\w+)\((?P<args>.*)\)\s*$') template_func_arg_re = re.compile(r'(?P<arg>\+?\w+)') ugly_url_cleaner = re.compile(r'\.html$') @@ -27,12 +27,6 @@ def create_route_metadata(page): route_metadata = copy.deepcopy(page.source_metadata) route_metadata.update(page.getRouteMetadata()) - - # TODO: fix this hard-coded shit - for key in ['year', 'month', 'day']: - if key in route_metadata and isinstance(route_metadata[key], str): - route_metadata[key] = int(route_metadata[key]) - return route_metadata @@ -75,6 +69,13 @@ re.escape(self.uri_pattern)) + '$' self.uri_re = re.compile(p) + # Get the types of the route parameters. + self.param_types = {} + for m in route_re.finditer(self.uri_pattern): + qual = m.group('qual') + if qual: + self.param_types[str(m.group('name'))] = qual + # If the URI pattern has a 'path'-type component, we'll need to match # the versions for which that component is empty. So for instance if # we have `/foo/%path:bar%`, we may need to match `/foo` (note the @@ -174,17 +175,18 @@ for k in missing_keys: route_metadata[k] = '' - # TODO: fix this hard-coded shit - for key in ['year', 'month', 'day']: - if key in route_metadata and isinstance(route_metadata[key], str): - try: - route_metadata[key] = int(route_metadata[key]) - except ValueError: - pass + for k in route_metadata: + route_metadata[k] = self._coerceRouteParameter( + k, route_metadata[k]) return route_metadata def getUri(self, route_metadata, *, sub_num=1): + route_metadata = dict(route_metadata) + for k in route_metadata: + route_metadata[k] = self._coerceRouteParameter( + k, route_metadata[k]) + uri = self.uri_format % route_metadata suffix = None if sub_num > 1: @@ -230,21 +232,23 @@ return uri def _uriFormatRepl(self, m): + qual = m.group('qual') name = m.group('name') - #TODO: fix this hard-coded shit - if name == 'year': - return '%(year)04d' - if name == 'month': - return '%(month)02d' - if name == 'day': - return '%(day)02d' - return '%(' + name + ')s' + if qual == 'int4': + return '%%(%s)04d' % name + elif qual == 'int2': + return '%%(%s)02d' % name + return '%%(%s)s' % name def _uriPatternRepl(self, m): name = m.group('name') - qualifier = m.group('qual') - if qualifier == 'path': + qual = m.group('qual') + if qual == 'path': return r'(?P<%s>[^\?]*)' % name + elif qual == 'int4': + return r'(?P<%s>\d{4})' % name + elif qual == 'int2': + return r'(?P<%s>\d{2})' % name return r'(?P<%s>[^/\?]+)' % name def _uriNoPathRepl(self, m): @@ -254,6 +258,22 @@ return '' return r'(?P<%s>[^/\?]+)' % name + def _coerceRouteParameter(self, name, val): + param_type = self.param_types.get(name) + if param_type is None: + return val + if param_type in ['int', 'int2', 'int4']: + try: + return int(val) + except ValueError: + raise Exception( + "Expected route parameter '%s' to be of type " + "'%s', but was: %s" % + (k, param_type, route_metadata[k])) + if param_type == 'path': + return val + raise Exception("Unknown route parameter type: %s" % param_type) + def _createTemplateFunc(self, func_def): if func_def is None: return @@ -299,10 +319,8 @@ del non_var_args[-1] for arg_name, arg_val in zip(non_var_args, args): - #TODO: fix this hard-coded shit. - if arg_name in ['year', 'month', 'day']: - arg_val = int(arg_val) - metadata[arg_name] = arg_val + metadata[arg_name] = self._coerceRouteParameter( + arg_name, arg_val) if is_variable: metadata[self.template_func_vararg] = []