From bda1306749c62ef4f11cfe567ed7d56c8ad94240 Mon Sep 17 00:00:00 2001 From: Michael Merickel <github@m.merickel.org> Date: Mon, 15 Oct 2018 16:56:42 +0200 Subject: [PATCH] Merge pull request #3388 from mmerickel/black --- src/pyramid/viewderivers.py | 175 +++++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 113 insertions(+), 62 deletions(-) diff --git a/src/pyramid/viewderivers.py b/src/pyramid/viewderivers.py index d914a47..fbe0c25 100644 --- a/src/pyramid/viewderivers.py +++ b/src/pyramid/viewderivers.py @@ -1,15 +1,9 @@ import inspect -from zope.interface import ( - implementer, - provider, - ) +from zope.interface import implementer, provider from pyramid.security import NO_PERMISSION_REQUIRED -from pyramid.csrf import ( - check_csrf_origin, - check_csrf_token, -) +from pyramid.csrf import check_csrf_origin, check_csrf_token from pyramid.response import Response from pyramid.interfaces import ( @@ -21,21 +15,13 @@ IResponse, IViewMapper, IViewMapperFactory, - ) - -from pyramid.compat import ( - is_bound_method, - is_unbound_method, - ) - -from pyramid.exceptions import ( - ConfigurationError, - ) -from pyramid.httpexceptions import HTTPForbidden -from pyramid.util import ( - object_description, - takes_one_arg, ) + +from pyramid.compat import is_bound_method, is_unbound_method + +from pyramid.exceptions import ConfigurationError +from pyramid.httpexceptions import HTTPForbidden +from pyramid.util import object_description, takes_one_arg from pyramid.view import render_view_to_response from pyramid import renderers @@ -47,8 +33,10 @@ # custom view mappers might not add __text__ return object_description(view) + def requestonly(view, attr=None): return takes_one_arg(view, attr=attr, argname='request') + @implementer(IViewMapper) @provider(IViewMapperFactory) @@ -58,10 +46,12 @@ def __call__(self, view): if is_unbound_method(view) and self.attr is None: - raise ConfigurationError(( - 'Unbound method calls are not supported, please set the class ' - 'as your `view` and the method as your `attr`' - )) + raise ConfigurationError( + ( + 'Unbound method calls are not supported, please set the ' + 'class as your `view` and the method as your `attr`' + ) + ) if inspect.isclass(view): view = self.map_class(view) @@ -76,7 +66,9 @@ else: mapped_view = self.map_class_native(view) mapped_view.__text__ = 'method %s of %s' % ( - self.attr or '__call__', object_description(view)) + self.attr or '__call__', + object_description(view), + ) return mapped_view def map_nonclass(self, view): @@ -98,11 +90,15 @@ # bound method. if is_bound_method(view): _mapped_view = mapped_view + def mapped_view(context, request): return _mapped_view(context, request) + if self.attr is not None: mapped_view.__text__ = 'attr %s of %s' % ( - self.attr, object_description(view)) + self.attr, + object_description(view), + ) else: mapped_view.__text__ = object_description(view) return mapped_view @@ -110,6 +106,7 @@ def map_class_requestonly(self, view): # its a class that has an __init__ which only accepts request attr = self.attr + def _class_requestonly_view(context, request): inst = view(request) request.__view__ = inst @@ -118,12 +115,14 @@ else: response = getattr(inst, attr)() return response + return _class_requestonly_view def map_class_native(self, view): # its a class that has an __init__ which accepts both context and # request attr = self.attr + def _class_view(context, request): inst = view(context, request) request.__view__ = inst @@ -132,18 +131,21 @@ else: response = getattr(inst, attr)() return response + return _class_view def map_nonclass_requestonly(self, view): # its a function that has a __call__ which accepts only a single # request argument attr = self.attr + def _requestonly_view(context, request): if attr is None: response = view(request) else: response = getattr(view, attr)(request) return response + return _requestonly_view def map_nonclass_attr(self, view): @@ -152,6 +154,7 @@ def _attr_view(context, request): response = getattr(view, self.attr)(context, request) return response + return _attr_view @@ -159,7 +162,9 @@ def inner(view, info): wrapper_view = wrapper(view, info) return preserve_view_attrs(view, wrapper_view) + return inner + def preserve_view_attrs(view, wrapper): if view is None: @@ -185,15 +190,23 @@ # attrs that may not exist on "view", but, if so, must be attached to # "wrapped view" - for attr in ('__permitted__', '__call_permissive__', '__permission__', - '__predicated__', '__predicates__', '__accept__', - '__order__', '__text__'): + for attr in ( + '__permitted__', + '__call_permissive__', + '__permission__', + '__predicated__', + '__predicates__', + '__accept__', + '__order__', + '__text__', + ): try: setattr(wrapper, attr, getattr(view, attr)) except AttributeError: pass return wrapper + def mapped_view(view, info): mapper = info.options.get('mapper') @@ -207,28 +220,36 @@ mapped_view = mapper(**info.options)(view) return mapped_view + mapped_view.options = ('mapper', 'attr') + def owrapped_view(view, info): wrapper_viewname = info.options.get('wrapper') viewname = info.options.get('name') if not wrapper_viewname: return view + def _owrapped_view(context, request): response = view(context, request) request.wrapped_response = response request.wrapped_body = response.body request.wrapped_view = view - wrapped_response = render_view_to_response(context, request, - wrapper_viewname) + wrapped_response = render_view_to_response( + context, request, wrapper_viewname + ) if wrapped_response is None: raise ValueError( 'No wrapper view named %r found when executing view ' - 'named %r' % (wrapper_viewname, viewname)) + 'named %r' % (wrapper_viewname, viewname) + ) return wrapped_response + return _owrapped_view + owrapped_view.options = ('name', 'wrapper') + def http_cached_view(view, info): if info.settings.get('prevent_http_cache', False): @@ -247,26 +268,32 @@ except ValueError: raise ConfigurationError( 'If http_cache parameter is a tuple or list, it must be ' - 'in the form (seconds, options); not %s' % (seconds,)) + 'in the form (seconds, options); not %s' % (seconds,) + ) def wrapper(context, request): response = view(context, request) - prevent_caching = getattr(response.cache_control, 'prevent_auto', - False) + prevent_caching = getattr( + response.cache_control, 'prevent_auto', False + ) if not prevent_caching: response.cache_expires(seconds, **options) return response return wrapper + http_cached_view.options = ('http_cache',) + def secured_view(view, info): for wrapper in (_secured_view, _authdebug_view): view = wraps_view(wrapper)(view, info) return view + secured_view.options = ('permission',) + def _secured_view(view, info): permission = explicit_val = info.options.get('permission') @@ -287,24 +314,30 @@ return view if authn_policy and authz_policy and (permission is not None): + def permitted(context, request): principals = authn_policy.effective_principals(request) return authz_policy.permits(context, principals, permission) + def secured_view(context, request): result = permitted(context, request) if result: return view(context, request) view_name = getattr(view, '__name__', view) msg = getattr( - request, 'authdebug_message', - 'Unauthorized: %s failed permission check' % view_name) + request, + 'authdebug_message', + 'Unauthorized: %s failed permission check' % view_name, + ) raise HTTPForbidden(msg, result=result) + wrapped_view = secured_view wrapped_view.__call_permissive__ = view wrapped_view.__permitted__ = permitted wrapped_view.__permission__ = permission return wrapped_view + def _authdebug_view(view, info): wrapped_view = view @@ -321,6 +354,7 @@ return view if settings and settings.get('debug_authorization', False): + def authdebug_view(context, request): view_name = getattr(request, 'view_name', None) @@ -331,23 +365,28 @@ msg = 'Allowed (no permission registered)' else: principals = authn_policy.effective_principals(request) - msg = str(authz_policy.permits( - context, principals, permission)) + msg = str( + authz_policy.permits(context, principals, permission) + ) else: msg = 'Allowed (no authorization policy in use)' view_name = getattr(request, 'view_name', None) url = getattr(request, 'url', None) - msg = ('debug_authorization of url %s (view name %r against ' - 'context %r): %s' % (url, view_name, context, msg)) + msg = ( + 'debug_authorization of url %s (view name %r against ' + 'context %r): %s' % (url, view_name, context, msg) + ) if logger: logger.debug(msg) if request is not None: request.authdebug_message = msg return view(context, request) + wrapped_view = authdebug_view return wrapped_view + def rendered_view(view, info): # one way or another this wrapper must produce a Response (unless @@ -360,23 +399,29 @@ # a view registration. def viewresult_to_response(context, request): result = view(context, request) - if result.__class__ is Response: # common case + if result.__class__ is Response: # common case response = result else: response = info.registry.queryAdapterOrSelf(result, IResponse) if response is None: if result is None: - append = (' You may have forgotten to return a value ' - 'from the view callable.') + append = ( + ' You may have forgotten to return a value ' + 'from the view callable.' + ) elif isinstance(result, dict): - append = (' You may have forgotten to define a ' - 'renderer in the view configuration.') + append = ( + ' You may have forgotten to define a ' + 'renderer in the view configuration.' + ) else: append = '' - msg = ('Could not convert return value of the view ' - 'callable %s into a response object. ' - 'The value returned was %r.' + append) + msg = ( + 'Could not convert return value of the view ' + 'callable %s into a response object. ' + 'The value returned was %r.' + append + ) raise ValueError(msg % (view_description(view), result)) @@ -389,7 +434,7 @@ def rendered_view(context, request): result = view(context, request) - if result.__class__ is Response: # potential common case + if result.__class__ is Response: # potential common case response = result else: # this must adapt, it can't do a simple interface check @@ -403,7 +448,8 @@ view_renderer = renderers.RendererHelper( name=renderer_name, package=info.package, - registry=info.registry) + registry=info.registry, + ) else: view_renderer = renderer.clone() if '__view__' in attrs: @@ -411,12 +457,15 @@ else: view_inst = getattr(view, '__original_view__', view) response = view_renderer.render_view( - request, result, view_inst, context) + request, result, view_inst, context + ) return response return rendered_view + rendered_view.options = ('renderer',) + def decorated_view(view, info): decorator = info.options.get('decorator') @@ -424,7 +473,9 @@ return view return decorator(view) + decorated_view.options = ('decorator',) + def csrf_view(view, info): explicit_val = info.options.get('require_csrf') @@ -443,29 +494,29 @@ callback = defaults.callback enabled = ( - explicit_val is True or + explicit_val is True + or # fallback to the default val if not explicitly enabled # but only if the view is not an exception view - ( - explicit_val is not False and default_val and - not info.exception_only - ) + (explicit_val is not False and default_val and not info.exception_only) ) # disable if both header and token are disabled enabled = enabled and (token or header) wrapped_view = view if enabled: + def csrf_view(context, request): - if ( - request.method not in safe_methods and - (callback is None or callback(request)) + if request.method not in safe_methods and ( + callback is None or callback(request) ): check_csrf_origin(request, raises=True) check_csrf_token(request, token, header, raises=True) return view(context, request) + wrapped_view = csrf_view return wrapped_view + csrf_view.options = ('require_csrf',) VIEW = 'VIEW' -- Gitblit v1.9.3