summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt16
-rw-r--r--pyramid/tests/test_urldispatch.py16
-rw-r--r--pyramid/urldispatch.py10
3 files changed, 40 insertions, 2 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index ffafe1b7d..34e8cd7b6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,19 @@
+Next release
+============
+
+Bug Fixes
+---------
+
+- URL pattern markers used in URL dispatch are permitted to specify a custom
+ regex. For example, the pattern ``/{foo:\d+}`` means to match ``/12345``
+ (foo==12345 in the match dictionary) but not ``/abc``. However, custom
+ regexes in a pattern marker which used squiggly brackets did not work. For
+ example, ``/{foo:\d{4}}`` would fail to match ``/1234`` and
+ ``/{foo:\d{1,2}}`` would fail to match ``/1`` or ``/11``. One level of
+ inner squiggly brackets is now recognized so that the prior two patterns
+ given as examples now work. See also
+ https://github.com/Pylons/pyramid/issues/#issue/123.
+
1.0 (2011-01-30)
================
diff --git a/pyramid/tests/test_urldispatch.py b/pyramid/tests/test_urldispatch.py
index a452fdb97..eca4603a3 100644
--- a/pyramid/tests/test_urldispatch.py
+++ b/pyramid/tests/test_urldispatch.py
@@ -268,7 +268,21 @@ class TestCompileRoute(unittest.TestCase):
self.assertEqual(matcher('/foo/baz/biz/buz.bar'),
{'baz':'baz', 'buz':'buz', 'bar':'bar'})
self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
- self.assertEqual(generator({'baz':1, 'buz':2, 'bar': 'html'}), '/foo/1/biz/2.html')
+ self.assertEqual(generator({'baz':1, 'buz':2, 'bar': 'html'}),
+ '/foo/1/biz/2.html')
+
+ def test_custom_regex_with_embedded_squigglies(self):
+ matcher, generator = self._callFUT('/{buz:\d{4}}')
+ self.assertEqual(matcher('/2001'), {'buz':'2001'})
+ self.assertEqual(matcher('/200'), None)
+ self.assertEqual(generator({'buz':2001}), '/2001')
+
+ def test_custom_regex_with_embedded_squigglies2(self):
+ matcher, generator = self._callFUT('/{buz:\d{3,4}}')
+ self.assertEqual(matcher('/2001'), {'buz':'2001'})
+ self.assertEqual(matcher('/200'), {'buz':'200'})
+ self.assertEqual(matcher('/20'), None)
+ self.assertEqual(generator({'buz':2001}), '/2001')
class TestCompileRouteMatchFunctional(unittest.TestCase):
def matches(self, pattern, path, expected):
diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py
index 5d1e53947..57ca8ff83 100644
--- a/pyramid/urldispatch.py
+++ b/pyramid/urldispatch.py
@@ -76,7 +76,13 @@ class RoutesMapper(object):
# stolen from bobo and modified
old_route_re = re.compile(r'(\:[a-zA-Z]\w*)')
star_in_brackets = re.compile(r'\{[^\}]*\*\w*[^\}]*\}')
-route_re = re.compile(r'(\{[a-zA-Z][^\}]*\})')
+# The torturous nature of the regex named ``route_re`` below is due to the
+# fact that we need to support at least one level of "inner" squigglies
+# inside the expr of a {name:expr} pattern. This regex used to be just
+# (\{[a-zA-Z][^\}]*\}) but that choked when supplied with e.g. {foo:\d{4}}.
+# Thanks to Zart for the regex help.
+route_re = re.compile(r'(\{[a-zA-Z](?:\{[^\}]*\}|[^\{\}]*)*\})')
+
def update_pattern(matchobj):
name = matchobj.group(0)
return '{%s}' % name[1:]
@@ -103,6 +109,8 @@ def _compile_route(route):
name = name[1:-1]
if ':' in name:
name, reg = name.split(':')
+ reg = reg.replace(r'\{', '{')
+ reg = reg.replace(r'\}', '}')
else:
reg = '[^/]+'
gen.append('%%(%s)s' % name)