Mercurial > piecrust2
comparison piecrust/routing.py @ 790:4cbe057a8b6a
routing: Add some backwards compatibility support for parameter types.
This makes it so old routes are still correctly formatting years/months/days
which were previously hard-coded to int4/int2 types.
| author | Ludovic Chabant <ludovic@chabant.com> |
|---|---|
| date | Mon, 05 Sep 2016 22:12:37 -0700 |
| parents | f6f9a284a5f3 |
| children | 504d6817352d |
comparison
equal
deleted
inserted
replaced
| 789:b8e760b3413e | 790:4cbe057a8b6a |
|---|---|
| 64 | 64 |
| 65 # Get the straight-forward regex for matching this URI pattern. | 65 # Get the straight-forward regex for matching this URI pattern. |
| 66 p = route_esc_re.sub(self._uriPatternRepl, | 66 p = route_esc_re.sub(self._uriPatternRepl, |
| 67 re.escape(self.uri_pattern)) + '$' | 67 re.escape(self.uri_pattern)) + '$' |
| 68 self.uri_re = re.compile(p) | 68 self.uri_re = re.compile(p) |
| 69 | |
| 70 # Get the types of the route parameters. | |
| 71 self.param_types = {} | |
| 72 for m in route_re.finditer(self.uri_pattern): | |
| 73 qual = m.group('qual') | |
| 74 if qual: | |
| 75 self.param_types[str(m.group('name'))] = qual | |
| 76 | 69 |
| 77 # If the URI pattern has a 'path'-type component, we'll need to match | 70 # If the URI pattern has a 'path'-type component, we'll need to match |
| 78 # the versions for which that component is empty. So for instance if | 71 # the versions for which that component is empty. So for instance if |
| 79 # we have `/foo/%path:bar%`, we may need to match `/foo` (note the | 72 # we have `/foo/%path:bar%`, we may need to match `/foo` (note the |
| 80 # lack of a trailing slash). We have to build a special pattern (in | 73 # lack of a trailing slash). We have to build a special pattern (in |
| 94 | 87 |
| 95 # Determine the parameters for the route function. | 88 # Determine the parameters for the route function. |
| 96 self.func_name = self._validateFuncName(cfg.get('func')) | 89 self.func_name = self._validateFuncName(cfg.get('func')) |
| 97 self.func_parameters = [] | 90 self.func_parameters = [] |
| 98 self.func_has_variadic_parameter = False | 91 self.func_has_variadic_parameter = False |
| 92 self.param_types = {} | |
| 99 variadic_param_idx = -1 | 93 variadic_param_idx = -1 |
| 100 for m in route_re.finditer(self.uri_pattern): | 94 for m in route_re.finditer(self.uri_pattern): |
| 101 name = m.group('name') | 95 name = m.group('name') |
| 96 self.func_parameters.append(name) | |
| 97 | |
| 98 qual = m.group('qual') | |
| 99 if not qual: | |
| 100 qual = self._getBackwardCompatibleParamType(name) | |
| 101 if qual: | |
| 102 self.param_types[name] = qual | |
| 103 | |
| 102 if m.group('var'): | 104 if m.group('var'): |
| 103 self.func_has_variadic_parameter = True | 105 self.func_has_variadic_parameter = True |
| 104 variadic_param_idx = len(self.func_parameters) | 106 variadic_param_idx = len(self.func_parameters) |
| 105 | |
| 106 self.func_parameters.append(name) | |
| 107 | 107 |
| 108 if (variadic_param_idx >= 0 and | 108 if (variadic_param_idx >= 0 and |
| 109 variadic_param_idx != len(self.func_parameters) - 1): | 109 variadic_param_idx != len(self.func_parameters) - 1): |
| 110 raise Exception( | 110 raise Exception( |
| 111 "Only the last route URL parameter can be variadic. " | 111 "Only the last route URL parameter can be variadic. " |
| 268 return self.getUri(metadata) | 268 return self.getUri(metadata) |
| 269 | 269 |
| 270 def _uriFormatRepl(self, m): | 270 def _uriFormatRepl(self, m): |
| 271 qual = m.group('qual') | 271 qual = m.group('qual') |
| 272 name = m.group('name') | 272 name = m.group('name') |
| 273 | |
| 274 # Backwards compatibility... this will print a warning later. | |
| 275 if qual is None: | |
| 276 if name == 'year': | |
| 277 qual = 'int4' | |
| 278 elif name in ['month', 'day']: | |
| 279 qual = 'int2' | |
| 280 | |
| 273 if qual == 'int4': | 281 if qual == 'int4': |
| 274 return '%%(%s)04d' % name | 282 return '%%(%s)04d' % name |
| 275 elif qual == 'int2': | 283 elif qual == 'int2': |
| 276 return '%%(%s)02d' % name | 284 return '%%(%s)02d' % name |
| 285 elif qual and qual != 'path': | |
| 286 raise Exception("Unknown route parameter type: %s" % qual) | |
| 277 return '%%(%s)s' % name | 287 return '%%(%s)s' % name |
| 278 | 288 |
| 279 def _uriPatternRepl(self, m): | 289 def _uriPatternRepl(self, m): |
| 280 name = m.group('name') | 290 name = m.group('name') |
| 281 qual = m.group('qual') | 291 qual = m.group('qual') |
| 292 | |
| 293 # Backwards compatibility... this will print a warning later. | |
| 294 if qual is None: | |
| 295 if name == 'year': | |
| 296 qual = 'int4' | |
| 297 elif name in ['month', 'day']: | |
| 298 qual = 'int2' | |
| 299 | |
| 282 if qual == 'path' or m.group('var'): | 300 if qual == 'path' or m.group('var'): |
| 283 return r'(?P<%s>[^\?]*)' % name | 301 return r'(?P<%s>[^\?]*)' % name |
| 284 elif qual == 'int4': | 302 elif qual == 'int4': |
| 285 return r'(?P<%s>\d{4})' % name | 303 return r'(?P<%s>\d{4})' % name |
| 286 elif qual == 'int2': | 304 elif qual == 'int2': |
| 287 return r'(?P<%s>\d{2})' % name | 305 return r'(?P<%s>\d{2})' % name |
| 306 elif qual and qual != 'path': | |
| 307 raise Exception("Unknown route parameter type: %s" % qual) | |
| 288 return r'(?P<%s>[^/\?]+)' % name | 308 return r'(?P<%s>[^/\?]+)' % name |
| 289 | 309 |
| 290 def _uriNoPathRepl(self, m): | 310 def _uriNoPathRepl(self, m): |
| 291 name = m.group('name') | 311 name = m.group('name') |
| 292 qualifier = m.group('qual') | 312 qualifier = m.group('qual') |
| 301 if param_type in ['int', 'int2', 'int4']: | 321 if param_type in ['int', 'int2', 'int4']: |
| 302 try: | 322 try: |
| 303 return int(val) | 323 return int(val) |
| 304 except ValueError: | 324 except ValueError: |
| 305 raise Exception( | 325 raise Exception( |
| 306 "Expected route parameter '%s' to be of type " | 326 "Expected route parameter '%s' to be of type " |
| 307 "'%s', but was: %s" % | 327 "'%s', but was: %s" % |
| 308 (name, param_type, val)) | 328 (name, param_type, val)) |
| 309 if param_type == 'path': | 329 if param_type == 'path': |
| 310 return val | 330 return val |
| 311 raise Exception("Unknown route parameter type: %s" % param_type) | 331 raise Exception("Unknown route parameter type: %s" % param_type) |
| 332 | |
| 333 def _getBackwardCompatibleParamType(self, name): | |
| 334 # Print a warning only if we're not in a worker process. | |
| 335 print_warning = not self.app.config.has('baker/worker_id') | |
| 336 | |
| 337 if name in ['year']: | |
| 338 if print_warning: | |
| 339 logger.warning( | |
| 340 "Route parameter '%%%s%%' has no type qualifier. " | |
| 341 "You probably meant '%%int4:%s%%' so we'll use that." % | |
| 342 (name, name)) | |
| 343 return 'int4' | |
| 344 if name in ['month', 'day']: | |
| 345 if print_warning: | |
| 346 logger.warning( | |
| 347 "Route parameter '%%%s%%' has no type qualifier. " | |
| 348 "You probably meant '%%int2:%s%%' so we'll use that." % | |
| 349 (name, name)) | |
| 350 return 'int2' | |
| 351 return None | |
| 312 | 352 |
| 313 def _validateFuncName(self, name): | 353 def _validateFuncName(self, name): |
| 314 if not name: | 354 if not name: |
| 315 return None | 355 return None |
| 316 i = name.find('(') | 356 i = name.find('(') |
