summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hellkamp <marc@gsites.de>2009-07-13 12:24:30 +0200
committerMarcel Hellkamp <marc@gsites.de>2009-07-13 13:20:43 +0200
commit3da3db5b3f6418821a5a1aa2d17de1f21fc1767f (patch)
tree97e368034642a7b7ef6a041589e0d5fe0ebbfe98
parent8ad8e6122afadec6a6377b70f209f72556f4802c (diff)
downloadbottle-3da3db5b3f6418821a5a1aa2d17de1f21fc1767f.tar.gz
New 'nobreak' statement for SimpleTemplate, minor routing changes and some unit tests.
-rw-r--r--.gitignore1
-rw-r--r--MANIFEST.in1
-rw-r--r--bottle.py18
-rw-r--r--test/test_routes.py38
-rw-r--r--test/test_templates.py46
-rw-r--r--test/testall.py17
6 files changed, 112 insertions, 9 deletions
diff --git a/.gitignore b/.gitignore
index 045e75f..61301c4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,4 +7,3 @@ release.sh
*.db
MANIFEST
benchmark.py
-test*
diff --git a/MANIFEST.in b/MANIFEST.in
index b28c1e8..91adff4 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,3 +4,4 @@ include README.*
include docs/*.html
include examples/*.py
include examples/*.tpl
+include test/*.py
diff --git a/bottle.py b/bottle.py
index 7dfdbfb..4cc8f3e 100644
--- a/bottle.py
+++ b/bottle.py
@@ -383,17 +383,16 @@ def compile_route(route):
A more human readable syntax is supported too.
Example: '/user/:id/:action' will match '/user/5/kiss' with {'id':'5', 'action':'kiss'}
"""
- route = route.strip().lstrip('$^/ ').rstrip('$^ ')
route = re.sub(r':([a-zA-Z_]+)(?P<uniq>[^\w/])(?P<re>.+?)(?P=uniq)',r'(?P<\1>\g<re>)',route)
route = re.sub(r':([a-zA-Z_]+)',r'(?P<\1>[^/]+)', route)
- return re.compile('^/%s$' % route)
+ return re.compile('^%s$' % route)
def match_url(url, method='GET'):
"""Returns the first matching handler and a parameter dict or (None, None).
This reorders the ROUTING_REGEXP list every 1000 requests. To turn this off, use OPTIMIZER=False"""
- url = '/' + url.strip().lstrip("/")
+ url = url.strip().lstrip("/ ")
# Search for static routes first
route = ROUTES_SIMPLE.get(method,{}).get(url,None)
if route:
@@ -421,7 +420,8 @@ def add_route(route, handler, method='GET', simple=False):
return "Hello world!"
add_route(r'/hello', hello)"""
method = method.strip().upper()
- if re.match(r'^/(\w+/)*\w*$', route) or simple:
+ route = route.strip().lstrip('$^/ ').rstrip('$^ ')
+ if re.match(r'^(\w+/)*\w*$', route) or simple:
ROUTES_SIMPLE.setdefault(method, {})[route] = handler
else:
route = compile_route(route)
@@ -618,15 +618,17 @@ class SimpleTemplate(BaseTemplate):
self.subtemplates = {}
class PyStmt(str):
def __repr__(self): return 'str(' + self + ')'
- def flush():
- if len(strbuffer):
- code.append(" " * indent + "stdout.append(%s)" % repr(''.join(strbuffer)))
+ def flush(allow_nobreak=False):
+ bfr = ''.join(strbuffer)
+ if len(bfr):
+ if allow_nobreak and bfr.endswith("\\\\\n"): bfr=bfr[:-3]
+ code.append(" " * indent + "stdout.append(%s)" % repr(bfr))
code.append("\n" * len(strbuffer)) # to preserve line numbers
del strbuffer[:]
for line in template.splitlines(True):
m = self.re_python.match(line)
if m:
- flush()
+ flush(allow_nobreak=True)
keyword, include, end, statement = m.groups()
if keyword:
if keyword in self.dedent_keywords:
diff --git a/test/test_routes.py b/test/test_routes.py
new file mode 100644
index 0000000..7aa0b32
--- /dev/null
+++ b/test/test_routes.py
@@ -0,0 +1,38 @@
+import unittest
+import sys, os.path
+TESTDIR = os.path.dirname(os.path.abspath(__file__))
+DISTDIR = os.path.dirname(TESTDIR)
+sys.path.insert(0, TESTDIR)
+sys.path.insert(0, DISTDIR)
+
+from bottle import route, add_route, match_url, compile_route, ROUTES_REGEXP, ROUTES_SIMPLE
+
+class TestRoutes(unittest.TestCase):
+
+ def test_static(self):
+ """ Routes: Static routes """
+ token = 'abc'
+ routes = ['','/','/abc','abc','/abc/','/abc/def','/abc/def.ghi']
+ for r in routes:
+ add_route(r, token, simple=True)
+ self.assertTrue('GET' in ROUTES_SIMPLE)
+ r = [r for r in ROUTES_SIMPLE['GET'].values() if r == 'abc']
+ self.assertEqual(5, len(r))
+ for r in routes:
+ self.assertEqual(token, match_url(r)[0])
+
+ def test_dynamic(self):
+ """ Routes: Dynamic routes """
+ token = 'abcd'
+ add_route('/:a/:b', token)
+ self.assertTrue('GET' in ROUTES_REGEXP)
+ self.assertEqual(token, match_url('/aa/bb')[0])
+ self.assertEqual(None, match_url('/aa')[0])
+ self.assertEqual(repr({'a':'aa','b':'bb'}), repr(match_url('/aa/bb')[1]))
+
+
+suite = unittest.TestSuite()
+suite.addTest(unittest.makeSuite(TestRoutes))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/test_templates.py b/test/test_templates.py
new file mode 100644
index 0000000..42d88bb
--- /dev/null
+++ b/test/test_templates.py
@@ -0,0 +1,46 @@
+import unittest
+import sys, os.path
+TESTDIR = os.path.dirname(os.path.abspath(__file__))
+DISTDIR = os.path.dirname(TESTDIR)
+sys.path.insert(0, TESTDIR)
+sys.path.insert(0, DISTDIR)
+
+from bottle import SimpleTemplate
+
+class TestSimpleTemplate(unittest.TestCase):
+
+ def test_inline(self):
+ """ Templates: Inline statements """
+ t = SimpleTemplate('start {{var}} end')
+ self.assertEqual('start True end', t.render(var=True))
+ self.assertEqual('start False end', t.render(var=False))
+ self.assertEqual('start None end', t.render(var=None))
+ self.assertEqual('start 0 end', t.render(var=0))
+ self.assertEqual('start 5 end', t.render(var=5))
+ self.assertEqual('start b end', t.render(var='b'))
+ self.assertEqual('start 1.0 end', t.render(var=1.0))
+ self.assertEqual('start [1, 2] end', t.render(var=[1,2]))
+
+ def test_blocks(self):
+ """ Templates: Code blocks and loops """
+ t = SimpleTemplate("start\n%for i in l:\n{{i}} \n%end\nend")
+ self.assertEqual('start\n1 \n2 \n3 \nend', t.render(l=[1,2,3]))
+ self.assertEqual('start\nend', t.render(l=[]))
+
+ def test_nobreak(self):
+ """ Templates: Nobreak statements"""
+ t = SimpleTemplate("start\\\\\n%pass\nend")
+ self.assertEqual('startend', t.render())
+
+ def test_nonobreak(self):
+ """ Templates: Escaped nobreak statements"""
+ t = SimpleTemplate("start\\\\\n\\\\\n%pass\nend")
+ self.assertEqual('start\\\\\nend', t.render())
+
+suite = unittest.TestSuite()
+suite.addTest(unittest.makeSuite(TestSimpleTemplate))
+
+
+if __name__ == '__main__':
+ unittest.main()
+
diff --git a/test/testall.py b/test/testall.py
new file mode 100644
index 0000000..4e71066
--- /dev/null
+++ b/test/testall.py
@@ -0,0 +1,17 @@
+import unittest
+import sys, os.path
+TESTDIR = os.path.dirname(os.path.abspath(__file__))
+DISTDIR = os.path.dirname(TESTDIR)
+sys.path.insert(0, TESTDIR)
+sys.path.insert(0, DISTDIR)
+
+from test_templates import suite as suite1
+from test_routes import suite as suite2
+
+suite = unittest.TestSuite()
+suite.addTest(suite1)
+suite.addTest(suite2)
+
+if __name__ == '__main__':
+ unittest.TextTestRunner(verbosity=2).run(suite)
+