diff options
| -rw-r--r-- | pyramid/tests/test_traversal.py | 52 | ||||
| -rw-r--r-- | pyramid/tests/test_url.py | 63 | ||||
| -rw-r--r-- | pyramid/tests/test_urldispatch.py | 19 | ||||
| -rw-r--r-- | pyramid/tests/test_view.py | 26 | ||||
| -rw-r--r-- | pyramid/traversal.py | 8 | ||||
| -rw-r--r-- | pyramid/urldispatch.py | 33 | ||||
| -rw-r--r-- | pyramid/util.py | 6 |
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,) ) |
