CHANGES.txt | ●●●●● patch | view | raw | blame | history | |
pyramid/configuration.py | ●●●●● patch | view | raw | blame | history | |
pyramid/request.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_configuration.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_request.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_traversal.py | ●●●●● patch | view | raw | blame | history | |
pyramid/traversal.py | ●●●●● patch | view | raw | blame | history |
CHANGES.txt
@@ -8,6 +8,9 @@ represent the function that returns a WSGI application, each now uses WebError, each now has roughly the same shape of development.ini style. - Added class vars ``matchdict`` and ``matched_route`` to ``pyramid.request.Request``. Each is set to ``None``. Bug Fixes --------- @@ -154,7 +157,7 @@ - The deprecated API ``pyramid.testing.registerViewPermission`` has been removed. - The deprecated API named ``pyramid.testing.registerRoutesMapper`` - The deprecated API named ``pyramid.testing.registerRoutesMapper`` has been removed. - The deprecated API named ``pyramid.request.get_request`` was removed. pyramid/configuration.py
@@ -263,7 +263,7 @@ policy = self.maybe_dotted(policy) self.registry.registerUtility(policy, IAuthenticationPolicy, info=_info) def _set_authorization_policy(self, policy, _info=u''): """ Add a :app:`Pyramid` :term:`authorization policy` to the current configuration state (also accepts a :term:`dotted @@ -472,7 +472,7 @@ def derive_view(self, view, attr=None, renderer=None): """ Create a :term:`view callable` using the function, instance, or class (or :term:`dotted Python name` referring to the same) provided as ``view`` object. @@ -582,7 +582,7 @@ config.add_settings({'external_uri':'http://example.com'}) Or a set of key/value pairs:: config.add_settings(external_uri='http://example.com') This function is useful when you need to test code that calls @@ -658,7 +658,7 @@ """ Add a Pylons-style view handler. This function adds a route and some number of views based on a handler object (usually a class). ``route_name`` is the name of the route (to be used later in URL generation). @@ -668,7 +668,7 @@ ``route_name`` is used. If ``pattern`` is ``None`` and no route named ``route_name`` exists, a ``ConfigurationError`` is raised. ``handler`` is a dotted name of (or direct reference to) a Python handler class, e.g. ``'my.package.handlers.MyHandler'``. @@ -698,7 +698,7 @@ 'The "pattern" parameter may only be "None" when a route ' 'with the route_name argument was previously registered. ' 'No such route named %r exists' % route_name) pattern = route.pattern path_has_action = ':action' in pattern or '{action}' in pattern @@ -735,7 +735,7 @@ method_name = action if method_name is None: method_name = '__call__' # Scan the controller for any other methods with this action name for meth_name, method in inspect.getmembers( handler, inspect.ismethod): @@ -754,7 +754,7 @@ del view_args['name'] self.add_view(view=handler, attr=meth_name, route_name=route_name, **view_args) # Now register the method itself method = getattr(handler, method_name, None) configs = getattr(method, '__exposed__', [{}]) @@ -1001,7 +1001,7 @@ variable. If the regex matches, this predicate will be ``True``. custom_predicates This value should be a sequence of references to custom @@ -1145,11 +1145,11 @@ # the same predicate hash as this view; this registration # is therefore an override. regclosure() else: # - A view or multiview was already registered for this # triad, and the new view is not an override. # XXX we could try to be more efficient here and register # a non-secured view for a multiview if none of the # multiview's consituent views have a permission @@ -1401,7 +1401,7 @@ A Python object or :term:`dotted Python name` to the same object that will be used as a view callable when this route matches. e.g. ``mypackage.views.my_view``. view_context A class or an :term:`interface` or :term:`dotted Python @@ -1487,7 +1487,7 @@ traverse=traverse, custom=custom_predicates ) request_iface = self.registry.queryUtility(IRouteRequest, name=name) if request_iface is None: bases = use_global_views and (IRequest,) or () @@ -1524,7 +1524,7 @@ pattern = path if pattern is None: raise ConfigurationError('"pattern" argument may not be None') return mapper.connect(name, pattern, factory, predicates=predicates, pregenerator=pregenerator) @@ -2731,7 +2731,7 @@ the resolver's ``resolve`` and ``maybe_resolve`` methods. A dotted name which has a ``.`` (dot) or ``:`` (colon) as its first character is treated as relative. If the value ``None`` is supplied as the package name, the resolver will only be able to resolve fully qualified (not relative) names. Any attempt to resolve a relative name when the @@ -2839,7 +2839,7 @@ raise ConfigurationError( 'The dotted name %r cannot be imported' % (dotted,)) return dotted class ActionPredicate(object): action_name = 'action' @@ -2851,7 +2851,7 @@ raise ConfigurationError(why[0]) def __call__(self, context, request): matchdict = getattr(request, 'matchdict', None) matchdict = request.matchdict if matchdict is None: return False action = matchdict.get(self.action_name) @@ -2863,4 +2863,4 @@ # allow this predicate's phash to be compared as equal to # others that share the same action name return hash(self.action) pyramid/request.py
@@ -37,6 +37,8 @@ response_callbacks = () finished_callbacks = () exception = None matchdict = None matched_route = None @reify def tmpl_context(self): pyramid/tests/test_configuration.py
@@ -567,7 +567,7 @@ self.assertEqual(L[0], event) config.registry.subscribers((event.object, IDummy), None) self.assertEqual(len(L), 1) def test_make_wsgi_app(self): from pyramid.router import Router from pyramid.interfaces import IApplicationCreated @@ -1934,7 +1934,7 @@ def test_add_handler_with_action_and_action_in_path(self): from pyramid.exceptions import ConfigurationError config = self._makeOne() self.assertRaises(ConfigurationError, config.add_handler, self.assertRaises(ConfigurationError, config.add_handler, 'name', '/{action}', DummyHandler, action='abc') def test_add_handler_with_explicit_action(self): @@ -1970,7 +1970,7 @@ self.assertEqual(view['attr'], None) self.assertEqual(view['route_name'], 'name') self.assertEqual(view['view'], DummyHandler) def test_add_handler_with_multiple_action(self): config = self._makeOne() class DummyHandler(object): @@ -2584,7 +2584,7 @@ self.failUnless(result is view) self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(view(None, None), 'OK') def test__derive_view_as_function_requestonly(self): def view(request): return 'OK' @@ -2611,7 +2611,7 @@ self.assertEqual(view.__name__, result.__name__) self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(result(None, None), 'OK') def test__derive_view_as_newstyle_class_requestonly(self): class view(object): def __init__(self, context, request): @@ -2641,7 +2641,7 @@ self.assertEqual(view.__name__, result.__name__) self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(result(None, None), 'OK') def test__derive_view_as_oldstyle_class_requestonly(self): class view: def __init__(self, context, request): @@ -2667,7 +2667,7 @@ self.failUnless(result is view) self.failIf(hasattr(result, '__call_permissive__')) self.assertEqual(result(None, None), 'OK') def test__derive_view_as_instance_requestonly(self): class View: def __call__(self, request): @@ -2745,7 +2745,7 @@ self.assertEqual(logger.messages[0], "debug_authorization of url url (view name " "'view_name' against context None): True") def test__derive_view_debug_auth_permission_authpol_denied(self): from pyramid.exceptions import Forbidden view = lambda *arg: 'OK' @@ -3028,10 +3028,10 @@ result = render_view_to_response(ctx, req, 'stacked_method2') self.assertEqual(result, 'stacked_method') result = render_view_to_response(ctx, req, 'subpackage_init') self.assertEqual(result, 'subpackage_init') result = render_view_to_response(ctx, req, 'subpackage_notinit') self.assertEqual(result, 'subpackage_notinit') @@ -3132,7 +3132,7 @@ self.assertEqual(len(L), 2) self.assertEqual(L[0], 'foo') self.assertEqual(L[1], event) def test_testing_add_subscriber_defaults(self): config = self._makeOne() L = config.testing_add_subscriber() @@ -3149,7 +3149,7 @@ config = self._makeOne() config.hook_zca(getSiteManager=gsm) self.assertEqual(gsm.hook, get_current_registry) def test_unhook_zca(self): gsm = DummyGetSiteManager() config = self._makeOne() @@ -3170,7 +3170,7 @@ renderer.assert_(foo=1) renderer.assert_(bar=2) renderer.assert_(request=request) def test_testing_add_renderer_explicitrenderer(self): config = self._makeOne() class E(Exception): pass @@ -3188,7 +3188,7 @@ except E: pass else: # pragma: no cover raise AssertionError raise AssertionError def test_testing_add_template(self): config = self._makeOne() @@ -3214,7 +3214,7 @@ def tearDown(self): del self.registry testing.tearDown() def _registerRenderer(self, typ='.txt'): from pyramid.interfaces import IRendererFactory from pyramid.interfaces import ITemplateRenderer @@ -3237,7 +3237,7 @@ def _callFUT(self, *arg, **kw): from pyramid.configuration import _map_view return _map_view(*arg, **kw) def test__map_view_as_function_context_and_request(self): def view(context, request): return 'OK' @@ -3259,7 +3259,7 @@ result = self._callFUT(view, attr='__name__', renderer=info) self.failIf(result is view) self.assertRaises(TypeError, result, None, None) def test__map_view_as_function_requestonly(self): def view(request): return 'OK' @@ -3322,7 +3322,7 @@ self.assertEqual(view.__name__, result.__name__) request = self._makeRequest() self.assertEqual(result(None, request).body, 'Hello!') def test__map_view_as_newstyle_class_requestonly(self): class view(object): def __init__(self, request): @@ -3457,7 +3457,7 @@ result = self._callFUT(view) self.failUnless(result is view) self.assertEqual(result(None, None), 'OK') def test__map_view_as_instance_context_and_request_and_attr(self): class View: def index(self, context, request): @@ -3547,7 +3547,7 @@ def _callFUT(self, wrapped, original): from pyramid.configuration import decorate_view return decorate_view(wrapped, original) def test_it_same(self): def view(context, request): """ """ @@ -3700,7 +3700,7 @@ ) order3, _, _ = self._callFUT( path_info='path_info', ) ) order4, _, _ = self._callFUT( request_param='param', ) @@ -3809,7 +3809,7 @@ def _makeOne(self, name='name'): return self._getTargetClass()(name) def test_class_implements_ISecuredView(self): from zope.interface.verify import verifyClass from pyramid.interfaces import ISecuredView @@ -3925,7 +3925,7 @@ """ """ mv.views = [(100, view, None)] self.assertEqual(mv.__permitted__(None, None), True) def test_permitted(self): mv = self._makeOne() def view(context, request): @@ -4047,13 +4047,13 @@ mv.accepts = ['text/xml'] response = mv(context, request) self.assertEqual(response, expected_response) class TestRequestOnly(unittest.TestCase): def _callFUT(self, arg): from pyramid.configuration import requestonly return requestonly(arg) def test_newstyle_class_no_init(self): class foo(object): """ """ @@ -4064,7 +4064,7 @@ def __init__(self, context, request): """ """ self.assertFalse(self._callFUT(foo)) def test_newstyle_class_init_onearg_named_request(self): class foo(object): def __init__(self, request): @@ -4105,7 +4105,7 @@ def __init__(self, context, request): """ """ self.assertFalse(self._callFUT(foo)) def test_oldstyle_class_init_onearg_named_request(self): class foo: def __init__(self, request): @@ -4140,7 +4140,7 @@ def foo(context, request): """ """ self.assertFalse(self._callFUT(foo)) def test_function_onearg_named_request(self): def foo(request): """ """ @@ -4172,7 +4172,7 @@ """ """ foo = Foo() self.assertFalse(self._callFUT(foo)) def test_instance_defaultargs_onearg_named_request(self): class Foo: def __call__(self, request): @@ -4269,7 +4269,7 @@ result = typ._zope_dottedname_style( 'pyramid.tests.test_configuration.TestDottedNameResolver') self.assertEqual(result, self.__class__) def test_zope_dottedname_style_irrresolveable_absolute(self): typ = self._makeOne() self.assertRaises(ImportError, typ._zope_dottedname_style, @@ -4339,7 +4339,7 @@ result = typ._pkg_resources_style( 'pyramid.tests.test_configuration:TestDottedNameResolver') self.assertEqual(result, self.__class__) def test__pkg_resources_style_irrresolveable_absolute(self): typ = self._makeOne() self.assertRaises(ImportError, typ._pkg_resources_style, @@ -4357,7 +4357,7 @@ typ = self._makeOne(package=pyramid.tests) result = typ._pkg_resources_style('.') self.assertEqual(result, pyramid.tests) def test__pkg_resources_style_resolve_relative_nocurrentpackage(self): typ = self._makeOne() from pyramid.exceptions import ConfigurationError @@ -4431,7 +4431,7 @@ def _callFUT(self, ob): from pyramid.configuration import isexception return isexception(ob) def test_is_exception_instance(self): class E(Exception): pass @@ -4457,7 +4457,7 @@ def _getTargetClass(self): from pyramid.configuration import ActionPredicate return ActionPredicate def _makeOne(self, action='myaction'): return self._getTargetClass()(action) @@ -4501,11 +4501,12 @@ self.assertEqual(hash(pred1), hash(pred2)) self.assertNotEqual(hash(pred1), hash(pred3)) self.assertNotEqual(hash(pred2), hash(pred3)) class DummyRequest: subpath = () matchdict = None def __init__(self): self.environ = {'PATH_INFO':'/static'} self.params = {} @@ -4524,7 +4525,7 @@ def release(self): self.released = True class DummyPackage: def __init__(self, name): self.__name__ = name @@ -4592,13 +4593,13 @@ def load_zcml(self, filename): self.zcml_file = filename def make_wsgi_app(self): return self def hook_zca(self): self.zca_hooked = True class DummyAccept(object): def __init__(self, *matches): @@ -4632,7 +4633,7 @@ self.hook = hook def reset(self): self.unhooked = True class DummyThreadLocalManager(object): pushed = None popped = False @@ -4648,17 +4649,17 @@ implements(IFactory) def __call__(self): """ """ class DummyEvent: implements(IDummy) class DummyStaticURLInfo: def __init__(self): self.added = [] def add(self, name, spec, **kw): self.added.append((name, spec, kw)) def dummy_view(request): return 'OK' pyramid/tests/test_request.py
@@ -8,7 +8,7 @@ def tearDown(self): self.config.end() def _makeOne(self, environ): return self._getTargetClass()(environ) @@ -23,6 +23,14 @@ def test_exception_defaults_to_None(self): r = self._makeOne({'PATH_INFO':'/'}) self.assertEqual(r.exception, None) def test_matchdict_defaults_to_None(self): r = self._makeOne({'PATH_INFO':'/'}) self.assertEqual(r.matchdict, None) def test_matched_route_defaults_to_None(self): r = self._makeOne({'PATH_INFO':'/'}) self.assertEqual(r.matched_route, None) def test_params_decoded_from_utf_8_by_default(self): environ = { @@ -48,7 +56,7 @@ inst = self._makeOne({}) result = inst.tmpl_context self.assertEqual(result.__class__, TemplateContext) def test_session_configured(self): from pyramid.interfaces import ISessionFactory inst = self._makeOne({}) @@ -107,7 +115,7 @@ environ = {'zooma':1} inst = self._makeOne(environ) self.assertEqual(inst.get('zooma'), 1) def test_has_key(self): environ = {'zooma':1} inst = self._makeOne(environ) pyramid/tests/test_traversal.py
@@ -6,7 +6,7 @@ def _callFUT(self, path): from pyramid.traversal import traversal_path return traversal_path(path) def test_path_startswith_endswith(self): self.assertEqual(self._callFUT('/foo/'), (u'foo',)) @@ -41,7 +41,7 @@ decoded = unicode(la, 'utf-8') path = '/'.join([encoded, encoded]) self.assertEqual(self._callFUT(path), (decoded, decoded)) def test_utf16(self): from pyramid.exceptions import URLDecodeError import urllib @@ -626,7 +626,7 @@ root.__name__ = None result = self._callFUT(root) self.assertEqual(result, ('',)) def test_nonroot_default(self): root = DummyContext() root.__parent__ = None @@ -750,7 +750,7 @@ context_url = self._makeOne(two, request) result = context_url() self.assertEqual(result, 'http://example.com:5432/two/') request = DummyRequest({VH_ROOT_KEY:'/one/two'}) context_url = self._makeOne(two, request) result = context_url() @@ -973,8 +973,9 @@ return self._getTargetClass()(environ) def test_no_matchdict(self): environ = {} root = self._makeOne(environ) class DummyRequest: matchdict = None root = self._makeOne(DummyRequest()) self.assertEqual(root.__parent__, None) self.assertEqual(root.__name__, None) @@ -997,13 +998,13 @@ self.context.request = request return result return DummyTraverser class DummyContext(object): __parent__ = None def __init__(self, next=None, name=None): self.next = next self.__name__ = name def __getitem__(self, name): if self.next is None: raise KeyError, name @@ -1018,7 +1019,7 @@ if environ is None: environ = {} self.environ = environ class DummyContextURL: def __init__(self, context, request): pass pyramid/traversal.py
@@ -592,7 +592,7 @@ 'virtual_root':vroot, 'virtual_root_path':vroot_tuple, 'root':root} if i == vroot_idx: if i == vroot_idx: vroot = next ob = next i += 1 @@ -623,7 +623,7 @@ return self.request.root except AttributeError: return find_root(self.context) def __call__(self): """ Generate a URL based on the :term:`lineage` of a :term:`model` object obtained via :term:`traversal`. If any @@ -658,8 +658,9 @@ __parent__ = None __name__ = None def __init__(self, request): matchdict = getattr(request, 'matchdict', {}) matchdict = request.matchdict # provide backwards compatibility for applications which # used routes (at least apps without any custom "context # factory") in BFG 0.9.X and before self.__dict__.update(matchdict) if matchdict is not None: self.__dict__.update(matchdict)