1import inspect
2import posixpath
3import operator
4import os
5import warnings
6
7from zope.interface import (
8    Interface,
9    implementedBy,
10    implementer,
11    )
12
13from zope.interface.interfaces import IInterface
14
15from pyramid.interfaces import (
16    IException,
17    IExceptionViewClassifier,
18    IMultiView,
19    IPackageOverrides,
20    IRendererFactory,
21    IRequest,
22    IResponse,
23    IRouteRequest,
24    ISecuredView,
25    IStaticURLInfo,
26    IView,
27    IViewClassifier,
28    IViewDerivers,
29    IViewDeriverInfo,
30    IViewMapperFactory,
31    PHASE1_CONFIG,
32    )
33
34from pyramid import renderers
35
36from pyramid.asset import resolve_asset_spec
37from pyramid.compat import (
38    string_types,
39    urlparse,
40    url_quote,
41    WIN,
42    is_nonstr_iter,
43    )
44
45from pyramid.decorator import reify
46
47from pyramid.exceptions import (
48    ConfigurationError,
49    PredicateMismatch,
50    )
51
52from pyramid.httpexceptions import (
53    HTTPForbidden,
54    HTTPNotFound,
55    default_exceptionresponse_view,
56    )
57
58from pyramid.registry import (
59    predvalseq,
60    Deferred,
61    )
62
63from pyramid.security import NO_PERMISSION_REQUIRED
64from pyramid.static import static_view
65
66from pyramid.url import parse_url_overrides
67
68from pyramid.view import AppendSlashNotFoundViewFactory
69
70import pyramid.util
71from pyramid.util import (
72    viewdefaults,
73    action_method,
74    TopologicalSorter,
75    )
76
77import pyramid.config.predicates
78import pyramid.viewderivers
79
80from pyramid.viewderivers import (
81    INGRESS,
82    VIEW,
83    preserve_view_attrs,
84    view_description,
85    requestonly,
86    DefaultViewMapper,
87    wraps_view,
88)
89
90from pyramid.config.util import (
91    DEFAULT_PHASH,
92    MAX_ORDER,
93    as_sorted_tuple,
94    )
95
96urljoin = urlparse.urljoin
97url_parse = urlparse.urlparse
98
99DefaultViewMapper = DefaultViewMapper # bw-compat
100preserve_view_attrs = preserve_view_attrs # bw-compat
101requestonly = requestonly # bw-compat
102view_description = view_description # bw-compat
103
104@implementer(IMultiView)
105class MultiView(object):
106
107    def __init__(self, name):
108        self.name = name
109        self.media_views = {}
110        self.views = []
111        self.accepts = []
112
113    def __discriminator__(self, context, request):
114        # used by introspection systems like so:
115        # view = adapters.lookup(....)
116        # view.__discriminator__(context, request) -> view's discriminator
117        # so that superdynamic systems can feed the discriminator to
118        # the introspection system to get info about it
119        view = self.match(context, request)
120        return view.__discriminator__(context, request)
121
122    def add(self, view, order, accept=None, phash=None):
123        if phash is not None:
124            for i, (s, v, h) in enumerate(list(self.views)):
125                if phash == h:
126                    self.views[i] = (order, view, phash)
127                    return
128
129        if accept is None or '*' in accept:
130            self.views.append((order, view, phash))
131            self.views.sort(key=operator.itemgetter(0))
132        else:
133            subset = self.media_views.setdefault(accept, [])
134            for i, (s, v, h) in enumerate(list(subset)):
135                if phash == h:
136                    subset[i] = (order, view, phash)
137                    return
138            else:
139                subset.append((order, view, phash))
140                subset.sort(key=operator.itemgetter(0))
141            accepts = set(self.accepts)
142            accepts.add(accept)
143            self.accepts = list(accepts) # dedupe
144
145    def get_views(self, request):
146        if self.accepts and hasattr(request, 'accept'):
147            accepts = self.accepts[:]
148            views = []
149            while accepts:
150                match = request.accept.best_match(accepts)
151                if match is None:
152                    break
153                subset = self.media_views[match]
154                views.extend(subset)
155                accepts.remove(match)
156            views.extend(self.views)
157            return views
158        return self.views
159
160    def match(self, context, request):
161        for order, view, phash in self.get_views(request):
162            if not hasattr(view, '__predicated__'):
163                return view
164            if view.__predicated__(context, request):
165                return view
166        raise PredicateMismatch(self.name)
167
168    def __permitted__(self, context, request):
169        view = self.match(context, request)
170        if hasattr(view, '__permitted__'):
171            return view.__permitted__(context, request)
172        return True
173
174    def __call_permissive__(self, context, request):
175        view = self.match(context, request)
176        view = getattr(view, '__call_permissive__', view)
177        return view(context, request)
178
179    def __call__(self, context, request):
180        for order, view, phash in self.get_views(request):
181            try:
182                return view(context, request)
183            except PredicateMismatch:
184                continue
185        raise PredicateMismatch(self.name)
186
187class ViewsConfiguratorMixin(object):
188    @viewdefaults
189    @action_method
190    def add_view(
191        self,
192        view=None,
193        name="",
194        for_=None,
195        permission=None,
196        request_type=None,
197        route_name=None,
198        request_method=None,
199        request_param=None,
200        containment=None,
201        attr=None,
202        renderer=None,
203        wrapper=None,
204        xhr=None,
205        accept=None,
206        header=None,
207        path_info=None,
208        custom_predicates=(),
209        context=None,
210        decorator=None,
211        mapper=None,
212        http_cache=None,
213        match_param=None,
214        check_csrf=None,
215        require_csrf=None,
216        **view_options):
217        """ Add a :term:`view configuration` to the current
218        configuration state.  Arguments to ``add_view`` are broken
219        down below into *predicate* arguments and *non-predicate*
220        arguments.  Predicate arguments narrow the circumstances in
221        which the view callable will be invoked when a request is
222        presented to :app:`Pyramid`; non-predicate arguments are
223        informational.
224
225        Non-Predicate Arguments
226
227        view
228
229          A :term:`view callable` or a :term:`dotted Python name`
230          which refers to a view callable.  This argument is required
231          unless a ``renderer`` argument also exists.  If a
232          ``renderer`` argument is passed, and a ``view`` argument is
233          not provided, the view callable defaults to a callable that
234          returns an empty dictionary (see
235          :ref:`views_which_use_a_renderer`).
236
237        permission
238
239          A :term:`permission` that the user must possess in order to invoke
240          the :term:`view callable`.  See :ref:`view_security_section` for
241          more information about view security and permissions.  This is
242          often a string like ``view`` or ``edit``.
243
244          If ``permission`` is omitted, a *default* permission may be used
245          for this view registration if one was named as the
246          :class:`pyramid.config.Configurator` constructor's
247          ``default_permission`` argument, or if
248          :meth:`pyramid.config.Configurator.set_default_permission` was used
249          prior to this view registration.  Pass the value
250          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission
251          argument to explicitly indicate that the view should always be
252          executable by entirely anonymous users, regardless of the default
253          permission, bypassing any :term:`authorization policy` that may be
254          in effect.
255
256        attr
257
258          This knob is most useful when the view definition is a class.
259
260          The view machinery defaults to using the ``__call__`` method
261          of the :term:`view callable` (or the function itself, if the
262          view callable is a function) to obtain a response.  The
263          ``attr`` value allows you to vary the method attribute used
264          to obtain the response.  For example, if your view was a
265          class, and the class has a method named ``index`` and you
266          wanted to use this method instead of the class' ``__call__``
267          method to return the response, you'd say ``attr="index"`` in the
268          view configuration for the view.
269
270        renderer
271
272          This is either a single string term (e.g. ``json``) or a
273          string implying a path or :term:`asset specification`
274          (e.g. ``templates/views.pt``) naming a :term:`renderer`
275          implementation.  If the ``renderer`` value does not contain
276          a dot ``.``, the specified string will be used to look up a
277          renderer implementation, and that renderer implementation
278          will be used to construct a response from the view return
279          value.  If the ``renderer`` value contains a dot (``.``),
280          the specified term will be treated as a path, and the
281          filename extension of the last element in the path will be
282          used to look up the renderer implementation, which will be
283          passed the full path.  The renderer implementation will be
284          used to construct a :term:`response` from the view return
285          value.
286
287          Note that if the view itself returns a :term:`response` (see
288          :ref:`the_response`), the specified renderer implementation
289          is never called.
290
291          When the renderer is a path, although a path is usually just
292          a simple relative pathname (e.g. ``templates/foo.pt``,
293          implying that a template named "foo.pt" is in the
294          "templates" directory relative to the directory of the
295          current :term:`package` of the Configurator), a path can be
296          absolute, starting with a slash on UNIX or a drive letter
297          prefix on Windows.  The path can alternately be a
298          :term:`asset specification` in the form
299          ``some.dotted.package_name:relative/path``, making it
300          possible to address template assets which live in a
301          separate package.
302
303          The ``renderer`` attribute is optional.  If it is not
304          defined, the "null" renderer is assumed (no rendering is
305          performed and the value is passed back to the upstream
306          :app:`Pyramid` machinery unmodified).
307
308        http_cache
309
310          .. versionadded:: 1.1
311
312          When you supply an ``http_cache`` value to a view configuration,
313          the ``Expires`` and ``Cache-Control`` headers of a response
314          generated by the associated view callable are modified.  The value
315          for ``http_cache`` may be one of the following:
316
317          - A nonzero integer.  If it's a nonzero integer, it's treated as a
318            number of seconds.  This number of seconds will be used to
319            compute the ``Expires`` header and the ``Cache-Control:
320            max-age`` parameter of responses to requests which call this view.
321            For example: ``http_cache=3600`` instructs the requesting browser
322            to 'cache this response for an hour, please'.
323
324          - A ``datetime.timedelta`` instance.  If it's a
325            ``datetime.timedelta`` instance, it will be converted into a
326            number of seconds, and that number of seconds will be used to
327            compute the ``Expires`` header and the ``Cache-Control:
328            max-age`` parameter of responses to requests which call this view.
329            For example: ``http_cache=datetime.timedelta(days=1)`` instructs
330            the requesting browser to 'cache this response for a day, please'.
331
332          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and
333            ``Expires`` headers present in all responses from this view will
334            be composed such that client browser cache (and any intermediate
335            caches) are instructed to never cache the response.
336
337          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,
338            {'public':True})``), the first value in the tuple may be a
339            nonzero integer or a ``datetime.timedelta`` instance; in either
340            case this value will be used as the number of seconds to cache
341            the response.  The second value in the tuple must be a
342            dictionary.  The values present in the dictionary will be used as
343            input to the ``Cache-Control`` response header.  For example:
344            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,
345            and add ``public`` to the Cache-Control header of the response'.
346            All keys and values supported by the
347            ``webob.cachecontrol.CacheControl`` interface may be added to the
348            dictionary.  Supplying ``{'public':True}`` is equivalent to
349            calling ``response.cache_control.public = True``.
350
351          Providing a non-tuple value as ``http_cache`` is equivalent to
352          calling ``response.cache_expires(value)`` within your view's body.
353
354          Providing a two-tuple value as ``http_cache`` is equivalent to
355          calling ``response.cache_expires(value[0], **value[1])`` within your
356          view's body.
357
358          If you wish to avoid influencing, the ``Expires`` header, and
359          instead wish to only influence ``Cache-Control`` headers, pass a
360          tuple as ``http_cache`` with the first element of ``None``, e.g.:
361          ``(None, {'public':True})``.
362
363          If you wish to prevent a view that uses ``http_cache`` in its
364          configuration from having its caching response headers changed by
365          this machinery, set ``response.cache_control.prevent_auto = True``
366          before returning the response from the view.  This effectively
367          disables any HTTP caching done by ``http_cache`` for that response.
368
369        require_csrf
370
371          .. versionadded:: 1.7
372
373          A boolean option or ``None``. Default: ``None``.
374
375          If this option is set to ``True`` then CSRF checks will be enabled
376          for requests to this view. The required token or header default to
377          ``csrf_token`` and ``X-CSRF-Token``, respectively.
378
379          CSRF checks only affect "unsafe" methods as defined by RFC2616. By
380          default, these methods are anything except
381          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.
382
383          The defaults here may be overridden by
384          :meth:`pyramid.config.Configurator.set_default_csrf_options`.
385
386          This feature requires a configured :term:`session factory`.
387
388          If this option is set to ``False`` then CSRF checks will be disabled
389          regardless of the default ``require_csrf`` setting passed
390          to ``set_default_csrf_options``.
391
392          See :ref:`auto_csrf_checking` for more information.
393
394        wrapper
395
396          The :term:`view name` of a different :term:`view
397          configuration` which will receive the response body of this
398          view as the ``request.wrapped_body`` attribute of its own
399          :term:`request`, and the :term:`response` returned by this
400          view as the ``request.wrapped_response`` attribute of its
401          own request.  Using a wrapper makes it possible to "chain"
402          views together to form a composite response.  The response
403          of the outermost wrapper view will be returned to the user.
404          The wrapper view will be found as any view is found: see
405          :ref:`view_lookup`.  The "best" wrapper view will be found
406          based on the lookup ordering: "under the hood" this wrapper
407          view is looked up via
408          ``pyramid.view.render_view_to_response(context, request,
409          'wrapper_viewname')``. The context and request of a wrapper
410          view is the same context and request of the inner view.  If
411          this attribute is unspecified, no view wrapping is done.
412
413        decorator
414
415          A :term:`dotted Python name` to function (or the function itself,
416          or an iterable of the aforementioned) which will be used to
417          decorate the registered :term:`view callable`.  The decorator
418          function(s) will be called with the view callable as a single
419          argument.  The view callable it is passed will accept
420          ``(context, request)``.  The decorator(s) must return a
421          replacement view callable which also accepts ``(context,
422          request)``.
423
424          If decorator is an iterable, the callables will be combined and
425          used in the order provided as a decorator.
426          For example::
427
428            @view_config(...,
429                decorator=(decorator2,
430                           decorator1))
431            def myview(request):
432                ....
433
434          Is similar to doing::
435
436            @view_config(...)
437            @decorator2
438            @decorator1
439            def myview(request):
440                ...
441
442          Except with the existing benefits of ``decorator=`` (having a common
443          decorator syntax for all view calling conventions and not having to
444          think about preserving function attributes such as ``__name__`` and
445          ``__module__`` within decorator logic).
446
447          All view callables in the decorator chain must return a response
448          object implementing :class:`pyramid.interfaces.IResponse` or raise
449          an exception:
450
451          .. code-block:: python
452
453             def log_timer(wrapped):
454                 def wrapper(context, request):
455                     start = time.time()
456                     response = wrapped(context, request)
457                     duration = time.time() - start
458                     response.headers['X-View-Time'] = '%.3f' % (duration,)
459                     log.info('view took %.3f seconds', duration)
460                     return response
461                 return wrapper
462
463          .. versionchanged:: 1.4a4
464             Passing an iterable.
465
466        mapper
467
468          A Python object or :term:`dotted Python name` which refers to a
469          :term:`view mapper`, or ``None``.  By default it is ``None``, which
470          indicates that the view should use the default view mapper.  This
471          plug-point is useful for Pyramid extension developers, but it's not
472          very useful for 'civilians' who are just developing stock Pyramid
473          applications. Pay no attention to the man behind the curtain.
474
475        accept
476
477          This value represents a match query for one or more mimetypes in the
478          ``Accept`` HTTP request header.  If this value is specified, it must
479          be in one of the following forms: a mimetype match token in the form
480          ``text/plain``, a wildcard mimetype match token in the form
481          ``text/*`` or a match-all wildcard mimetype match token in the form
482          ``*/*``.  If any of the forms matches the ``Accept`` header of the
483          request, or if the ``Accept`` header isn't set at all in the request,
484          this will match the current view. If this does not match the
485          ``Accept`` header of the request, view matching continues.
486
487        Predicate Arguments
488
489        name
490
491          The :term:`view name`.  Read :ref:`traversal_chapter` to
492          understand the concept of a view name.
493
494        context
495
496          An object or a :term:`dotted Python name` referring to an
497          interface or class object that the :term:`context` must be
498          an instance of, *or* the :term:`interface` that the
499          :term:`context` must provide in order for this view to be
500          found and called.  This predicate is true when the
501          :term:`context` is an instance of the represented class or
502          if the :term:`context` provides the represented interface;
503          it is otherwise false.  This argument may also be provided
504          to ``add_view`` as ``for_`` (an older, still-supported
505          spelling).
506
507        route_name
508
509          This value must match the ``name`` of a :term:`route
510          configuration` declaration (see :ref:`urldispatch_chapter`)
511          that must match before this view will be called.
512
513        request_type
514
515          This value should be an :term:`interface` that the
516          :term:`request` must provide in order for this view to be
517          found and called.  This value exists only for backwards
518          compatibility purposes.
519
520        request_method
521
522          This value can be either a string (such as ``"GET"``, ``"POST"``,
523          ``"PUT"``, ``"DELETE"``, ``"HEAD"`` or ``"OPTIONS"``) representing
524          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of
525          these strings.  A view declaration with this argument ensures that
526          the view will only be called when the ``method`` attribute of the
527          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches
528          a supplied value.  Note that use of ``GET`` also implies that the
529          view will respond to ``HEAD`` as of Pyramid 1.4.
530
531          .. versionchanged:: 1.2
532             The ability to pass a tuple of items as ``request_method``.
533             Previous versions allowed only a string.
534
535        request_param
536
537          This value can be any string or any sequence of strings.  A view
538          declaration with this argument ensures that the view will only be
539          called when the :term:`request` has a key in the ``request.params``
540          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a
541          name which matches the supplied value (if the value is a string)
542          or values (if the value is a tuple).  If any value
543          supplied has a ``=`` sign in it,
544          e.g. ``request_param="foo=123"``, then the key (``foo``)
545          must both exist in the ``request.params`` dictionary, *and*
546          the value must match the right hand side of the expression
547          (``123``) for the view to "match" the current request.
548
549        match_param
550
551          .. versionadded:: 1.2
552
553          This value can be a string of the format "key=value" or a tuple
554          containing one or more of these strings.
555
556          A view declaration with this argument ensures that the view will
557          only be called when the :term:`request` has key/value pairs in its
558          :term:`matchdict` that equal those supplied in the predicate.
559          e.g. ``match_param="action=edit"`` would require the ``action``
560          parameter in the :term:`matchdict` match the right hand side of
561          the expression (``edit``) for the view to "match" the current
562          request.
563
564          If the ``match_param`` is a tuple, every key/value pair must match
565          for the predicate to pass.
566
567        containment
568
569          This value should be a Python class or :term:`interface` (or a
570          :term:`dotted Python name`) that an object in the
571          :term:`lineage` of the context must provide in order for this view
572          to be found and called.  The nodes in your object graph must be
573          "location-aware" to use this feature.  See
574          :ref:`location_aware` for more information about
575          location-awareness.
576
577        xhr
578
579          This value should be either ``True`` or ``False``.  If this
580          value is specified and is ``True``, the :term:`request`
581          must possess an ``HTTP_X_REQUESTED_WITH`` (aka
582          ``X-Requested-With``) header that has the value
583          ``XMLHttpRequest`` for this view to be found and called.
584          This is useful for detecting AJAX requests issued from
585          jQuery, Prototype and other Javascript libraries.
586
587        header
588
589          This value represents an HTTP header name or a header
590          name/value pair.  If the value contains a ``:`` (colon), it
591          will be considered a name/value pair
592          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The
593          value portion should be a regular expression.  If the value
594          does not contain a colon, the entire value will be
595          considered to be the header name
596          (e.g. ``If-Modified-Since``).  If the value evaluates to a
597          header name only without a value, the header specified by
598          the name must be present in the request for this predicate
599          to be true.  If the value evaluates to a header name/value
600          pair, the header specified by the name must be present in
601          the request *and* the regular expression specified as the
602          value must match the header value.  Whether or not the value
603          represents a header name or a header name/value pair, the
604          case of the header name is not significant.
605
606        path_info
607
608          This value represents a regular expression pattern that will
609          be tested against the ``PATH_INFO`` WSGI environment
610          variable.  If the regex matches, this predicate will be
611          ``True``.
612
613        check_csrf
614
615          .. deprecated:: 1.7
616             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`
617             instead to have :class:`pyramid.exceptions.BadCSRFToken`
618             exceptions raised.
619
620          If specified, this value should be one of ``None``, ``True``,
621          ``False``, or a string representing the 'check name'.  If the value
622          is ``True`` or a string, CSRF checking will be performed.  If the
623          value is ``False`` or ``None``, CSRF checking will not be performed.
624
625          If the value provided is a string, that string will be used as the
626          'check name'.  If the value provided is ``True``, ``csrf_token`` will
627          be used as the check name.
628
629          If CSRF checking is performed, the checked value will be the value
630          of ``request.params[check_name]``.  This value will be compared
631          against the value of ``request.session.get_csrf_token()``, and the
632          check will pass if these two values are the same.  If the check
633          passes, the associated view will be permitted to execute.  If the
634          check fails, the associated view will not be permitted to execute.
635
636          Note that using this feature requires a :term:`session factory` to
637          have been configured.
638
639          .. versionadded:: 1.4a2
640
641        physical_path
642
643          If specified, this value should be a string or a tuple representing
644          the :term:`physical path` of the context found via traversal for this
645          predicate to match as true.  For example: ``physical_path='/'`` or
646          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.
647          This is not a path prefix match or a regex, it's a whole-path match.
648          It's useful when you want to always potentially show a view when some
649          object is traversed to, but you can't be sure about what kind of
650          object it will be, so you can't use the ``context`` predicate.  The
651          individual path elements inbetween slash characters or in tuple
652          elements should be the Unicode representation of the name of the
653          resource and should not be encoded in any way.
654
655          .. versionadded:: 1.4a3
656
657        effective_principals
658
659          If specified, this value should be a :term:`principal` identifier or
660          a sequence of principal identifiers.  If the
661          :attr:`pyramid.request.Request.effective_principals` property
662          indicates that every principal named in the argument list is present
663          in the current request, this predicate will return True; otherwise it
664          will return False.  For example:
665          ``effective_principals=pyramid.security.Authenticated`` or
666          ``effective_principals=('fred', 'group:admins')``.
667
668          .. versionadded:: 1.4a4
669
670        custom_predicates
671
672            .. deprecated:: 1.5
673                This value should be a sequence of references to custom
674                predicate callables.  Use custom predicates when no set of
675                predefined predicates do what you need.  Custom predicates
676                can be combined with predefined predicates as necessary.
677                Each custom predicate callable should accept two arguments:
678                ``context`` and ``request`` and should return either
679                ``True`` or ``False`` after doing arbitrary evaluation of
680                the context and/or the request.  The ``predicates`` argument
681                to this method and the ability to register third-party view
682                predicates via
683                :meth:`pyramid.config.Configurator.add_view_predicate`
684                obsoletes this argument, but it is kept around for backwards
685                compatibility.
686
687        view_options:
688
689          Pass a key/value pair here to use a third-party predicate or set a
690          value for a view deriver. See
691          :meth:`pyramid.config.Configurator.add_view_predicate` and
692          :meth:`pyramid.config.Configurator.add_view_deriver`. See
693          :ref:`view_and_route_predicates` for more information about
694          third-party predicates and :ref:`view_derivers` for information
695          about view derivers.
696
697          .. versionadded: 1.4a1
698
699          .. versionchanged: 1.7
700
701             Support setting view deriver options. Previously, only custom
702             view predicate values could be supplied.
703
704        """
705        if custom_predicates:
706            warnings.warn(
707                ('The "custom_predicates" argument to Configurator.add_view '
708                 'is deprecated as of Pyramid 1.5.  Use '
709                 '"config.add_view_predicate" and use the registered '
710                 'view predicate as a predicate argument to add_view instead. '
711                 'See "Adding A Third Party View, Route, or Subscriber '
712                 'Predicate" in the "Hooks" chapter of the documentation '
713                 'for more information.'),
714                DeprecationWarning,
715                stacklevel=4,
716                )
717
718        if check_csrf is not None:
719            warnings.warn(
720                ('The "check_csrf" argument to Configurator.add_view is '
721                 'deprecated as of Pyramid 1.7. Use the "require_csrf" option '
722                 'instead or see "Checking CSRF Tokens Automatically" in the '
723                 '"Sessions" chapter of the documentation for more '
724                 'information.'),
725                DeprecationWarning,
726                stacklevel=4,
727                )
728
729        view = self.maybe_dotted(view)
730        context = self.maybe_dotted(context)
731        for_ = self.maybe_dotted(for_)
732        containment = self.maybe_dotted(containment)
733        mapper = self.maybe_dotted(mapper)
734
735        def combine(*decorators):
736            def decorated(view_callable):
737                # reversed() allows a more natural ordering in the api
738                for decorator in reversed(decorators):
739                    view_callable = decorator(view_callable)
740                return view_callable
741            return decorated
742
743        if is_nonstr_iter(decorator):
744            decorator = combine(*map(self.maybe_dotted, decorator))
745        else:
746            decorator = self.maybe_dotted(decorator)
747
748        if not view:
749            if renderer:
750                def view(context, request):
751                    return {}
752            else:
753                raise ConfigurationError('"view" was not specified and '
754                                         'no "renderer" specified')
755
756        if request_type is not None:
757            request_type = self.maybe_dotted(request_type)
758            if not IInterface.providedBy(request_type):
759                raise ConfigurationError(
760                    'request_type must be an interface, not %s' % request_type)
761
762        if context is None:
763            context = for_
764
765        r_context = context
766        if r_context is None:
767            r_context = Interface
768        if not IInterface.providedBy(r_context):
769            r_context = implementedBy(r_context)
770
771        if isinstance(renderer, string_types):
772            renderer = renderers.RendererHelper(
773                name=renderer, package=self.package,
774                registry=self.registry)
775
776        if accept is not None:
777            accept = accept.lower()
778
779        introspectables = []
780        ovals = view_options.copy()
781        ovals.update(dict(
782            xhr=xhr,
783            request_method=request_method,
784            path_info=path_info,
785            request_param=request_param,
786            header=header,
787            accept=accept,
788            containment=containment,
789            request_type=request_type,
790            match_param=match_param,
791            check_csrf=check_csrf,
792            custom=predvalseq(custom_predicates),
793        ))
794
795        def discrim_func():
796            # We need to defer the discriminator until we know what the phash
797            # is.  It can't be computed any sooner because thirdparty
798            # predicates/view derivers may not yet exist when add_view is
799            # called.
800            valid_predicates = predlist.names()
801            pvals = {}
802            dvals = {}
803
804            for (k, v) in ovals.items():
805                if k in valid_predicates:
806                    pvals[k] = v
807                else:
808                    dvals[k] = v
809
810            self._check_view_options(**dvals)
811
812            order, preds, phash = predlist.make(self, **pvals)
813
814            view_intr.update({
815                'phash': phash,
816                'order': order,
817                'predicates': preds,
818                })
819            return ('view', context, name, route_name, phash)
820
821        discriminator = Deferred(discrim_func)
822
823        if inspect.isclass(view) and attr:
824            view_desc = 'method %r of %s' % (
825                attr, self.object_description(view))
826        else:
827            view_desc = self.object_description(view)
828
829        tmpl_intr = None
830
831        view_intr = self.introspectable('views',
832                                        discriminator,
833                                        view_desc,
834                                        'view')
835        view_intr.update(dict(
836            name=name,
837            context=context,
838            containment=containment,
839            request_param=request_param,
840            request_methods=request_method,
841            route_name=route_name,
842            attr=attr,
843            xhr=xhr,
844            accept=accept,
845            header=header,
846            path_info=path_info,
847            match_param=match_param,
848            check_csrf=check_csrf,
849            http_cache=http_cache,
850            require_csrf=require_csrf,
851            callable=view,
852            mapper=mapper,
853            decorator=decorator,
854        ))
855        view_intr.update(view_options)
856        introspectables.append(view_intr)
857        predlist = self.get_predlist('view')
858
859        def register(permission=permission, renderer=renderer):
860            request_iface = IRequest
861            if route_name is not None:
862                request_iface = self.registry.queryUtility(IRouteRequest,
863                                                           name=route_name)
864                if request_iface is None:
865                    # route configuration should have already happened in
866                    # phase 2
867                    raise ConfigurationError(
868                        'No route named %s found for view registration' %
869                        route_name)
870
871            if renderer is None:
872                # use default renderer if one exists (reg'd in phase 1)
873                if self.registry.queryUtility(IRendererFactory) is not None:
874                    renderer = renderers.RendererHelper(
875                        name=None,
876                        package=self.package,
877                        registry=self.registry
878                        )
879
880            # added by discrim_func above during conflict resolving
881            preds = view_intr['predicates']
882            order = view_intr['order']
883            phash = view_intr['phash']
884
885            # __no_permission_required__ handled by _secure_view
886            derived_view = self._derive_view(
887                view,
888                permission=permission,
889                predicates=preds,
890                attr=attr,
891                context=context,
892                renderer=renderer,
893                wrapper_viewname=wrapper,
894                viewname=name,
895                accept=accept,
896                order=order,
897                phash=phash,
898                decorator=decorator,
899                mapper=mapper,
900                http_cache=http_cache,
901                require_csrf=require_csrf,
902                extra_options=ovals,
903            )
904            derived_view.__discriminator__ = lambda *arg: discriminator
905            # __discriminator__ is used by superdynamic systems
906            # that require it for introspection after manual view lookup;
907            # see also MultiView.__discriminator__
908            view_intr['derived_callable'] = derived_view
909
910            registered = self.registry.adapters.registered
911
912            # A multiviews is a set of views which are registered for
913            # exactly the same context type/request type/name triad.  Each
914            # consituent view in a multiview differs only by the
915            # predicates which it possesses.
916
917            # To find a previously registered view for a context
918            # type/request type/name triad, we need to use the
919            # ``registered`` method of the adapter registry rather than
920            # ``lookup``.  ``registered`` ignores interface inheritance
921            # for the required and provided arguments, returning only a
922            # view registered previously with the *exact* triad we pass
923            # in.
924
925            # We need to do this three times, because we use three
926            # different interfaces as the ``provided`` interface while
927            # doing registrations, and ``registered`` performs exact
928            # matches on all the arguments it receives.
929
930            old_view = None
931
932            for view_type in (IView, ISecuredView, IMultiView):
933                old_view = registered((IViewClassifier, request_iface,
934                                       r_context), view_type, name)
935                if old_view is not None:
936                    break
937
938            isexc = isexception(context)
939
940            def regclosure():
941                if hasattr(derived_view, '__call_permissive__'):
942                    view_iface = ISecuredView
943                else:
944                    view_iface = IView
945                self.registry.registerAdapter(
946                    derived_view,
947                    (IViewClassifier, request_iface, context), view_iface, name
948                    )
949                if isexc:
950                    self.registry.registerAdapter(
951                        derived_view,
952                        (IExceptionViewClassifier, request_iface, context),
953                        view_iface, name)
954
955            is_multiview = IMultiView.providedBy(old_view)
956            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)
957
958            if old_view is None:
959                # - No component was yet registered for any of our I*View
960                #   interfaces exactly; this is the first view for this
961                #   triad.
962                regclosure()
963
964            elif (not is_multiview) and (old_phash == phash):
965                # - A single view component was previously registered with
966                #   the same predicate hash as this view; this registration
967                #   is therefore an override.
968                regclosure()
969
970            else:
971                # - A view or multiview was already registered for this
972                #   triad, and the new view is not an override.
973
974                # XXX we could try to be more efficient here and register
975                # a non-secured view for a multiview if none of the
976                # multiview's consituent views have a permission
977                # associated with them, but this code is getting pretty
978                # rough already
979                if is_multiview:
980                    multiview = old_view
981                else:
982                    multiview = MultiView(name)
983                    old_accept = getattr(old_view, '__accept__', None)
984                    old_order = getattr(old_view, '__order__', MAX_ORDER)
985                    multiview.add(old_view, old_order, old_accept, old_phash)
986                multiview.add(derived_view, order, accept, phash)
987                for view_type in (IView, ISecuredView):
988                    # unregister any existing views
989                    self.registry.adapters.unregister(
990                        (IViewClassifier, request_iface, r_context),
991                        view_type, name=name)
992                    if isexc:
993                        self.registry.adapters.unregister(
994                            (IExceptionViewClassifier, request_iface,
995                             r_context), view_type, name=name)
996                self.registry.registerAdapter(
997                    multiview,
998                    (IViewClassifier, request_iface, context),
999                    IMultiView, name=name)
1000                if isexc:
1001                    self.registry.registerAdapter(
1002                        multiview,
1003                        (IExceptionViewClassifier, request_iface, context),
1004                        IMultiView, name=name)
1005
1006            self.registry._clear_view_lookup_cache()
1007            renderer_type = getattr(renderer, 'type', None) # gard against None
1008            intrspc = self.introspector
1009            if (
1010                renderer_type is not None and
1011                tmpl_intr is not None and
1012                intrspc is not None and
1013                intrspc.get('renderer factories', renderer_type) is not None
1014                ):
1015                # allow failure of registered template factories to be deferred
1016                # until view execution, like other bad renderer factories; if
1017                # we tried to relate this to an existing renderer factory
1018                # without checking if it the factory actually existed, we'd end
1019                # up with a KeyError at startup time, which is inconsistent
1020                # with how other bad renderer registrations behave (they throw
1021                # a ValueError at view execution time)
1022                tmpl_intr.relate('renderer factories', renderer.type)
1023
1024        if mapper:
1025            mapper_intr = self.introspectable(
1026                'view mappers',
1027                discriminator,
1028                'view mapper for %s' % view_desc,
1029                'view mapper'
1030                )
1031            mapper_intr['mapper'] = mapper
1032            mapper_intr.relate('views', discriminator)
1033            introspectables.append(mapper_intr)
1034        if route_name:
1035            view_intr.relate('routes', route_name) # see add_route
1036        if renderer is not None and renderer.name and '.' in renderer.name:
1037            # the renderer is a template
1038            tmpl_intr = self.introspectable(
1039                'templates',
1040                discriminator,
1041                renderer.name,
1042                'template'
1043                )
1044            tmpl_intr.relate('views', discriminator)
1045            tmpl_intr['name'] = renderer.name
1046            tmpl_intr['type'] = renderer.type
1047            tmpl_intr['renderer'] = renderer
1048            introspectables.append(tmpl_intr)
1049        if permission is not None:
1050            # if a permission exists, register a permission introspectable
1051            perm_intr = self.introspectable(
1052                'permissions',
1053                permission,
1054                permission,
1055                'permission'
1056                )
1057            perm_intr['value'] = permission
1058            perm_intr.relate('views', discriminator)
1059            introspectables.append(perm_intr)
1060        self.action(discriminator, register, introspectables=introspectables)
1061
1062    def _check_view_options(self, **kw):
1063        # we only need to validate deriver options because the predicates
1064        # were checked by the predlist
1065        derivers = self.registry.getUtility(IViewDerivers)
1066        for deriver in derivers.values():
1067            for opt in getattr(deriver, 'options', []):
1068                kw.pop(opt, None)
1069        if kw:
1070            raise ConfigurationError('Unknown view options: %s' % (kw,))
1071
1072    def _apply_view_derivers(self, info):
1073        d = pyramid.viewderivers
1074
1075        # These derivers are not really derivers and so have fixed order
1076        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),
1077                          ('predicated_view', d.predicated_view)]
1078
1079        view = info.original_view
1080        derivers = self.registry.getUtility(IViewDerivers)
1081        for name, deriver in reversed(outer_derivers + derivers.sorted()):
1082            view = wraps_view(deriver)(view, info)
1083        return view
1084
1085    @action_method
1086    def add_view_predicate(self, name, factory, weighs_more_than=None,
1087                           weighs_less_than=None):
1088        """
1089        .. versionadded:: 1.4
1090
1091        Adds a view predicate factory.  The associated view predicate can
1092        later be named as a keyword argument to
1093        :meth:`pyramid.config.Configurator.add_view` in the
1094        ``predicates`` anonyous keyword argument dictionary.
1095
1096        ``name`` should be the name of the predicate.  It must be a valid
1097        Python identifier (it will be used as a keyword argument to
1098        ``add_view`` by others).
1099
1100        ``factory`` should be a :term:`predicate factory` or :term:`dotted
1101        Python name` which refers to a predicate factory.
1102
1103        See :ref:`view_and_route_predicates` for more information.
1104        """
1105        self._add_predicate(
1106            'view',
1107            name,
1108            factory,
1109            weighs_more_than=weighs_more_than,
1110            weighs_less_than=weighs_less_than
1111            )
1112
1113    def add_default_view_predicates(self):
1114        p = pyramid.config.predicates
1115        for (name, factory) in (
1116            ('xhr', p.XHRPredicate),
1117            ('request_method', p.RequestMethodPredicate),
1118            ('path_info', p.PathInfoPredicate),
1119            ('request_param', p.RequestParamPredicate),
1120            ('header', p.HeaderPredicate),
1121            ('accept', p.AcceptPredicate),
1122            ('containment', p.ContainmentPredicate),
1123            ('request_type', p.RequestTypePredicate),
1124            ('match_param', p.MatchParamPredicate),
1125            ('check_csrf', p.CheckCSRFTokenPredicate),
1126            ('physical_path', p.PhysicalPathPredicate),
1127            ('effective_principals', p.EffectivePrincipalsPredicate),
1128            ('custom', p.CustomPredicate),
1129            ):
1130            self.add_view_predicate(name, factory)
1131
1132    @action_method
1133    def add_view_deriver(self, deriver, name=None, under=None, over=None):
1134        """
1135        .. versionadded:: 1.7
1136
1137        Add a :term:`view deriver` to the view pipeline. View derivers are
1138        a feature used by extension authors to wrap views in custom code
1139        controllable by view-specific options.
1140
1141        ``deriver`` should be a callable conforming to the
1142        :class:`pyramid.interfaces.IViewDeriver` interface.
1143
1144        ``name`` should be the name of the view deriver.  There are no
1145        restrictions on the name of a view deriver. If left unspecified, the
1146        name will be constructed from the name of the ``deriver``.
1147
1148        The ``under`` and ``over`` options can be used to control the ordering
1149        of view derivers by providing hints about where in the view pipeline
1150        the deriver is used. Each option may be a string or a list of strings.
1151        At least one view deriver in each, the over and under directions, must
1152        exist to fully satisfy the constraints.
1153
1154        ``under`` means closer to the user-defined :term:`view callable`,
1155        and ``over`` means closer to view pipeline ingress.
1156
1157        The default value for ``over`` is ``rendered_view`` and ``under`` is
1158        ``decorated_view``. This places the deriver somewhere between the two
1159        in the view pipeline. If the deriver should be placed elsewhere in the
1160        pipeline, such as above ``decorated_view``, then you MUST also specify
1161        ``under`` to something earlier in the order, or a
1162        ``CyclicDependencyError`` will be raised when trying to sort the
1163        derivers.
1164
1165        See :ref:`view_derivers` for more information.
1166
1167        """
1168        deriver = self.maybe_dotted(deriver)
1169
1170        if name is None:
1171            name = deriver.__name__
1172
1173        if name in (INGRESS, VIEW):
1174            raise ConfigurationError('%s is a reserved view deriver name'
1175                                     % name)
1176
1177        if under is None:
1178            under = 'decorated_view'
1179
1180        if over is None:
1181            over = 'rendered_view'
1182
1183        over = as_sorted_tuple(over)
1184        under = as_sorted_tuple(under)
1185
1186        if INGRESS in over:
1187            raise ConfigurationError('%s cannot be over INGRESS' % name)
1188
1189        # ensure everything is always over mapped_view
1190        if VIEW in over and name != 'mapped_view':
1191            over = as_sorted_tuple(over + ('mapped_view',))
1192
1193        if VIEW in under:
1194            raise ConfigurationError('%s cannot be under VIEW' % name)
1195        if 'mapped_view' in under:
1196            raise ConfigurationError('%s cannot be under "mapped_view"' % name)
1197
1198        discriminator = ('view deriver', name)
1199        intr = self.introspectable(
1200            'view derivers',
1201            name,
1202            name,
1203            'view deriver')
1204        intr['name'] = name
1205        intr['deriver'] = deriver
1206        intr['under'] = under
1207        intr['over'] = over
1208        def register():
1209            derivers = self.registry.queryUtility(IViewDerivers)
1210            if derivers is None:
1211                derivers = TopologicalSorter(
1212                    default_before=None,
1213                    default_after=INGRESS,
1214                    first=INGRESS,
1215                    last=VIEW,
1216                )
1217                self.registry.registerUtility(derivers, IViewDerivers)
1218            derivers.add(name, deriver, before=over, after=under)
1219        self.action(discriminator, register, introspectables=(intr,),
1220                    order=PHASE1_CONFIG) # must be registered before add_view
1221
1222    def add_default_view_derivers(self):
1223        d = pyramid.viewderivers
1224        derivers = [
1225            ('secured_view', d.secured_view),
1226            ('owrapped_view', d.owrapped_view),
1227            ('http_cached_view', d.http_cached_view),
1228            ('decorated_view', d.decorated_view),
1229            ('rendered_view', d.rendered_view),
1230            ('mapped_view', d.mapped_view),
1231        ]
1232        last = INGRESS
1233        for name, deriver in derivers:
1234            self.add_view_deriver(
1235                deriver,
1236                name=name,
1237                under=last,
1238                over=VIEW,
1239            )
1240            last = name
1241
1242        # leave the csrf_view loosely coupled to the rest of the pipeline
1243        # by ensuring nothing in the default pipeline depends on the order
1244        # of the csrf_view
1245        self.add_view_deriver(
1246            d.csrf_view,
1247            'csrf_view',
1248            under='secured_view',
1249            over='owrapped_view',
1250        )
1251
1252    def derive_view(self, view, attr=None, renderer=None):
1253        """
1254        Create a :term:`view callable` using the function, instance,
1255        or class (or :term:`dotted Python name` referring to the same)
1256        provided as ``view`` object.
1257
1258        .. warning::
1259
1260           This method is typically only used by :app:`Pyramid` framework
1261           extension authors, not by :app:`Pyramid` application developers.
1262
1263        This is API is useful to framework extenders who create
1264        pluggable systems which need to register 'proxy' view
1265        callables for functions, instances, or classes which meet the
1266        requirements of being a :app:`Pyramid` view callable.  For
1267        example, a ``some_other_framework`` function in another
1268        framework may want to allow a user to supply a view callable,
1269        but he may want to wrap the view callable in his own before
1270        registering the wrapper as a :app:`Pyramid` view callable.
1271        Because a :app:`Pyramid` view callable can be any of a
1272        number of valid objects, the framework extender will not know
1273        how to call the user-supplied object.  Running it through
1274        ``derive_view`` normalizes it to a callable which accepts two
1275        arguments: ``context`` and ``request``.
1276
1277        For example:
1278
1279        .. code-block:: python
1280
1281           def some_other_framework(user_supplied_view):
1282               config = Configurator(reg)
1283               proxy_view = config.derive_view(user_supplied_view)
1284               def my_wrapper(context, request):
1285                   do_something_that_mutates(request)
1286                   return proxy_view(context, request)
1287               config.add_view(my_wrapper)
1288
1289        The ``view`` object provided should be one of the following:
1290
1291        - A function or another non-class callable object that accepts
1292          a :term:`request` as a single positional argument and which
1293          returns a :term:`response` object.
1294
1295        - A function or other non-class callable object that accepts
1296          two positional arguments, ``context, request`` and which
1297          returns a :term:`response` object.
1298
1299        - A class which accepts a single positional argument in its
1300          constructor named ``request``, and which has a ``__call__``
1301          method that accepts no arguments that returns a
1302          :term:`response` object.
1303
1304        - A class which accepts two positional arguments named
1305          ``context, request``, and which has a ``__call__`` method
1306          that accepts no arguments that returns a :term:`response`
1307          object.
1308
1309        - A :term:`dotted Python name` which refers to any of the
1310          kinds of objects above.
1311
1312        This API returns a callable which accepts the arguments
1313        ``context, request`` and which returns the result of calling
1314        the provided ``view`` object.
1315
1316        The ``attr`` keyword argument is most useful when the view
1317        object is a class.  It names the method that should be used as
1318        the callable.  If ``attr`` is not provided, the attribute
1319        effectively defaults to ``__call__``.  See
1320        :ref:`class_as_view` for more information.
1321
1322        The ``renderer`` keyword argument should be a renderer
1323        name. If supplied, it will cause the returned callable to use
1324        a :term:`renderer` to convert the user-supplied view result to
1325        a :term:`response` object.  If a ``renderer`` argument is not
1326        supplied, the user-supplied view must itself return a
1327        :term:`response` object.  """
1328        return self._derive_view(view, attr=attr, renderer=renderer)
1329
1330    # b/w compat
1331    def _derive_view(self, view, permission=None, predicates=(),
1332                     attr=None, renderer=None, wrapper_viewname=None,
1333                     viewname=None, accept=None, order=MAX_ORDER,
1334                     phash=DEFAULT_PHASH, decorator=None,
1335                     mapper=None, http_cache=None, context=None,
1336                     require_csrf=None, extra_options=None):
1337        view = self.maybe_dotted(view)
1338        mapper = self.maybe_dotted(mapper)
1339        if isinstance(renderer, string_types):
1340            renderer = renderers.RendererHelper(
1341                name=renderer, package=self.package,
1342                registry=self.registry)
1343        if renderer is None:
1344            # use default renderer if one exists
1345            if self.registry.queryUtility(IRendererFactory) is not None:
1346                renderer = renderers.RendererHelper(
1347                    name=None,
1348                    package=self.package,
1349                    registry=self.registry)
1350
1351        options = dict(
1352            view=view,
1353            context=context,
1354            permission=permission,
1355            attr=attr,
1356            renderer=renderer,
1357            wrapper=wrapper_viewname,
1358            name=viewname,
1359            accept=accept,
1360            mapper=mapper,
1361            decorator=decorator,
1362            http_cache=http_cache,
1363            require_csrf=require_csrf,
1364        )
1365        if extra_options:
1366            options.update(extra_options)
1367
1368        info = ViewDeriverInfo(
1369            view=view,
1370            registry=self.registry,
1371            package=self.package,
1372            predicates=predicates,
1373            options=options,
1374        )
1375
1376        # order and phash are only necessary for the predicated view and
1377        # are not really view deriver options
1378        info.order = order
1379        info.phash = phash
1380
1381        return self._apply_view_derivers(info)
1382
1383    @viewdefaults
1384    @action_method
1385    def add_forbidden_view(
1386        self,
1387        view=None,
1388        attr=None,
1389        renderer=None,
1390        wrapper=None,
1391        route_name=None,
1392        request_type=None,
1393        request_method=None,
1394        request_param=None,
1395        containment=None,
1396        xhr=None,
1397        accept=None,
1398        header=None,
1399        path_info=None,
1400        custom_predicates=(),
1401        decorator=None,
1402        mapper=None,
1403        match_param=None,
1404        **view_options
1405        ):
1406        """ Add a forbidden view to the current configuration state.  The
1407        view will be called when Pyramid or application code raises a
1408        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of
1409        circumstances implied by the predicates provided are matched.  The
1410        simplest example is:
1411
1412          .. code-block:: python
1413
1414            def forbidden(request):
1415                return Response('Forbidden', status='403 Forbidden')
1416
1417            config.add_forbidden_view(forbidden)
1418
1419        If ``view`` argument is not provided, the view callable defaults to
1420        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.
1421
1422        All arguments have the same meaning as
1423        :meth:`pyramid.config.Configurator.add_view` and each predicate
1424        argument restricts the set of circumstances under which this forbidden
1425        view will be invoked.  Unlike
1426        :meth:`pyramid.config.Configurator.add_view`, this method will raise
1427        an exception if passed ``name``, ``permission``, ``context``,
1428        ``for_``, or ``http_cache`` keyword arguments.  These argument values
1429        make no sense in the context of a forbidden view.
1430
1431        .. versionadded:: 1.3
1432        """
1433        for arg in (
1434            'name', 'permission', 'context', 'for_', 'http_cache',
1435            'require_csrf',
1436        ):
1437            if arg in view_options:
1438                raise ConfigurationError(
1439                    '%s may not be used as an argument to add_forbidden_view'
1440                    % arg
1441                    )
1442
1443        if view is None:
1444            view = default_exceptionresponse_view
1445
1446        settings = dict(
1447            view=view,
1448            context=HTTPForbidden,
1449            wrapper=wrapper,
1450            request_type=request_type,
1451            request_method=request_method,
1452            request_param=request_param,
1453            containment=containment,
1454            xhr=xhr,
1455            accept=accept,
1456            header=header,
1457            path_info=path_info,
1458            custom_predicates=custom_predicates,
1459            decorator=decorator,
1460            mapper=mapper,
1461            match_param=match_param,
1462            route_name=route_name,
1463            permission=NO_PERMISSION_REQUIRED,
1464            require_csrf=False,
1465            attr=attr,
1466            renderer=renderer,
1467            )
1468        settings.update(view_options)
1469        return self.add_view(**settings)
1470
1471    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias
1472
1473    @viewdefaults
1474    @action_method
1475    def add_notfound_view(
1476        self,
1477        view=None,
1478        attr=None,
1479        renderer=None,
1480        wrapper=None,
1481        route_name=None,
1482        request_type=None,
1483        request_method=None,
1484        request_param=None,
1485        containment=None,
1486        xhr=None,
1487        accept=None,
1488        header=None,
1489        path_info=None,
1490        custom_predicates=(),
1491        decorator=None,
1492        mapper=None,
1493        match_param=None,
1494        append_slash=False,
1495        **view_options
1496        ):
1497        """ Add a default Not Found View to the current configuration state.
1498        The view will be called when Pyramid or application code raises an
1499        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a
1500        view cannot be found for the request).  The simplest example is:
1501
1502          .. code-block:: python
1503
1504            def notfound(request):
1505                return Response('Not Found', status='404 Not Found')
1506
1507            config.add_notfound_view(notfound)
1508
1509        If ``view`` argument is not provided, the view callable defaults to
1510        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.
1511
1512        All arguments except ``append_slash`` have the same meaning as
1513        :meth:`pyramid.config.Configurator.add_view` and each predicate
1514        argument restricts the set of circumstances under which this notfound
1515        view will be invoked.  Unlike
1516        :meth:`pyramid.config.Configurator.add_view`, this method will raise
1517        an exception if passed ``name``, ``permission``, ``context``,
1518        ``for_``, or ``http_cache`` keyword arguments.  These argument values
1519        make no sense in the context of a Not Found View.
1520
1521        If ``append_slash`` is ``True``, when this Not Found View is invoked,
1522        and the current path info does not end in a slash, the notfound logic
1523        will attempt to find a :term:`route` that matches the request's path
1524        info suffixed with a slash.  If such a route exists, Pyramid will
1525        issue a redirect to the URL implied by the route; if it does not,
1526        Pyramid will return the result of the view callable provided as
1527        ``view``, as normal.
1528
1529        If the argument provided as ``append_slash`` is not a boolean but
1530        instead implements :class:`~pyramid.interfaces.IResponse`, the
1531        append_slash logic will behave as if ``append_slash=True`` was passed,
1532        but the provided class will be used as the response class instead of
1533        the default :class:`~pyramid.httpexceptions.HTTPFound` response class
1534        when a redirect is performed.  For example:
1535
1536          .. code-block:: python
1537
1538            from pyramid.httpexceptions import HTTPMovedPermanently
1539            config.add_notfound_view(append_slash=HTTPMovedPermanently)
1540
1541        The above means that a redirect to a slash-appended route will be
1542        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`
1543        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will
1544        be used` for the redirect response if a slash-appended route is found.
1545
1546        .. versionchanged:: 1.6
1547        .. versionadded:: 1.3
1548        """
1549        for arg in (
1550            'name', 'permission', 'context', 'for_', 'http_cache',
1551            'require_csrf',
1552        ):
1553            if arg in view_options:
1554                raise ConfigurationError(
1555                    '%s may not be used as an argument to add_notfound_view'
1556                    % arg
1557                    )
1558
1559        if view is None:
1560            view = default_exceptionresponse_view
1561
1562        settings = dict(
1563            view=view,
1564            context=HTTPNotFound,
1565            wrapper=wrapper,
1566            request_type=request_type,
1567            request_method=request_method,
1568            request_param=request_param,
1569            containment=containment,
1570            xhr=xhr,
1571            accept=accept,
1572            header=header,
1573            path_info=path_info,
1574            custom_predicates=custom_predicates,
1575            decorator=decorator,
1576            mapper=mapper,
1577            match_param=match_param,
1578            route_name=route_name,
1579            permission=NO_PERMISSION_REQUIRED,
1580            require_csrf=False,
1581            )
1582        settings.update(view_options)
1583        if append_slash:
1584            view = self._derive_view(view, attr=attr, renderer=renderer)
1585            if IResponse.implementedBy(append_slash):
1586                view = AppendSlashNotFoundViewFactory(
1587                    view, redirect_class=append_slash,
1588                )
1589            else:
1590                view = AppendSlashNotFoundViewFactory(view)
1591            settings['view'] = view
1592        else:
1593            settings['attr'] = attr
1594            settings['renderer'] = renderer
1595        return self.add_view(**settings)
1596
1597    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias
1598
1599    @action_method
1600    def set_view_mapper(self, mapper):
1601        """
1602        Setting a :term:`view mapper` makes it possible to make use of
1603        :term:`view callable` objects which implement different call
1604        signatures than the ones supported by :app:`Pyramid` as described in
1605        its narrative documentation.
1606
1607        The ``mapper`` argument should be an object implementing
1608        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted
1609        Python name` to such an object.  The provided ``mapper`` will become
1610        the default view mapper to be used by all subsequent :term:`view
1611        configuration` registrations.
1612
1613        .. seealso::
1614
1615            See also :ref:`using_a_view_mapper`.
1616
1617        .. note::
1618
1619           Using the ``default_view_mapper`` argument to the
1620           :class:`pyramid.config.Configurator` constructor
1621           can be used to achieve the same purpose.
1622        """
1623        mapper = self.maybe_dotted(mapper)
1624        def register():
1625            self.registry.registerUtility(mapper, IViewMapperFactory)
1626        # IViewMapperFactory is looked up as the result of view config
1627        # in phase 3
1628        intr = self.introspectable('view mappers',
1629                                   IViewMapperFactory,
1630                                   self.object_description(mapper),
1631                                   'default view mapper')
1632        intr['mapper'] = mapper
1633        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,
1634                    introspectables=(intr,))
1635
1636    @action_method
1637    def add_static_view(self, name, path, **kw):
1638        """ Add a view used to render static assets such as images
1639        and CSS files.
1640
1641        The ``name`` argument is a string representing an
1642        application-relative local URL prefix.  It may alternately be a full
1643        URL.
1644
1645        The ``path`` argument is the path on disk where the static files
1646        reside.  This can be an absolute path, a package-relative path, or a
1647        :term:`asset specification`.
1648
1649        The ``cache_max_age`` keyword argument is input to set the
1650        ``Expires`` and ``Cache-Control`` headers for static assets served.
1651        Note that this argument has no effect when the ``name`` is a *url
1652        prefix*.  By default, this argument is ``None``, meaning that no
1653        particular Expires or Cache-Control headers are set in the response.
1654
1655        The ``permission`` keyword argument is used to specify the
1656        :term:`permission` required by a user to execute the static view.  By
1657        default, it is the string
1658        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel
1659        which indicates that, even if a :term:`default permission` exists for
1660        the current application, the static view should be renderered to
1661        completely anonymous users.  This default value is permissive
1662        because, in most web apps, static assets seldom need protection from
1663        viewing.  If ``permission`` is specified, the security checking will
1664        be performed against the default root factory ACL.
1665
1666        Any other keyword arguments sent to ``add_static_view`` are passed on
1667        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,
1668        perhaps to define a custom factory with a custom ACL for this static
1669        view).
1670
1671        *Usage*
1672
1673        The ``add_static_view`` function is typically used in conjunction
1674        with the :meth:`pyramid.request.Request.static_url` method.
1675        ``add_static_view`` adds a view which renders a static asset when
1676        some URL is visited; :meth:`pyramid.request.Request.static_url`
1677        generates a URL to that asset.
1678
1679        The ``name`` argument to ``add_static_view`` is usually a simple URL
1680        prefix (e.g. ``'images'``).  When this is the case, the
1681        :meth:`pyramid.request.Request.static_url` API will generate a URL
1682        which points to a Pyramid view, which will serve up a set of assets
1683        that live in the package itself. For example:
1684
1685        .. code-block:: python
1686
1687           add_static_view('images', 'mypackage:images/')
1688
1689        Code that registers such a view can generate URLs to the view via
1690        :meth:`pyramid.request.Request.static_url`:
1691
1692        .. code-block:: python
1693
1694           request.static_url('mypackage:images/logo.png')
1695
1696        When ``add_static_view`` is called with a ``name`` argument that
1697        represents a URL prefix, as it is above, subsequent calls to
1698        :meth:`pyramid.request.Request.static_url` with paths that start with
1699        the ``path`` argument passed to ``add_static_view`` will generate a
1700        URL something like ``http://<Pyramid app URL>/images/logo.png``,
1701        which will cause the ``logo.png`` file in the ``images`` subdirectory
1702        of the ``mypackage`` package to be served.
1703
1704        ``add_static_view`` can alternately be used with a ``name`` argument
1705        which is a *URL*, causing static assets to be served from an external
1706        webserver.  This happens when the ``name`` argument is a fully
1707        qualified URL (e.g. starts with ``http://`` or similar).  In this
1708        mode, the ``name`` is used as the prefix of the full URL when
1709        generating a URL using :meth:`pyramid.request.Request.static_url`.
1710        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)
1711        is used as the ``name`` argument, the generated URL will use the
1712        protocol of the request (http or https, respectively).
1713
1714        For example, if ``add_static_view`` is called like so:
1715
1716        .. code-block:: python
1717
1718           add_static_view('http://example.com/images', 'mypackage:images/')
1719
1720        Subsequently, the URLs generated by
1721        :meth:`pyramid.request.Request.static_url` for that static view will
1722        be prefixed with ``http://example.com/images`` (the external webserver
1723        listening on ``example.com`` must be itself configured to respond
1724        properly to such a request.):
1725
1726        .. code-block:: python
1727
1728           static_url('mypackage:images/logo.png', request)
1729
1730        See :ref:`static_assets_section` for more information.
1731        """
1732        spec = self._make_spec(path)
1733        info = self._get_static_info()
1734        info.add(self, name, spec, **kw)
1735
1736    def add_cache_buster(self, path, cachebust, explicit=False):
1737        """
1738        Add a cache buster to a set of files on disk.
1739
1740        The ``path`` should be the path on disk where the static files
1741        reside.  This can be an absolute path, a package-relative path, or a
1742        :term:`asset specification`.
1743
1744        The ``cachebust`` argument may be set to cause
1745        :meth:`~pyramid.request.Request.static_url` to use cache busting when
1746        generating URLs. See :ref:`cache_busting` for general information
1747        about cache busting. The value of the ``cachebust`` argument must
1748        be an object which implements
1749        :class:`~pyramid.interfaces.ICacheBuster`.
1750
1751        If ``explicit`` is set to ``True`` then the ``path`` for the cache
1752        buster will be matched based on the ``rawspec`` instead of the
1753        ``pathspec`` as defined in the
1754        :class:`~pyramid.interfaces.ICacheBuster` interface.
1755        Default: ``False``.
1756
1757        """
1758        spec = self._make_spec(path)
1759        info = self._get_static_info()
1760        info.add_cache_buster(self, spec, cachebust, explicit=explicit)
1761
1762    def _get_static_info(self):
1763        info = self.registry.queryUtility(IStaticURLInfo)
1764        if info is None:
1765            info = StaticURLInfo()
1766            self.registry.registerUtility(info, IStaticURLInfo)
1767        return info
1768
1769def isexception(o):
1770    if IInterface.providedBy(o):
1771        if IException.isEqualOrExtendedBy(o):
1772            return True
1773    return (
1774        isinstance(o, Exception) or
1775        (inspect.isclass(o) and (issubclass(o, Exception)))
1776        )
1777
1778@implementer(IViewDeriverInfo)
1779class ViewDeriverInfo(object):
1780    def __init__(self, view, registry, package, predicates, options):
1781        self.original_view = view
1782        self.registry = registry
1783        self.package = package
1784        self.predicates = predicates or []
1785        self.options = options or {}
1786
1787    @reify
1788    def settings(self):
1789        return self.registry.settings
1790
1791@implementer(IStaticURLInfo)
1792class StaticURLInfo(object):
1793    def __init__(self):
1794        self.registrations = []
1795        self.cache_busters = []
1796
1797    def generate(self, path, request, **kw):
1798        for (url, spec, route_name) in self.registrations:
1799            if path.startswith(spec):
1800                subpath = path[len(spec):]
1801                if WIN: # pragma: no cover
1802                    subpath = subpath.replace('\\', '/') # windows
1803                if self.cache_busters:
1804                    subpath, kw = self._bust_asset_path(
1805                        request, spec, subpath, kw)
1806                if url is None:
1807                    kw['subpath'] = subpath
1808                    return request.route_url(route_name, **kw)
1809                else:
1810                    app_url, scheme, host, port, qs, anchor = \
1811                        parse_url_overrides(kw)
1812                    parsed = url_parse(url)
1813                    if not parsed.scheme:
1814                        url = urlparse.urlunparse(parsed._replace(
1815                            scheme=request.environ['wsgi.url_scheme']))
1816                    subpath = url_quote(subpath)
1817                    result = urljoin(url, subpath)
1818                    return result + qs + anchor
1819
1820        raise ValueError('No static URL definition matching %s' % path)
1821
1822    def add(self, config, name, spec, **extra):
1823        # This feature only allows for the serving of a directory and
1824        # the files contained within, not of a single asset;
1825        # appending a slash here if the spec doesn't have one is
1826        # required for proper prefix matching done in ``generate``
1827        # (``subpath = path[len(spec):]``).
1828        if os.path.isabs(spec): # FBO windows
1829            sep = os.sep
1830        else:
1831            sep = '/'
1832        if not spec.endswith(sep) and not spec.endswith(':'):
1833            spec = spec + sep
1834
1835        # we also make sure the name ends with a slash, purely as a
1836        # convenience: a name that is a url is required to end in a
1837        # slash, so that ``urljoin(name, subpath))`` will work above
1838        # when the name is a URL, and it doesn't hurt things for it to
1839        # have a name that ends in a slash if it's used as a route
1840        # name instead of a URL.
1841        if not name.endswith('/'):
1842            # make sure it ends with a slash
1843            name = name + '/'
1844
1845        if url_parse(name).netloc:
1846            # it's a URL
1847            # url, spec, route_name
1848            url = name
1849            route_name = None
1850        else:
1851            # it's a view name
1852            url = None
1853            cache_max_age = extra.pop('cache_max_age', None)
1854
1855            # create a view
1856            view = static_view(spec, cache_max_age=cache_max_age,
1857                               use_subpath=True)
1858
1859            # Mutate extra to allow factory, etc to be passed through here.
1860            # Treat permission specially because we'd like to default to
1861            # permissiveness (see docs of config.add_static_view).
1862            permission = extra.pop('permission', None)
1863            if permission is None:
1864                permission = NO_PERMISSION_REQUIRED
1865
1866            context = extra.pop('context', None)
1867            if context is None:
1868                context = extra.pop('for_', None)
1869
1870            renderer = extra.pop('renderer', None)
1871
1872            # register a route using the computed view, permission, and
1873            # pattern, plus any extras passed to us via add_static_view
1874            pattern = "%s*subpath" % name # name already ends with slash
1875            if config.route_prefix:
1876                route_name = '__%s/%s' % (config.route_prefix, name)
1877            else:
1878                route_name = '__%s' % name
1879            config.add_route(route_name, pattern, **extra)
1880            config.add_view(
1881                route_name=route_name,
1882                view=view,
1883                permission=permission,
1884                context=context,
1885                renderer=renderer,
1886            )
1887
1888        def register():
1889            registrations = self.registrations
1890
1891            names = [t[0] for t in registrations]
1892
1893            if name in names:
1894                idx = names.index(name)
1895                registrations.pop(idx)
1896
1897            # url, spec, route_name
1898            registrations.append((url, spec, route_name))
1899
1900        intr = config.introspectable('static views',
1901                                     name,
1902                                     'static view for %r' % name,
1903                                     'static view')
1904        intr['name'] = name
1905        intr['spec'] = spec
1906
1907        config.action(None, callable=register, introspectables=(intr,))
1908
1909    def add_cache_buster(self, config, spec, cachebust, explicit=False):
1910        # ensure the spec always has a trailing slash as we only support
1911        # adding cache busters to folders, not files
1912        if os.path.isabs(spec): # FBO windows
1913            sep = os.sep
1914        else:
1915            sep = '/'
1916        if not spec.endswith(sep) and not spec.endswith(':'):
1917            spec = spec + sep
1918
1919        def register():
1920            if config.registry.settings.get('pyramid.prevent_cachebust'):
1921                return
1922
1923            cache_busters = self.cache_busters
1924
1925            # find duplicate cache buster (old_idx)
1926            # and insertion location (new_idx)
1927            new_idx, old_idx = len(cache_busters), None
1928            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):
1929                # if we find an identical (spec, explicit) then use it
1930                if spec == spec_ and explicit == explicit_:
1931                    old_idx = new_idx = idx
1932                    break
1933
1934                # past all explicit==False specs then add to the end
1935                elif not explicit and explicit_:
1936                    new_idx = idx
1937                    break
1938
1939                # explicit matches and spec is shorter
1940                elif explicit == explicit_ and len(spec) < len(spec_):
1941                    new_idx = idx
1942                    break
1943
1944            if old_idx is not None:
1945                cache_busters.pop(old_idx)
1946
1947            cache_busters.insert(new_idx, (spec, cachebust, explicit))
1948
1949        intr = config.introspectable('cache busters',
1950                                     spec,
1951                                     'cache buster for %r' % spec,
1952                                     'cache buster')
1953        intr['cachebust'] = cachebust
1954        intr['path'] = spec
1955        intr['explicit'] = explicit
1956
1957        config.action(None, callable=register, introspectables=(intr,))
1958
1959    def _bust_asset_path(self, request, spec, subpath, kw):
1960        registry = request.registry
1961        pkg_name, pkg_subpath = resolve_asset_spec(spec)
1962        rawspec = None
1963
1964        if pkg_name is not None:
1965            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)
1966            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)
1967            if overrides is not None:
1968                resource_name = posixpath.join(pkg_subpath, subpath)
1969                sources = overrides.filtered_sources(resource_name)
1970                for source, filtered_path in sources:
1971                    rawspec = source.get_path(filtered_path)
1972                    if hasattr(source, 'pkg_name'):
1973                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)
1974                    break
1975
1976        else:
1977            pathspec = pkg_subpath + subpath
1978
1979        if rawspec is None:
1980            rawspec = pathspec
1981
1982        kw['pathspec'] = pathspec
1983        kw['rawspec'] = rawspec
1984        for spec_, cachebust, explicit in reversed(self.cache_busters):
1985            if (
1986                (explicit and rawspec.startswith(spec_)) or
1987                (not explicit and pathspec.startswith(spec_))
1988            ):
1989                subpath, kw = cachebust(request, subpath, kw)
1990                break
1991        return subpath, kw
1992