summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pyramid/tests/test_traversal.py52
-rw-r--r--pyramid/tests/test_url.py63
-rw-r--r--pyramid/tests/test_urldispatch.py19
-rw-r--r--pyramid/tests/test_view.py26
-rw-r--r--pyramid/traversal.py8
-rw-r--r--pyramid/urldispatch.py33
-rw-r--r--pyramid/util.py6
7 files changed, 179 insertions, 28 deletions
diff --git a/pyramid/tests/test_traversal.py b/pyramid/tests/test_traversal.py
index d0afb9a2b..89edb230b 100644
--- a/pyramid/tests/test_traversal.py
+++ b/pyramid/tests/test_traversal.py
@@ -336,6 +336,19 @@ class ResourceTreeTraverserTests(unittest.TestCase):
self.assertEqual(result['virtual_root'], resource)
self.assertEqual(result['virtual_root_path'], ())
+ def test_withroute_and_traverse_empty(self):
+ resource = DummyContext()
+ traverser = self._makeOne(resource)
+ environ = {'bfg.routes.matchdict': {'traverse':''}}
+ result = traverser(environ)
+ self.assertEqual(result['context'], resource)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], ())
+ self.assertEqual(result['root'], resource)
+ self.assertEqual(result['virtual_root'], resource)
+ self.assertEqual(result['virtual_root_path'], ())
+
class FindInterfaceTests(unittest.TestCase):
def _callFUT(self, context, iface):
from pyramid.traversal import find_interface
@@ -653,6 +666,16 @@ class ResourcePathTupleTests(unittest.TestCase):
result = self._callFUT(root)
self.assertEqual(result, ('',))
+ def test_root_default_emptystring_name(self):
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = ''
+ other = DummyContext()
+ other.__parent__ = root
+ other.__name__ = 'other'
+ result = self._callFUT(other)
+ self.assertEqual(result, ('', 'other',))
+
def test_nonroot_default(self):
root = DummyContext()
root.__parent__ = None
@@ -802,6 +825,22 @@ class TraversalContextURLTests(unittest.TestCase):
result = context_url()
self.assertEqual(result, 'http://example.com:5432/')
+ def test_call_with_virtual_root_path_physical_not_startwith_vroot(self):
+ from pyramid.interfaces import VH_ROOT_KEY
+ root = DummyContext()
+ root.__parent__ = None
+ root.__name__ = None
+ one = DummyContext()
+ one.__parent__ = root
+ one.__name__ = 'one'
+ two = DummyContext()
+ two.__parent__ = one
+ two.__name__ = 'two'
+ request = DummyRequest({VH_ROOT_KEY:'/wrong'})
+ context_url = self._makeOne(two, request)
+ result = context_url()
+ self.assertEqual(result, 'http://example.com:5432/one/two/')
+
def test_virtual_root_no_virtual_root_path(self):
root = DummyContext()
root.__name__ = None
@@ -1058,6 +1097,19 @@ class TestDefaultRootFactory(unittest.TestCase):
self.assertEqual(root.a, 1)
self.assertEqual(root.b, 2)
+class Test__join_path_tuple(unittest.TestCase):
+ def _callFUT(self, tup):
+ from pyramid.traversal import _join_path_tuple
+ return _join_path_tuple(tup)
+
+ def test_empty_tuple(self):
+ # tests "or '/'" case
+ result = self._callFUT(())
+ self.assertEqual(result, '/')
+
+ def test_nonempty_tuple(self):
+ result = self._callFUT(('x',))
+ self.assertEqual(result, 'x')
def make_traverser(result):
class DummyTraverser(object):
diff --git a/pyramid/tests/test_url.py b/pyramid/tests/test_url.py
index e13fbbb91..08708d93b 100644
--- a/pyramid/tests/test_url.py
+++ b/pyramid/tests/test_url.py
@@ -160,11 +160,18 @@ class TestRouteUrl(unittest.TestCase):
request = _makeRequest()
mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
request.registry.registerUtility(mapper, IRoutesMapper)
- result = self._callFUT('flub', request, 'extra1', 'extra2',
- a=1, b=2, c=3, _query={'a':1},
- _anchor=u"foo")
+ result = self._callFUT('flub', request, 'extra1', 'extra2')
self.assertEqual(result,
- 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
+ 'http://example.com:5432/1/2/3/extra1/extra2')
+
+ def test_with_elements_path_endswith_slash(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3/'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = self._callFUT('flub', request, 'extra1', 'extra2')
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3/extra1/extra2')
def test_no_elements(self):
from pyramid.interfaces import IRoutesMapper
@@ -176,6 +183,43 @@ class TestRouteUrl(unittest.TestCase):
self.assertEqual(result,
'http://example.com:5432/1/2/3?a=1#foo')
+ def test_with_anchor_string(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = self._callFUT('flub', request, _anchor="La Pe\xc3\xb1a")
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3#La Pe\xc3\xb1a')
+
+ def test_with_anchor_unicode(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ anchor = unicode('La Pe\xc3\xb1a', 'utf-8')
+ result = self._callFUT('flub', request, _anchor=anchor)
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3#La Pe\xc3\xb1a')
+
+ def test_with_query(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = self._callFUT('flub', request, _query={'q':'1'})
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3?q=1')
+
+ def test_with_app_url(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute('/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = self._callFUT('flub', request, _app_url='http://example2.com')
+ self.assertEqual(result,
+ 'http://example2.com/1/2/3')
+
def test_it_generation_error(self):
from pyramid.interfaces import IRoutesMapper
request = _makeRequest()
@@ -217,6 +261,17 @@ class TestRouteUrl(unittest.TestCase):
self.assertEqual(result, 'http://example2.com/1/2/3/a')
self.assertEqual(route.kw, {}) # shouldnt have anchor/query
+ def test_with_anchor_app_url_elements_and_query(self):
+ from pyramid.interfaces import IRoutesMapper
+ request = _makeRequest()
+ mapper = DummyRoutesMapper(route=DummyRoute(result='/1/2/3'))
+ request.registry.registerUtility(mapper, IRoutesMapper)
+ result = self._callFUT('flub', request, 'element1',
+ _app_url='http://example2.com',
+ _anchor='anchor', _query={'q':'1'})
+ self.assertEqual(result,
+ 'http://example2.com/1/2/3/element1?q=1#anchor')
+
class TestCurrentRouteUrl(unittest.TestCase):
def setUp(self):
cleanUp()
diff --git a/pyramid/tests/test_urldispatch.py b/pyramid/tests/test_urldispatch.py
index 82ecd2b79..5be04478f 100644
--- a/pyramid/tests/test_urldispatch.py
+++ b/pyramid/tests/test_urldispatch.py
@@ -175,6 +175,14 @@ class RoutesMapperTests(unittest.TestCase):
self.assertEqual(result['route'], mapper.routes['root'])
self.assertEqual(result['match'], {})
+ def test___call__root_route_when_path_info_notempty(self):
+ mapper = self._makeOne()
+ mapper.connect('root', '/')
+ request = self._getRequest(PATH_INFO='/')
+ result = mapper(request)
+ self.assertEqual(result['route'], mapper.routes['root'])
+ self.assertEqual(result['match'], {})
+
def test___call__no_path_info(self):
mapper = self._makeOne()
mapper.connect('root', '/')
@@ -241,7 +249,8 @@ class TestCompileRoute(unittest.TestCase):
{'baz':1, 'buz':2, 'traverse':u'/a/b'}), '/foo/1/biz/2/bar/a/b')
def test_with_bracket_star(self):
- matcher, generator = self._callFUT('/foo/{baz}/biz/{buz}/bar{remainder:.*}')
+ matcher, generator = self._callFUT(
+ '/foo/{baz}/biz/{buz}/bar{remainder:.*}')
self.assertEqual(matcher('/foo/baz/biz/buz/bar'),
{'baz':'baz', 'buz':'buz', 'remainder':''})
self.assertEqual(matcher('/foo/baz/biz/buz/bar/everything/else/here'),
@@ -271,6 +280,14 @@ class TestCompileRoute(unittest.TestCase):
self.assertEqual(generator({'baz':1, 'buz':2, 'bar': 'html'}),
'/foo/1/biz/2.html')
+ def test_mixed_newstyle_oldstyle_pattern_defaults_to_newstyle(self):
+ # pattern: '\\/foo\\/(?P<baz>abc)\\/biz\\/(?P<buz>[^/]+)\\/bar$'
+ # note presence of :abc in pattern (oldstyle match)
+ matcher, generator = self._callFUT('foo/{baz:abc}/biz/{buz}/bar')
+ self.assertEqual(matcher('/foo/abc/biz/buz/bar'),
+ {'baz':'abc', 'buz':'buz'})
+ self.assertEqual(generator({'baz':1, 'buz':2}), '/foo/1/biz/2/bar')
+
# XXX reenable after torturous_route_re replacement is found for
# Jython
## def test_custom_regex_with_embedded_squigglies(self):
diff --git a/pyramid/tests/test_view.py b/pyramid/tests/test_view.py
index 0e88351b1..5d6028b4f 100644
--- a/pyramid/tests/test_view.py
+++ b/pyramid/tests/test_view.py
@@ -241,6 +241,14 @@ class TestViewConfigDecorator(unittest.TestCase):
self.assertEqual(decorator.request_type, None)
self.assertEqual(decorator.context, None)
self.assertEqual(decorator.permission, None)
+
+ def test_create_context_trumps_for(self):
+ decorator = self._makeOne(context='123', for_='456')
+ self.assertEqual(decorator.context, '123')
+
+ def test_create_for_trumps_context_None(self):
+ decorator = self._makeOne(context=None, for_='456')
+ self.assertEqual(decorator.context, '456')
def test_create_nondefaults(self):
decorator = self._makeOne(name=None, request_type=None, for_=None,
@@ -279,6 +287,22 @@ class TestViewConfigDecorator(unittest.TestCase):
self.assertEqual(settings[0]['permission'], None)
self.assertEqual(settings[0]['context'], None)
self.assertEqual(settings[0]['request_type'], None)
+ self.assertEqual(settings[0]['attr'], 'foo')
+
+ def test_call_class_attr_already_set(self):
+ decorator = self._makeOne(attr='abc')
+ venusian = DummyVenusian()
+ decorator.venusian = venusian
+ decorator.venusian.info.scope = 'class'
+ class foo(object): pass
+ wrapped = decorator(foo)
+ self.failUnless(wrapped is foo)
+ settings = call_venusian(venusian)
+ self.assertEqual(len(settings), 1)
+ self.assertEqual(settings[0]['permission'], None)
+ self.assertEqual(settings[0]['context'], None)
+ self.assertEqual(settings[0]['request_type'], None)
+ self.assertEqual(settings[0]['attr'], 'abc')
def test_stacking(self):
decorator1 = self._makeOne(name='1')
@@ -455,7 +479,7 @@ class Test_default_exceptionresponse_view(unittest.TestCase):
result = self._callFUT(context, None)
self.failUnless(result is context)
- def test_is_not_exception_context_is_false_still_chosen(self):
+ def test_is_not_exception_context_is_false_still_chose(self):
request = DummyRequest()
request.exception = 0
result = self._callFUT(None, request)
diff --git a/pyramid/traversal.py b/pyramid/traversal.py
index c69892854..540f17a31 100644
--- a/pyramid/traversal.py
+++ b/pyramid/traversal.py
@@ -577,14 +577,14 @@ class ResourceTreeTraverser(object):
if 'bfg.routes.matchdict' in environ:
matchdict = environ['bfg.routes.matchdict']
- path = matchdict.get('traverse', '/')
+ path = matchdict.get('traverse', '/') or '/'
if hasattr(path, '__iter__'):
- # this is a *traverse stararg (not a :traverse)
+ # this is a *traverse stararg (not a {traverse})
path = '/'.join([quote_path_segment(x) for x in path]) or '/'
subpath = matchdict.get('subpath', ())
if not hasattr(subpath, '__iter__'):
- # this is not a *subpath stararg (just a :subpath)
+ # this is not a *subpath stararg (just a {subpath})
subpath = traversal_path(subpath)
else:
@@ -608,7 +608,7 @@ class ResourceTreeTraverser(object):
root = self.root
ob = vroot = root
- if vpath == '/' or (not vpath):
+ if vpath == '/': # invariant: vpath must not be empty
# prevent a call to traversal_path if we know it's going
# to return the empty tuple
vpath_tuple = ()
diff --git a/pyramid/urldispatch.py b/pyramid/urldispatch.py
index c4c72362e..be737201b 100644
--- a/pyramid/urldispatch.py
+++ b/pyramid/urldispatch.py
@@ -102,17 +102,19 @@ def _compile_route(route):
if not route.startswith('/'):
route = '/' + route
+
star = None
+
if '*' in route and not star_in_brackets.search(route):
route, star = route.rsplit('*', 1)
pat = route_re.split(route)
pat.reverse()
rpat = []
gen = []
- prefix = pat.pop()
- if prefix:
- rpat.append(re.escape(prefix))
- gen.append(prefix)
+ prefix = pat.pop() # invar: always at least one element (route='/'+route)
+ rpat.append(re.escape(prefix))
+ gen.append(prefix)
+
while pat:
name = pat.pop()
name = name[1:-1]
@@ -140,18 +142,17 @@ def _compile_route(route):
if m is None:
return m
d = {}
- for k,v in m.groupdict().iteritems():
- if k is not None:
- if k == star:
- d[k] = traversal_path(v)
- else:
- encoded = unquote(v)
- try:
- d[k] = encoded.decode('utf-8')
- except UnicodeDecodeError, e:
- raise URLDecodeError(
- e.encoding, e.object, e.start, e.end, e.reason
- )
+ for k, v in m.groupdict().iteritems():
+ if k == star:
+ d[k] = traversal_path(v)
+ else:
+ encoded = unquote(v)
+ try:
+ d[k] = encoded.decode('utf-8')
+ except UnicodeDecodeError, e:
+ raise URLDecodeError(
+ e.encoding, e.object, e.start, e.end, e.reason
+ )
return d
diff --git a/pyramid/util.py b/pyramid/util.py
index faab2c54c..3e6cd2e60 100644
--- a/pyramid/util.py
+++ b/pyramid/util.py
@@ -94,9 +94,11 @@ class DottedNameResolver(object):
def _zope_dottedname_style(self, value):
""" package.module.attr style """
- module = self.package_name and self.package_name or None
+ module = self.package_name
+ if not module:
+ module = None
if value == '.':
- if self.package_name is None:
+ if module is None:
raise ConfigurationError(
'relative name %r irresolveable without package' % (value,)
)