diff options
author | David Cramer <dcramer@gmail.com> | 2016-09-13 12:04:10 -0700 |
---|---|---|
committer | David Cramer <dcramer@gmail.com> | 2016-09-13 12:04:10 -0700 |
commit | 241a3bf7e952d834657b67ee3895c14611a6c86b (patch) | |
tree | 50e39bee064befd055fa1e73528653777acd7b6c | |
parent | 737b48d8e6e5ba53a9a53b4aaef86a2366a6c58b (diff) | |
download | raven-transactions.tar.gz |
Handle included patternstransactions
-rw-r--r-- | raven/contrib/django/resolver.py | 76 | ||||
-rw-r--r-- | tests/contrib/django/test_resolver.py | 27 |
2 files changed, 69 insertions, 34 deletions
diff --git a/raven/contrib/django/resolver.py b/raven/contrib/django/resolver.py index cd5c5c0..12d22e4 100644 --- a/raven/contrib/django/resolver.py +++ b/raven/contrib/django/resolver.py @@ -3,9 +3,9 @@ from __future__ import absolute_import import re try: - from django.urls import get_resolver, Resolver404 + from django.urls import get_resolver except ImportError: - from django.core.urlresolvers import get_resolver, Resolver404 + from django.core.urlresolvers import get_resolver class RouteResolver(object): @@ -32,44 +32,58 @@ class RouteResolver(object): # TODO(dcramer): it'd be nice to change these into [%s] but it currently # conflicts with the other rules because we're doing regexp matches # rather than parsing tokens - pattern = self._optional_group_matcher.sub(lambda m: '%s' % m.group(1), pattern) + result = self._optional_group_matcher.sub(lambda m: '%s' % m.group(1), pattern) # handle named groups first - pattern = self._named_group_matcher.sub(lambda m: '{%s}' % m.group(1), pattern) + result = self._named_group_matcher.sub(lambda m: '{%s}' % m.group(1), result) # handle non-named groups - pattern = self._non_named_group_matcher.sub("{var}", pattern) + result = self._non_named_group_matcher.sub('{var}', result) # handle optional params - pattern = self._either_option_matcher.sub(lambda m: m.group(1), pattern) + result = self._either_option_matcher.sub(lambda m: m.group(1), result) # clean up any outstanding regex-y characters. - pattern = pattern.replace('^', '').replace('$', '') \ + result = result.replace('^', '').replace('$', '') \ .replace('?', '').replace('//', '/').replace('\\', '') - if not pattern.startswith('/'): - pattern = '/' + pattern - return pattern + + return result + + def _resolve(self, resolver, path, parents=None): + match = resolver.regex.search(path) + if not match: + return + + if parents is None: + parents = [resolver] + else: + parents.append(resolver) + + new_path = path[match.end():] + for pattern in resolver.url_patterns: + # this is an include() + if not pattern.callback: + match = self._resolve(pattern, new_path, parents) + if match: + return match + continue + + elif not pattern.regex.search(new_path): + continue + + try: + return self._cache[pattern] + except KeyError: + pass + + prefix = ''.join(self._simplify(p.regex.pattern) for p in parents) + result = prefix + self._simplify(pattern.regex.pattern) + if not result.startswith('/'): + result = '/' + result + self._cache[pattern] = result + return result def resolve(self, path, urlconf=None): - # TODO(dcramer): it'd be nice to pull out parameters - # and make this a normalized path resolver = get_resolver(urlconf) - match = resolver.regex.search(path) - if match: - new_path = path[match.end():] - for pattern in resolver.url_patterns: - try: - sub_match = pattern.resolve(new_path) - except Resolver404: - continue - if sub_match: - pattern = pattern.regex.pattern - try: - return self._cache[pattern] - except KeyError: - pass - - pattern_name = self._simplify(pattern) - self._cache[pattern] = pattern - return pattern_name - return path + match = self._resolve(resolver, path) + return match or path diff --git a/tests/contrib/django/test_resolver.py b/tests/contrib/django/test_resolver.py index 930d287..3960161 100644 --- a/tests/contrib/django/test_resolver.py +++ b/tests/contrib/django/test_resolver.py @@ -1,21 +1,42 @@ from __future__ import absolute_import +try: + from django.conf.urls import url, include +except ImportError: + # for Django version less than 1.4 + from django.conf.urls.defaults import url, include # NOQA + from raven.contrib.django.resolver import RouteResolver +included_url_conf = ( + url(r'^foo/bar/(?P<param>[\w]+)', lambda x: ''), +), '', '' + +example_url_conf = ( + url(r'^api/(?P<project_id>[\w_-]+)/store/$', lambda x: ''), + url(r'^example/', include(included_url_conf)), +) + def test_no_match(): resolver = RouteResolver() - result = resolver.resolve('/foo/bar', 'raven.contrib.django.urls') + result = resolver.resolve('/foo/bar', example_url_conf) assert result == '/foo/bar' def test_simple_match(): resolver = RouteResolver() - result = resolver.resolve('/report/', 'raven.contrib.django.urls') + result = resolver.resolve('/report/', example_url_conf) assert result == '/report/' def test_complex_match(): resolver = RouteResolver() - result = resolver.resolve('/api/1234/store/', 'raven.contrib.django.urls') + result = resolver.resolve('/api/1234/store/', example_url_conf) assert result == '/api/{project_id}/store/' + + +def test_included_match(): + resolver = RouteResolver() + result = resolver.resolve('/example/foo/bar/baz', example_url_conf) + assert result == '/example/foo/bar/{param}' |