{
    "file_diffs": [
        {
            "old_file_content": "import inspect\nimport posixpath\nimport operator\nimport os\nimport warnings\n\nfrom zope.interface import (\n    Interface,\n    implementedBy,\n    implementer,\n    )\n\nfrom zope.interface.interfaces import IInterface\n\nfrom pyramid.interfaces import (\n    IException,\n    IExceptionViewClassifier,\n    IMultiView,\n    IPackageOverrides,\n    IRendererFactory,\n    IRequest,\n    IResponse,\n    IRouteRequest,\n    ISecuredView,\n    IStaticURLInfo,\n    IView,\n    IViewClassifier,\n    IViewDerivers,\n    IViewDeriverInfo,\n    IViewMapperFactory,\n    PHASE1_CONFIG,\n    )\n\nfrom pyramid import renderers\n\nfrom pyramid.asset import resolve_asset_spec\nfrom pyramid.compat import (\n    string_types,\n    urlparse,\n    url_quote,\n    WIN,\n    is_nonstr_iter,\n    )\n\nfrom pyramid.decorator import reify\n\nfrom pyramid.exceptions import (\n    ConfigurationError,\n    PredicateMismatch,\n    )\n\nfrom pyramid.httpexceptions import (\n    HTTPForbidden,\n    HTTPNotFound,\n    default_exceptionresponse_view,\n    )\n\nfrom pyramid.registry import (\n    predvalseq,\n    Deferred,\n    )\n\nfrom pyramid.security import NO_PERMISSION_REQUIRED\nfrom pyramid.static import static_view\n\nfrom pyramid.url import parse_url_overrides\n\nfrom pyramid.view import AppendSlashNotFoundViewFactory\n\nimport pyramid.util\nfrom pyramid.util import (\n    viewdefaults,\n    action_method,\n    TopologicalSorter,\n    )\n\nimport pyramid.config.predicates\nimport pyramid.viewderivers\n\nfrom pyramid.viewderivers import (\n    INGRESS,\n    VIEW,\n    preserve_view_attrs,\n    view_description,\n    requestonly,\n    DefaultViewMapper,\n    wraps_view,\n)\n\nfrom pyramid.config.util import (\n    DEFAULT_PHASH,\n    MAX_ORDER,\n    as_sorted_tuple,\n    )\n\nurljoin = urlparse.urljoin\nurl_parse = urlparse.urlparse\n\nDefaultViewMapper = DefaultViewMapper # bw-compat\npreserve_view_attrs = preserve_view_attrs # bw-compat\nrequestonly = requestonly # bw-compat\nview_description = view_description # bw-compat\n\n@implementer(IMultiView)\nclass MultiView(object):\n\n    def __init__(self, name):\n        self.name = name\n        self.media_views = {}\n        self.views = []\n        self.accepts = []\n\n    def __discriminator__(self, context, request):\n        # used by introspection systems like so:\n        # view = adapters.lookup(....)\n        # view.__discriminator__(context, request) -> view's discriminator\n        # so that superdynamic systems can feed the discriminator to\n        # the introspection system to get info about it\n        view = self.match(context, request)\n        return view.__discriminator__(context, request)\n\n    def add(self, view, order, accept=None, phash=None):\n        if phash is not None:\n            for i, (s, v, h) in enumerate(list(self.views)):\n                if phash == h:\n                    self.views[i] = (order, view, phash)\n                    return\n\n        if accept is None or '*' in accept:\n            self.views.append((order, view, phash))\n            self.views.sort(key=operator.itemgetter(0))\n        else:\n            subset = self.media_views.setdefault(accept, [])\n            for i, (s, v, h) in enumerate(list(subset)):\n                if phash == h:\n                    subset[i] = (order, view, phash)\n                    return\n            else:\n                subset.append((order, view, phash))\n                subset.sort(key=operator.itemgetter(0))\n            accepts = set(self.accepts)\n            accepts.add(accept)\n            self.accepts = list(accepts) # dedupe\n\n    def get_views(self, request):\n        if self.accepts and hasattr(request, 'accept'):\n            accepts = self.accepts[:]\n            views = []\n            while accepts:\n                match = request.accept.best_match(accepts)\n                if match is None:\n                    break\n                subset = self.media_views[match]\n                views.extend(subset)\n                accepts.remove(match)\n            views.extend(self.views)\n            return views\n        return self.views\n\n    def match(self, context, request):\n        for order, view, phash in self.get_views(request):\n            if not hasattr(view, '__predicated__'):\n                return view\n            if view.__predicated__(context, request):\n                return view\n        raise PredicateMismatch(self.name)\n\n    def __permitted__(self, context, request):\n        view = self.match(context, request)\n        if hasattr(view, '__permitted__'):\n            return view.__permitted__(context, request)\n        return True\n\n    def __call_permissive__(self, context, request):\n        view = self.match(context, request)\n        view = getattr(view, '__call_permissive__', view)\n        return view(context, request)\n\n    def __call__(self, context, request):\n        for order, view, phash in self.get_views(request):\n            try:\n                return view(context, request)\n            except PredicateMismatch:\n                continue\n        raise PredicateMismatch(self.name)\n\nclass ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                self.registry.registerAdapter(\n                    derived_view,\n                    (IViewClassifier, request_iface, context), view_iface, name\n                    )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info\n\ndef isexception(o):\n    if IInterface.providedBy(o):\n        if IException.isEqualOrExtendedBy(o):\n            return True\n    return (\n        isinstance(o, Exception) or\n        (inspect.isclass(o) and (issubclass(o, Exception)))\n        )\n\n@implementer(IViewDeriverInfo)\nclass ViewDeriverInfo(object):\n    def __init__(self, view, registry, package, predicates, options):\n        self.original_view = view\n        self.registry = registry\n        self.package = package\n        self.predicates = predicates or []\n        self.options = options or {}\n\n    @reify\n    def settings(self):\n        return self.registry.settings\n\n@implementer(IStaticURLInfo)\nclass StaticURLInfo(object):\n    def __init__(self):\n        self.registrations = []\n        self.cache_busters = []\n\n    def generate(self, path, request, **kw):\n        for (url, spec, route_name) in self.registrations:\n            if path.startswith(spec):\n                subpath = path[len(spec):]\n                if WIN: # pragma: no cover\n                    subpath = subpath.replace('\\\\', '/') # windows\n                if self.cache_busters:\n                    subpath, kw = self._bust_asset_path(\n                        request, spec, subpath, kw)\n                if url is None:\n                    kw['subpath'] = subpath\n                    return request.route_url(route_name, **kw)\n                else:\n                    app_url, scheme, host, port, qs, anchor = \\\n                        parse_url_overrides(kw)\n                    parsed = url_parse(url)\n                    if not parsed.scheme:\n                        url = urlparse.urlunparse(parsed._replace(\n                            scheme=request.environ['wsgi.url_scheme']))\n                    subpath = url_quote(subpath)\n                    result = urljoin(url, subpath)\n                    return result + qs + anchor\n\n        raise ValueError('No static URL definition matching %s' % path)\n\n    def add(self, config, name, spec, **extra):\n        # This feature only allows for the serving of a directory and\n        # the files contained within, not of a single asset;\n        # appending a slash here if the spec doesn't have one is\n        # required for proper prefix matching done in ``generate``\n        # (``subpath = path[len(spec):]``).\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        # we also make sure the name ends with a slash, purely as a\n        # convenience: a name that is a url is required to end in a\n        # slash, so that ``urljoin(name, subpath))`` will work above\n        # when the name is a URL, and it doesn't hurt things for it to\n        # have a name that ends in a slash if it's used as a route\n        # name instead of a URL.\n        if not name.endswith('/'):\n            # make sure it ends with a slash\n            name = name + '/'\n\n        if url_parse(name).netloc:\n            # it's a URL\n            # url, spec, route_name\n            url = name\n            route_name = None\n        else:\n            # it's a view name\n            url = None\n            cache_max_age = extra.pop('cache_max_age', None)\n\n            # create a view\n            view = static_view(spec, cache_max_age=cache_max_age,\n                               use_subpath=True)\n\n            # Mutate extra to allow factory, etc to be passed through here.\n            # Treat permission specially because we'd like to default to\n            # permissiveness (see docs of config.add_static_view).\n            permission = extra.pop('permission', None)\n            if permission is None:\n                permission = NO_PERMISSION_REQUIRED\n\n            context = extra.pop('context', None)\n            if context is None:\n                context = extra.pop('for_', None)\n\n            renderer = extra.pop('renderer', None)\n\n            # register a route using the computed view, permission, and\n            # pattern, plus any extras passed to us via add_static_view\n            pattern = \"%s*subpath\" % name # name already ends with slash\n            if config.route_prefix:\n                route_name = '__%s/%s' % (config.route_prefix, name)\n            else:\n                route_name = '__%s' % name\n            config.add_route(route_name, pattern, **extra)\n            config.add_view(\n                route_name=route_name,\n                view=view,\n                permission=permission,\n                context=context,\n                renderer=renderer,\n            )\n\n        def register():\n            registrations = self.registrations\n\n            names = [t[0] for t in registrations]\n\n            if name in names:\n                idx = names.index(name)\n                registrations.pop(idx)\n\n            # url, spec, route_name\n            registrations.append((url, spec, route_name))\n\n        intr = config.introspectable('static views',\n                                     name,\n                                     'static view for %r' % name,\n                                     'static view')\n        intr['name'] = name\n        intr['spec'] = spec\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def add_cache_buster(self, config, spec, cachebust, explicit=False):\n        # ensure the spec always has a trailing slash as we only support\n        # adding cache busters to folders, not files\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        def register():\n            if config.registry.settings.get('pyramid.prevent_cachebust'):\n                return\n\n            cache_busters = self.cache_busters\n\n            # find duplicate cache buster (old_idx)\n            # and insertion location (new_idx)\n            new_idx, old_idx = len(cache_busters), None\n            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):\n                # if we find an identical (spec, explicit) then use it\n                if spec == spec_ and explicit == explicit_:\n                    old_idx = new_idx = idx\n                    break\n\n                # past all explicit==False specs then add to the end\n                elif not explicit and explicit_:\n                    new_idx = idx\n                    break\n\n                # explicit matches and spec is shorter\n                elif explicit == explicit_ and len(spec) < len(spec_):\n                    new_idx = idx\n                    break\n\n            if old_idx is not None:\n                cache_busters.pop(old_idx)\n\n            cache_busters.insert(new_idx, (spec, cachebust, explicit))\n\n        intr = config.introspectable('cache busters',\n                                     spec,\n                                     'cache buster for %r' % spec,\n                                     'cache buster')\n        intr['cachebust'] = cachebust\n        intr['path'] = spec\n        intr['explicit'] = explicit\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def _bust_asset_path(self, request, spec, subpath, kw):\n        registry = request.registry\n        pkg_name, pkg_subpath = resolve_asset_spec(spec)\n        rawspec = None\n\n        if pkg_name is not None:\n            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)\n            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)\n            if overrides is not None:\n                resource_name = posixpath.join(pkg_subpath, subpath)\n                sources = overrides.filtered_sources(resource_name)\n                for source, filtered_path in sources:\n                    rawspec = source.get_path(filtered_path)\n                    if hasattr(source, 'pkg_name'):\n                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)\n                    break\n\n        else:\n            pathspec = pkg_subpath + subpath\n\n        if rawspec is None:\n            rawspec = pathspec\n\n        kw['pathspec'] = pathspec\n        kw['rawspec'] = rawspec\n        for spec_, cachebust, explicit in reversed(self.cache_busters):\n            if (\n                (explicit and rawspec.startswith(spec_)) or\n                (not explicit and pathspec.startswith(spec_))\n            ):\n                subpath, kw = cachebust(request, subpath, kw)\n                break\n        return subpath, kw\n",
            "new_file_content": "import inspect\nimport posixpath\nimport operator\nimport os\nimport warnings\n\nfrom zope.interface import (\n    Interface,\n    implementedBy,\n    implementer,\n    )\n\nfrom zope.interface.interfaces import IInterface\n\nfrom pyramid.interfaces import (\n    IException,\n    IExceptionViewClassifier,\n    IMultiView,\n    IPackageOverrides,\n    IRendererFactory,\n    IRequest,\n    IResponse,\n    IRouteRequest,\n    ISecuredView,\n    IStaticURLInfo,\n    IView,\n    IViewClassifier,\n    IViewDerivers,\n    IViewDeriverInfo,\n    IViewMapperFactory,\n    PHASE1_CONFIG,\n    )\n\nfrom pyramid import renderers\n\nfrom pyramid.asset import resolve_asset_spec\nfrom pyramid.compat import (\n    string_types,\n    urlparse,\n    url_quote,\n    WIN,\n    is_nonstr_iter,\n    )\n\nfrom pyramid.decorator import reify\n\nfrom pyramid.exceptions import (\n    ConfigurationError,\n    PredicateMismatch,\n    )\n\nfrom pyramid.httpexceptions import (\n    HTTPForbidden,\n    HTTPNotFound,\n    default_exceptionresponse_view,\n    )\n\nfrom pyramid.registry import (\n    predvalseq,\n    Deferred,\n    )\n\nfrom pyramid.security import NO_PERMISSION_REQUIRED\nfrom pyramid.static import static_view\n\nfrom pyramid.url import parse_url_overrides\n\nfrom pyramid.view import AppendSlashNotFoundViewFactory\n\nimport pyramid.util\nfrom pyramid.util import (\n    viewdefaults,\n    action_method,\n    TopologicalSorter,\n    )\n\nimport pyramid.config.predicates\nimport pyramid.viewderivers\n\nfrom pyramid.viewderivers import (\n    INGRESS,\n    VIEW,\n    preserve_view_attrs,\n    view_description,\n    requestonly,\n    DefaultViewMapper,\n    wraps_view,\n)\n\nfrom pyramid.config.util import (\n    DEFAULT_PHASH,\n    MAX_ORDER,\n    as_sorted_tuple,\n    )\n\nurljoin = urlparse.urljoin\nurl_parse = urlparse.urlparse\n\nDefaultViewMapper = DefaultViewMapper # bw-compat\npreserve_view_attrs = preserve_view_attrs # bw-compat\nrequestonly = requestonly # bw-compat\nview_description = view_description # bw-compat\n\n@implementer(IMultiView)\nclass MultiView(object):\n\n    def __init__(self, name):\n        self.name = name\n        self.media_views = {}\n        self.views = []\n        self.accepts = []\n\n    def __discriminator__(self, context, request):\n        # used by introspection systems like so:\n        # view = adapters.lookup(....)\n        # view.__discriminator__(context, request) -> view's discriminator\n        # so that superdynamic systems can feed the discriminator to\n        # the introspection system to get info about it\n        view = self.match(context, request)\n        return view.__discriminator__(context, request)\n\n    def add(self, view, order, accept=None, phash=None):\n        if phash is not None:\n            for i, (s, v, h) in enumerate(list(self.views)):\n                if phash == h:\n                    self.views[i] = (order, view, phash)\n                    return\n\n        if accept is None or '*' in accept:\n            self.views.append((order, view, phash))\n            self.views.sort(key=operator.itemgetter(0))\n        else:\n            subset = self.media_views.setdefault(accept, [])\n            for i, (s, v, h) in enumerate(list(subset)):\n                if phash == h:\n                    subset[i] = (order, view, phash)\n                    return\n            else:\n                subset.append((order, view, phash))\n                subset.sort(key=operator.itemgetter(0))\n            accepts = set(self.accepts)\n            accepts.add(accept)\n            self.accepts = list(accepts) # dedupe\n\n    def get_views(self, request):\n        if self.accepts and hasattr(request, 'accept'):\n            accepts = self.accepts[:]\n            views = []\n            while accepts:\n                match = request.accept.best_match(accepts)\n                if match is None:\n                    break\n                subset = self.media_views[match]\n                views.extend(subset)\n                accepts.remove(match)\n            views.extend(self.views)\n            return views\n        return self.views\n\n    def match(self, context, request):\n        for order, view, phash in self.get_views(request):\n            if not hasattr(view, '__predicated__'):\n                return view\n            if view.__predicated__(context, request):\n                return view\n        raise PredicateMismatch(self.name)\n\n    def __permitted__(self, context, request):\n        view = self.match(context, request)\n        if hasattr(view, '__permitted__'):\n            return view.__permitted__(context, request)\n        return True\n\n    def __call_permissive__(self, context, request):\n        view = self.match(context, request)\n        view = getattr(view, '__call_permissive__', view)\n        return view(context, request)\n\n    def __call__(self, context, request):\n        for order, view, phash in self.get_views(request):\n            try:\n                return view(context, request)\n            except PredicateMismatch:\n                continue\n        raise PredicateMismatch(self.name)\n\nclass ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info\n\ndef isexception(o):\n    if IInterface.providedBy(o):\n        if IException.isEqualOrExtendedBy(o):\n            return True\n    return (\n        isinstance(o, Exception) or\n        (inspect.isclass(o) and (issubclass(o, Exception)))\n        )\n\n@implementer(IViewDeriverInfo)\nclass ViewDeriverInfo(object):\n    def __init__(self, view, registry, package, predicates, options):\n        self.original_view = view\n        self.registry = registry\n        self.package = package\n        self.predicates = predicates or []\n        self.options = options or {}\n\n    @reify\n    def settings(self):\n        return self.registry.settings\n\n@implementer(IStaticURLInfo)\nclass StaticURLInfo(object):\n    def __init__(self):\n        self.registrations = []\n        self.cache_busters = []\n\n    def generate(self, path, request, **kw):\n        for (url, spec, route_name) in self.registrations:\n            if path.startswith(spec):\n                subpath = path[len(spec):]\n                if WIN: # pragma: no cover\n                    subpath = subpath.replace('\\\\', '/') # windows\n                if self.cache_busters:\n                    subpath, kw = self._bust_asset_path(\n                        request, spec, subpath, kw)\n                if url is None:\n                    kw['subpath'] = subpath\n                    return request.route_url(route_name, **kw)\n                else:\n                    app_url, scheme, host, port, qs, anchor = \\\n                        parse_url_overrides(kw)\n                    parsed = url_parse(url)\n                    if not parsed.scheme:\n                        url = urlparse.urlunparse(parsed._replace(\n                            scheme=request.environ['wsgi.url_scheme']))\n                    subpath = url_quote(subpath)\n                    result = urljoin(url, subpath)\n                    return result + qs + anchor\n\n        raise ValueError('No static URL definition matching %s' % path)\n\n    def add(self, config, name, spec, **extra):\n        # This feature only allows for the serving of a directory and\n        # the files contained within, not of a single asset;\n        # appending a slash here if the spec doesn't have one is\n        # required for proper prefix matching done in ``generate``\n        # (``subpath = path[len(spec):]``).\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        # we also make sure the name ends with a slash, purely as a\n        # convenience: a name that is a url is required to end in a\n        # slash, so that ``urljoin(name, subpath))`` will work above\n        # when the name is a URL, and it doesn't hurt things for it to\n        # have a name that ends in a slash if it's used as a route\n        # name instead of a URL.\n        if not name.endswith('/'):\n            # make sure it ends with a slash\n            name = name + '/'\n\n        if url_parse(name).netloc:\n            # it's a URL\n            # url, spec, route_name\n            url = name\n            route_name = None\n        else:\n            # it's a view name\n            url = None\n            cache_max_age = extra.pop('cache_max_age', None)\n\n            # create a view\n            view = static_view(spec, cache_max_age=cache_max_age,\n                               use_subpath=True)\n\n            # Mutate extra to allow factory, etc to be passed through here.\n            # Treat permission specially because we'd like to default to\n            # permissiveness (see docs of config.add_static_view).\n            permission = extra.pop('permission', None)\n            if permission is None:\n                permission = NO_PERMISSION_REQUIRED\n\n            context = extra.pop('context', None)\n            if context is None:\n                context = extra.pop('for_', None)\n\n            renderer = extra.pop('renderer', None)\n\n            # register a route using the computed view, permission, and\n            # pattern, plus any extras passed to us via add_static_view\n            pattern = \"%s*subpath\" % name # name already ends with slash\n            if config.route_prefix:\n                route_name = '__%s/%s' % (config.route_prefix, name)\n            else:\n                route_name = '__%s' % name\n            config.add_route(route_name, pattern, **extra)\n            config.add_view(\n                route_name=route_name,\n                view=view,\n                permission=permission,\n                context=context,\n                renderer=renderer,\n            )\n\n        def register():\n            registrations = self.registrations\n\n            names = [t[0] for t in registrations]\n\n            if name in names:\n                idx = names.index(name)\n                registrations.pop(idx)\n\n            # url, spec, route_name\n            registrations.append((url, spec, route_name))\n\n        intr = config.introspectable('static views',\n                                     name,\n                                     'static view for %r' % name,\n                                     'static view')\n        intr['name'] = name\n        intr['spec'] = spec\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def add_cache_buster(self, config, spec, cachebust, explicit=False):\n        # ensure the spec always has a trailing slash as we only support\n        # adding cache busters to folders, not files\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        def register():\n            if config.registry.settings.get('pyramid.prevent_cachebust'):\n                return\n\n            cache_busters = self.cache_busters\n\n            # find duplicate cache buster (old_idx)\n            # and insertion location (new_idx)\n            new_idx, old_idx = len(cache_busters), None\n            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):\n                # if we find an identical (spec, explicit) then use it\n                if spec == spec_ and explicit == explicit_:\n                    old_idx = new_idx = idx\n                    break\n\n                # past all explicit==False specs then add to the end\n                elif not explicit and explicit_:\n                    new_idx = idx\n                    break\n\n                # explicit matches and spec is shorter\n                elif explicit == explicit_ and len(spec) < len(spec_):\n                    new_idx = idx\n                    break\n\n            if old_idx is not None:\n                cache_busters.pop(old_idx)\n\n            cache_busters.insert(new_idx, (spec, cachebust, explicit))\n\n        intr = config.introspectable('cache busters',\n                                     spec,\n                                     'cache buster for %r' % spec,\n                                     'cache buster')\n        intr['cachebust'] = cachebust\n        intr['path'] = spec\n        intr['explicit'] = explicit\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def _bust_asset_path(self, request, spec, subpath, kw):\n        registry = request.registry\n        pkg_name, pkg_subpath = resolve_asset_spec(spec)\n        rawspec = None\n\n        if pkg_name is not None:\n            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)\n            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)\n            if overrides is not None:\n                resource_name = posixpath.join(pkg_subpath, subpath)\n                sources = overrides.filtered_sources(resource_name)\n                for source, filtered_path in sources:\n                    rawspec = source.get_path(filtered_path)\n                    if hasattr(source, 'pkg_name'):\n                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)\n                    break\n\n        else:\n            pathspec = pkg_subpath + subpath\n\n        if rawspec is None:\n            rawspec = pathspec\n\n        kw['pathspec'] = pathspec\n        kw['rawspec'] = rawspec\n        for spec_, cachebust, explicit in reversed(self.cache_busters):\n            if (\n                (explicit and rawspec.startswith(spec_)) or\n                (not explicit and pathspec.startswith(spec_))\n            ):\n                subpath, kw = cachebust(request, subpath, kw)\n                break\n        return subpath, kw\n",
            "header": {
                "file": {
                    "path": "pyramid/config/views.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "9e46ba155",
                "new_commit_hash": "198fde5e8",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/pyramid/config/views.py"
            },
            "plus_file": {
                "path": "b/pyramid/config/views.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 213,
                            "length": 6
                        },
                        "new_range": {
                            "start": 213,
                            "length": 7
                        },
                        "section": "class ViewsConfiguratorMixin(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "        match_param=None,",
                                "type": "context"
                            },
                            {
                                "content": "        check_csrf=None,",
                                "type": "context"
                            },
                            {
                                "content": "        require_csrf=None,",
                                "type": "context"
                            },
                            {
                                "content": "        exception_only=False,",
                                "type": "added"
                            },
                            {
                                "content": "        **view_options):",
                                "type": "context"
                            },
                            {
                                "content": "        \"\"\" Add a :term:`view configuration` to the current",
                                "type": "context"
                            },
                            {
                                "content": "        configuration state.  Arguments to ``add_view`` are broken",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "method",
                            "name": "ViewsConfiguratorMixin.add_view",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 190,
                            "end_lineno": 1077,
                            "parent": {
                                "file_name": "pyramid/config/views.py",
                                "type": "class",
                                "name": "ViewsConfiguratorMixin",
                                "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 187,
                                "end_lineno": 1784,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "class",
                            "name": "ViewsConfiguratorMixin",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 187,
                            "end_lineno": 1784,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 701,
                            "length": 6
                        },
                        "new_range": {
                            "start": 702,
                            "length": 14
                        },
                        "section": "class ViewsConfiguratorMixin(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "             Support setting view deriver options. Previously, only custom",
                                "type": "context"
                            },
                            {
                                "content": "             view predicate values could be supplied.",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        exception_only",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "          .. versionadded:: 1.8",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "          A boolean indicating whether the view is registered only as an",
                                "type": "added"
                            },
                            {
                                "content": "          exception view. When this argument is true, the view context must",
                                "type": "added"
                            },
                            {
                                "content": "          be an exception.",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        \"\"\"",
                                "type": "context"
                            },
                            {
                                "content": "        if custom_predicates:",
                                "type": "context"
                            },
                            {
                                "content": "            warnings.warn(",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "method",
                            "name": "ViewsConfiguratorMixin.add_view",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 190,
                            "end_lineno": 1077,
                            "parent": {
                                "file_name": "pyramid/config/views.py",
                                "type": "class",
                                "name": "ViewsConfiguratorMixin",
                                "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 187,
                                "end_lineno": 1784,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "class",
                            "name": "ViewsConfiguratorMixin",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 187,
                            "end_lineno": 1784,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 759,
                            "length": 6
                        },
                        "new_range": {
                            "start": 768,
                            "length": 11
                        },
                        "section": "class ViewsConfiguratorMixin(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                raise ConfigurationError(",
                                "type": "context"
                            },
                            {
                                "content": "                    'request_type must be an interface, not %s' % request_type)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        if exception_only and not isexception(context):",
                                "type": "added"
                            },
                            {
                                "content": "            raise ConfigurationError(",
                                "type": "added"
                            },
                            {
                                "content": "                'context must be an exception when exception_only is true'",
                                "type": "added"
                            },
                            {
                                "content": "                )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "        if context is None:",
                                "type": "context"
                            },
                            {
                                "content": "            context = for_",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "method",
                            "name": "ViewsConfiguratorMixin.add_view",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 190,
                            "end_lineno": 1077,
                            "parent": {
                                "file_name": "pyramid/config/views.py",
                                "type": "class",
                                "name": "ViewsConfiguratorMixin",
                                "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 187,
                                "end_lineno": 1784,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "class",
                            "name": "ViewsConfiguratorMixin",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        exception_only=False,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        exception_only\n\n          .. versionadded:: 1.8\n\n          A boolean indicating whether the view is registered only as an\n          exception view. When this argument is true, the view context must\n          be an exception.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if exception_only and not isexception(context):\n            raise ConfigurationError(\n                'context must be an exception when exception_only is true'\n                )\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                if not exception_only:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IViewClassifier, request_iface, context),\n                        view_iface,\n                        name\n                        )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 187,
                            "end_lineno": 1784,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                },
                {
                    "descriptor": {
                        "old_range": {
                            "start": 942,
                            "length": 10
                        },
                        "new_range": {
                            "start": 956,
                            "length": 13
                        },
                        "section": "class ViewsConfiguratorMixin(object):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "                    view_iface = ISecuredView",
                                "type": "context"
                            },
                            {
                                "content": "                else:",
                                "type": "context"
                            },
                            {
                                "content": "                    view_iface = IView",
                                "type": "context"
                            },
                            {
                                "content": "                self.registry.registerAdapter(",
                                "type": "deleted"
                            },
                            {
                                "content": "                    derived_view,",
                                "type": "deleted"
                            },
                            {
                                "content": "                    (IViewClassifier, request_iface, context), view_iface, name",
                                "type": "deleted"
                            },
                            {
                                "content": "                    )",
                                "type": "deleted"
                            },
                            {
                                "content": "                if not exception_only:",
                                "type": "added"
                            },
                            {
                                "content": "                    self.registry.registerAdapter(",
                                "type": "added"
                            },
                            {
                                "content": "                        derived_view,",
                                "type": "added"
                            },
                            {
                                "content": "                        (IViewClassifier, request_iface, context),",
                                "type": "added"
                            },
                            {
                                "content": "                        view_iface,",
                                "type": "added"
                            },
                            {
                                "content": "                        name",
                                "type": "added"
                            },
                            {
                                "content": "                        )",
                                "type": "added"
                            },
                            {
                                "content": "                if isexc:",
                                "type": "context"
                            },
                            {
                                "content": "                    self.registry.registerAdapter(",
                                "type": "context"
                            },
                            {
                                "content": "                        derived_view,",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "method",
                            "name": "ViewsConfiguratorMixin.add_view",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                self.registry.registerAdapter(\n                    derived_view,\n                    (IViewClassifier, request_iface, context), view_iface, name\n                    )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 190,
                            "end_lineno": 1060,
                            "parent": {
                                "file_name": "pyramid/config/views.py",
                                "type": "class",
                                "name": "ViewsConfiguratorMixin",
                                "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                self.registry.registerAdapter(\n                    derived_view,\n                    (IViewClassifier, request_iface, context), view_iface, name\n                    )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 187,
                                "end_lineno": 1767,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/config/views.py",
                            "type": "class",
                            "name": "ViewsConfiguratorMixin",
                            "content": "class ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                self.registry.registerAdapter(\n                    derived_view,\n                    (IViewClassifier, request_iface, context), view_iface, name\n                    )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 187,
                            "end_lineno": 1767,
                            "parent": null
                        }
                    ],
                    "added_entities": [],
                    "deleted_entities": []
                }
            ]
        },
        {
            "old_file_content": "import os\nimport unittest\nfrom pyramid import testing\n\nfrom pyramid.tests.test_config import IDummy\n\nfrom pyramid.tests.test_config import dummy_view\n\nfrom pyramid.compat import (\n    im_func,\n    text_,\n    )\nfrom pyramid.exceptions import ConfigurationError\nfrom pyramid.exceptions import ConfigurationExecutionError\nfrom pyramid.exceptions import ConfigurationConflictError\n\nclass TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)\n\nclass Test_requestonly(unittest.TestCase):\n    def _callFUT(self, view, attr=None):\n        from pyramid.config.views import requestonly\n        return requestonly(view, attr=attr)\n\n    def test_defaults(self):\n        def aview(request, a=1, b=2): pass\n        self.assertTrue(self._callFUT(aview))\n\n    def test_otherattr(self):\n        class AView(object):\n            def __init__(self, request, a=1, b=2): pass\n            def bleh(self): pass\n        self.assertTrue(self._callFUT(AView, 'bleh'))\n\nclass Test_isexception(unittest.TestCase):\n    def _callFUT(self, ob):\n        from pyramid.config.views import isexception\n        return isexception(ob)\n\n    def test_is_exception_instance(self):\n        class E(Exception):\n            pass\n        e = E()\n        self.assertEqual(self._callFUT(e), True)\n\n    def test_is_exception_class(self):\n        class E(Exception):\n            pass\n        self.assertEqual(self._callFUT(E), True)\n\n    def test_is_IException(self):\n        from pyramid.interfaces import IException\n        self.assertEqual(self._callFUT(IException), True)\n\n    def test_is_IException_subinterface(self):\n        from pyramid.interfaces import IException\n        class ISubException(IException):\n            pass\n        self.assertEqual(self._callFUT(ISubException), True)\n\nclass TestMultiView(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import MultiView\n        return MultiView\n\n    def _makeOne(self, name='name'):\n        return self._getTargetClass()(name)\n\n    def test_class_implements_ISecuredView(self):\n        from zope.interface.verify import verifyClass\n        from pyramid.interfaces import ISecuredView\n        verifyClass(ISecuredView, self._getTargetClass())\n\n    def test_instance_implements_ISecuredView(self):\n        from zope.interface.verify import verifyObject\n        from pyramid.interfaces import ISecuredView\n        verifyObject(ISecuredView, self._makeOne())\n\n    def test_add(self):\n        mv = self._makeOne()\n        mv.add('view', 100)\n        self.assertEqual(mv.views, [(100, 'view', None)])\n        mv.add('view2', 99)\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view3', 100, 'text/html')\n        self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])\n        mv.add('view4', 99, 'text/html', 'abc')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, 'view4', 'abc'), (100, 'view3', None)])\n        mv.add('view5', 100, 'text/xml')\n        self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])\n        self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view6', 98, 'text/*')\n        self.assertEqual(mv.views, [(98, 'view6', None),\n                                    (99, 'view2', None),\n                                    (100, 'view', None)])\n\n    def test_add_with_phash(self):\n        mv = self._makeOne()\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='def')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n\n    def test_add_with_phash_override_accept(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='abc')\n        mv.add(view3, 99, accept='text/html', phash='def')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'def'), (100, view2, 'abc')])\n\n    def test_add_with_phash_override_accept2(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='def')\n        mv.add(view3, 99, accept='text/html', phash='ghi')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'ghi'),\n                          (100, view1, 'abc'),\n                          (100, view2, 'def')]\n                         )\n\n    def test_multiple_with_functions_as_views(self):\n        # this failed on py3 at one point, because functions aren't orderable\n        # and we were sorting the views via a plain sort() rather than\n        # sort(key=itemgetter(0)).\n        def view1(request): pass\n        def view2(request): pass\n        mv = self._makeOne()\n        mv.add(view1, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None)])\n        mv.add(view2, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None), (100, view2, None)])\n\n    def test_get_views_request_has_no_accept(self):\n        request = DummyRequest()\n        mv = self._makeOne()\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views_no_self_accepts(self):\n        request = DummyRequest()\n        request.accept = True\n        mv = self._makeOne()\n        mv.accepts = []\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views(self):\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        html_views = [(98, lambda *arg: None)]\n        mv.media_views['text/html'] = html_views\n        self.assertEqual(mv.get_views(request), html_views + mv.views)\n\n    def test_get_views_best_match_returns_None(self):\n        request = DummyRequest()\n        request.accept = DummyAccept(None)\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_match_not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_fails(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: False\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_succeeds(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: True\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.match(context, request)\n        self.assertEqual(result, view)\n\n    def test_permitted_no_views(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.__permitted__, context, request)\n\n    def test_permitted_no_match_with__permitted__(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view, None)]\n        self.assertEqual(mv.__permitted__(None, None), True)\n\n    def test_permitted(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permitted(context, request):\n            return False\n        view.__permitted__ = permitted\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.__permitted__(context, request)\n        self.assertEqual(result, False)\n\n    def test__call__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__intermediate_not_found(self):\n        from pyramid.exceptions import PredicateMismatch\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view1(context, request):\n            raise PredicateMismatch\n        def view2(context, request):\n            return expected_response\n        mv.views = [(100, view1, None), (99, view2, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        def view1(context, request):\n            raise  HTTPNotFound\n        def view2(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view1, None), (99, view2, None)]\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call_permissive__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call_permissive_has_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permissive(context, request):\n            return expected_response\n        view.__call_permissive__ = permissive\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call_permissive_has_no_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_match(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/xml')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, None)]\n        mv.media_views['text/xml'] = [(100, view, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_miss(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/plain', 'text/html')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        mv.media_views['text/xml'] = [(100, None, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n\n\nclass TestDefaultViewMapper(unittest.TestCase):\n    def setUp(self):\n        self.config = testing.setUp()\n        self.registry = self.config.registry\n\n    def tearDown(self):\n        del self.registry\n        testing.tearDown()\n\n    def _makeOne(self, **kw):\n        from pyramid.config.views import DefaultViewMapper\n        kw['registry'] = self.registry\n        return DefaultViewMapper(**kw)\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = self.registry\n        return request\n\n    def test_view_as_function_context_and_request(self):\n        def view(context, request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test__view_as_function_with_attr(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_function_requestonly(self):\n        def view(request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_function_requestonly_with_attr(self):\n        def view(request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_newstyle_class_context_and_request(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_context_and_request_with_attr(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly_with_attr(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request_with_attr(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly_with_attr(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request(self):\n        class View:\n            def __call__(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request_and_attr(self):\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly(self):\n        class View:\n            def __call__(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly_with_attr(self):\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\nclass Test_preserve_view_attrs(unittest.TestCase):\n    def _callFUT(self, view, wrapped_view):\n        from pyramid.config.views import preserve_view_attrs\n        return preserve_view_attrs(view, wrapped_view)\n\n    def test_it_same(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(view, view)\n        self.assertTrue(result is view)\n\n    def test_it_view_is_None(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(None, view)\n        self.assertTrue(result is view)\n\n    def test_it_different_with_existing_original_view(self):\n        def view1(context, request): pass\n        view1.__original_view__ = 'abc'\n        def view2(context, request): pass\n        result = self._callFUT(view1, view2)\n        self.assertEqual(result.__original_view__, 'abc')\n        self.assertFalse(result is view1)\n\n    def test_it_different(self):\n        class DummyView1:\n            \"\"\" 1 \"\"\"\n            __name__ = '1'\n            __module__ = '1'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        class DummyView2:\n            \"\"\" 2 \"\"\"\n            __name__ = '2'\n            __module__ = '2'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        view1 = DummyView1()\n        view2 = DummyView2()\n        result = self._callFUT(view2, view1)\n        self.assertEqual(result, view1)\n        self.assertTrue(view1.__original_view__ is view2)\n        self.assertTrue(view1.__doc__ is view2.__doc__)\n        self.assertTrue(view1.__module__ is view2.__module__)\n        self.assertTrue(view1.__name__ is view2.__name__)\n        self.assertTrue(getattr(view1.__call_permissive__, im_func) is\n                        getattr(view2.__call_permissive__, im_func))\n        self.assertTrue(getattr(view1.__permitted__, im_func) is\n                        getattr(view2.__permitted__, im_func))\n        self.assertTrue(getattr(view1.__predicated__, im_func) is\n                        getattr(view2.__predicated__, im_func))\n\n\nclass TestStaticURLInfo(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import StaticURLInfo\n        return StaticURLInfo\n\n    def _makeOne(self):\n        return self._getTargetClass()()\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = DummyRegistry()\n        return request\n\n    def test_verifyClass(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyClass\n        verifyClass(IStaticURLInfo, self._getTargetClass())\n\n    def test_verifyObject(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyObject\n        verifyObject(IStaticURLInfo, self._makeOne())\n\n    def test_generate_missing(self):\n        inst = self._makeOne()\n        request = self._makeRequest()\n        self.assertRaises(ValueError, inst.generate, 'path', request)\n\n    def test_generate_registration_miss(self):\n        inst = self._makeOne()\n        inst.registrations = [\n            (None, 'spec', 'route_name'),\n            ('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name1(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name2(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/', request)\n        self.assertEqual(result, 'http://example.com/foo/')\n\n    def test_generate_quoting(self):\n        from pyramid.interfaces import IStaticURLInfo\n        config = testing.setUp()\n        try:\n            config.add_static_view('images', path='mypkg:templates')\n            request = testing.DummyRequest()\n            request.registry = config.registry\n            inst = config.registry.getUtility(IStaticURLInfo)\n            result = inst.generate('mypkg:templates/foo%2Fbar', request)\n            self.assertEqual(result, 'http://example.com/images/foo%252Fbar')\n        finally:\n            testing.tearDown()\n\n    def test_generate_route_url(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_unquoted_local(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc def', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_quoted_remote(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'http://example.com/abc%20def')\n\n    def test_generate_url_with_custom_query(self):\n        inst = self._makeOne()\n        registrations = [('http://example.com/', 'package:path/', None)]\n        inst.registrations = registrations\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1,\n                               _query='(openlayers)')\n        self.assertEqual(result,\n                         'http://example.com/abc%20def?(openlayers)')\n\n    def test_generate_url_with_custom_anchor(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        uc = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        result = inst.generate('package:path/abc def', request, a=1, _anchor=uc)\n        self.assertEqual(result,\n                         'http://example.com/abc%20def#La%20Pe%C3%B1a')\n\n    def test_generate_url_cachebust(self):\n        def cachebust(request, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path/', cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_abspath(self):\n        here = os.path.dirname(__file__) + os.sep\n        def cachebust(pathspec, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, here, '__viewname')]\n        inst.cache_busters = [(here, cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': here + 'abc',\n                                  'rawspec': here + 'abc'})\n        request.route_url = route_url\n        inst.generate(here + 'abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_nomatch(self):\n        def fake_cb(*a, **kw): raise AssertionError\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path2/', fake_cb, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'abc',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\n        finally:\n            testing.tearDown()\n\n    def test_add_already_exists(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_package_root(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'package:')\n        expected = [('http://example.com/', 'package:', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_withendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com/', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noscheme(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, '//example.com', 'anotherpackage:path')\n        expected = [('//example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_viewname(self):\n        from pyramid.security import NO_PERMISSION_REQUIRED\n        from pyramid.static import static_view\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1)\n        expected = [(None, 'anotherpackage:path/', '__view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__view/', 'view/*subpath'))\n        self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED)\n        self.assertEqual(config.view_kw['view'].__class__, static_view)\n\n    def test_add_viewname_with_route_prefix(self):\n        config = DummyConfig()\n        config.route_prefix = '/abc'\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path',)\n        expected = [(None, 'anotherpackage:path/', '__/abc/view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__/abc/view/', 'view/*subpath'))\n\n    def test_add_viewname_with_permission(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 permission='abc')\n        self.assertEqual(config.view_kw['permission'], 'abc')\n\n    def test_add_viewname_with_context(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 context=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_for_(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 for_=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_renderer(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 renderer='mypackage:templates/index.pt')\n        self.assertEqual(config.view_kw['renderer'],\n                         'mypackage:templates/index.pt')\n\n    def test_add_cachebust_prevented(self):\n        config = DummyConfig()\n        config.registry.settings['pyramid.prevent_cachebust'] = True\n        inst = self._makeOne()\n        cachebust = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, 'mypackage:path', cachebust)\n        self.assertEqual(inst.cache_busters, [])\n\n    def test_add_cachebuster(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add_cache_buster(config, 'mypackage:path', DummyCacheBuster('foo'))\n        cachebust = inst.cache_busters[-1][1]\n        subpath, kw = cachebust(None, 'some/path', {})\n        self.assertEqual(subpath, 'some/path')\n        self.assertEqual(kw['x'], 'foo')\n\n    def test_add_cachebuster_abspath(self):\n        here = os.path.dirname(__file__)\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, here, cb)\n        self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)])\n\n    def test_add_cachebuster_overwrite(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb2, False)])\n\n    def test_add_cachebuster_overwrite_explicit(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2, True)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb1, False),\n                          ('mypackage:path/', cb2, True)])\n\n    def test_add_cachebuster_for_more_specific_path(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        cb3 = DummyCacheBuster('baz')\n        cb4 = DummyCacheBuster('xyz')\n        cb5 = DummyCacheBuster('w')\n        inst.add_cache_buster(config, 'mypackage:path', cb1)\n        inst.add_cache_buster(config, 'mypackage:path/sub', cb2, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb3)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb4, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/less', cb5, True)\n        self.assertEqual(\n            inst.cache_busters,\n            [('mypackage:path/', cb1, False),\n             ('mypackage:path/sub/other/', cb3, False),\n             ('mypackage:path/sub/', cb2, True),\n             ('mypackage:path/sub/less/', cb5, True),\n             ('mypackage:path/sub/other/', cb4, True)])\n\nclass Test_view_description(unittest.TestCase):\n    def _callFUT(self, view):\n        from pyramid.config.views import view_description\n        return view_description(view)\n\n    def test_with_text(self):\n        def view(): pass\n        view.__text__ = 'some text'\n        result = self._callFUT(view)\n        self.assertEqual(result, 'some text')\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n        self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\n\n\nclass DummyRegistry:\n    utility = None\n\n    def __init__(self):\n        self.settings = {}\n\n    def queryUtility(self, type_or_iface, name=None, default=None):\n        return self.utility or default\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import (\n    IResponse,\n    IRequest,\n    )\n\n@implementer(IResponse)\nclass DummyResponse(object):\n    content_type = None\n    default_content_type = None\n    body = None\n\nclass DummyRequest:\n    subpath = ()\n    matchdict = None\n    request_iface  = IRequest\n\n    def __init__(self, environ=None):\n        if environ is None:\n            environ = {}\n        self.environ = environ\n        self.params = {}\n        self.cookies = {}\n        self.response = DummyResponse()\n\nclass DummyContext:\n    pass\n\nclass DummyAccept(object):\n    def __init__(self, *matches):\n        self.matches = list(matches)\n\n    def best_match(self, offered):\n        if self.matches:\n            for match in self.matches:\n                if match in offered:\n                    self.matches.remove(match)\n                    return match\n    def __contains__(self, val):\n        return val in self.matches\n\nclass DummyConfig:\n    def __init__(self):\n        self.registry = DummyRegistry()\n\n    route_prefix = ''\n    def add_route(self, *args, **kw):\n        self.route_args = args\n        self.route_kw = kw\n\n    def add_view(self, *args, **kw):\n        self.view_args = args\n        self.view_kw = kw\n\n    def action(self, discriminator, callable, introspectables=()):\n        callable()\n\n    def introspectable(self, *arg):\n        return {}\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import IMultiView\n@implementer(IMultiView)\nclass DummyMultiView:\n    def __init__(self):\n        self.views = []\n        self.name = 'name'\n    def add(self, view, order, accept=None, phash=None):\n        self.views.append((view, accept, phash))\n    def __call__(self, context, request):\n        return 'OK1'\n    def __permitted__(self, context, request):\n        \"\"\" \"\"\"\n\nclass DummyCacheBuster(object):\n    def __init__(self, token):\n        self.token = token\n\n    def __call__(self, request, subpath, kw):\n        kw['x'] = self.token\n        return subpath, kw\n\ndef parse_httpdate(s):\n    import datetime\n    # cannot use %Z, must use literal GMT; Jython honors timezone\n    # but CPython does not\n    return datetime.datetime.strptime(s, \"%a, %d %b %Y %H:%M:%S GMT\")\n\ndef assert_similar_datetime(one, two):\n    for attr in ('year', 'month', 'day', 'hour', 'minute'):\n        one_attr = getattr(one, attr)\n        two_attr = getattr(two, attr)\n        if not one_attr == two_attr: # pragma: no cover\n            raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr))\n\nclass DummyStaticURLInfo:\n    def __init__(self):\n        self.added = []\n\n    def add(self, config, name, spec, **kw):\n        self.added.append((config, name, spec, kw))\n\nclass DummyViewDefaultsClass(object):\n    __view_defaults__ = {\n        'containment':'pyramid.tests.test_config.IDummy'\n        }\n    def __init__(self, request):\n        pass\n    def __call__(self):\n        return 'OK'\n\nclass DummyPredicate(object):\n    def __init__(self, val, config):\n        self.val = val\n\n    def text(self):\n        return 'dummy'\n\n    phash = text\n\nclass DummyIntrospector(object):\n    def __init__(self, getval=None):\n        self.related = []\n        self.introspectables = []\n        self.getval = getval\n    def add(self, introspectable):\n        self.introspectables.append(introspectable)\n    def get(self, name, discrim):\n        return self.getval\n    def relate(self, a, b):\n        self.related.append((a, b))\n\nclass DummySession(dict):\n    def get_csrf_token(self):\n        return self['csrf_token']\n",
            "new_file_content": "import os\nimport unittest\nfrom pyramid import testing\n\nfrom pyramid.tests.test_config import IDummy\n\nfrom pyramid.tests.test_config import dummy_view\n\nfrom pyramid.compat import (\n    im_func,\n    text_,\n    )\nfrom pyramid.exceptions import ConfigurationError\nfrom pyramid.exceptions import ConfigurationExecutionError\nfrom pyramid.exceptions import ConfigurationConflictError\n\nclass TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)\n\nclass Test_requestonly(unittest.TestCase):\n    def _callFUT(self, view, attr=None):\n        from pyramid.config.views import requestonly\n        return requestonly(view, attr=attr)\n\n    def test_defaults(self):\n        def aview(request, a=1, b=2): pass\n        self.assertTrue(self._callFUT(aview))\n\n    def test_otherattr(self):\n        class AView(object):\n            def __init__(self, request, a=1, b=2): pass\n            def bleh(self): pass\n        self.assertTrue(self._callFUT(AView, 'bleh'))\n\nclass Test_isexception(unittest.TestCase):\n    def _callFUT(self, ob):\n        from pyramid.config.views import isexception\n        return isexception(ob)\n\n    def test_is_exception_instance(self):\n        class E(Exception):\n            pass\n        e = E()\n        self.assertEqual(self._callFUT(e), True)\n\n    def test_is_exception_class(self):\n        class E(Exception):\n            pass\n        self.assertEqual(self._callFUT(E), True)\n\n    def test_is_IException(self):\n        from pyramid.interfaces import IException\n        self.assertEqual(self._callFUT(IException), True)\n\n    def test_is_IException_subinterface(self):\n        from pyramid.interfaces import IException\n        class ISubException(IException):\n            pass\n        self.assertEqual(self._callFUT(ISubException), True)\n\nclass TestMultiView(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import MultiView\n        return MultiView\n\n    def _makeOne(self, name='name'):\n        return self._getTargetClass()(name)\n\n    def test_class_implements_ISecuredView(self):\n        from zope.interface.verify import verifyClass\n        from pyramid.interfaces import ISecuredView\n        verifyClass(ISecuredView, self._getTargetClass())\n\n    def test_instance_implements_ISecuredView(self):\n        from zope.interface.verify import verifyObject\n        from pyramid.interfaces import ISecuredView\n        verifyObject(ISecuredView, self._makeOne())\n\n    def test_add(self):\n        mv = self._makeOne()\n        mv.add('view', 100)\n        self.assertEqual(mv.views, [(100, 'view', None)])\n        mv.add('view2', 99)\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view3', 100, 'text/html')\n        self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])\n        mv.add('view4', 99, 'text/html', 'abc')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, 'view4', 'abc'), (100, 'view3', None)])\n        mv.add('view5', 100, 'text/xml')\n        self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])\n        self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view6', 98, 'text/*')\n        self.assertEqual(mv.views, [(98, 'view6', None),\n                                    (99, 'view2', None),\n                                    (100, 'view', None)])\n\n    def test_add_with_phash(self):\n        mv = self._makeOne()\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='def')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n\n    def test_add_with_phash_override_accept(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='abc')\n        mv.add(view3, 99, accept='text/html', phash='def')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'def'), (100, view2, 'abc')])\n\n    def test_add_with_phash_override_accept2(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='def')\n        mv.add(view3, 99, accept='text/html', phash='ghi')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'ghi'),\n                          (100, view1, 'abc'),\n                          (100, view2, 'def')]\n                         )\n\n    def test_multiple_with_functions_as_views(self):\n        # this failed on py3 at one point, because functions aren't orderable\n        # and we were sorting the views via a plain sort() rather than\n        # sort(key=itemgetter(0)).\n        def view1(request): pass\n        def view2(request): pass\n        mv = self._makeOne()\n        mv.add(view1, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None)])\n        mv.add(view2, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None), (100, view2, None)])\n\n    def test_get_views_request_has_no_accept(self):\n        request = DummyRequest()\n        mv = self._makeOne()\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views_no_self_accepts(self):\n        request = DummyRequest()\n        request.accept = True\n        mv = self._makeOne()\n        mv.accepts = []\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views(self):\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        html_views = [(98, lambda *arg: None)]\n        mv.media_views['text/html'] = html_views\n        self.assertEqual(mv.get_views(request), html_views + mv.views)\n\n    def test_get_views_best_match_returns_None(self):\n        request = DummyRequest()\n        request.accept = DummyAccept(None)\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_match_not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_fails(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: False\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_succeeds(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: True\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.match(context, request)\n        self.assertEqual(result, view)\n\n    def test_permitted_no_views(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.__permitted__, context, request)\n\n    def test_permitted_no_match_with__permitted__(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view, None)]\n        self.assertEqual(mv.__permitted__(None, None), True)\n\n    def test_permitted(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permitted(context, request):\n            return False\n        view.__permitted__ = permitted\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.__permitted__(context, request)\n        self.assertEqual(result, False)\n\n    def test__call__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__intermediate_not_found(self):\n        from pyramid.exceptions import PredicateMismatch\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view1(context, request):\n            raise PredicateMismatch\n        def view2(context, request):\n            return expected_response\n        mv.views = [(100, view1, None), (99, view2, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        def view1(context, request):\n            raise  HTTPNotFound\n        def view2(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view1, None), (99, view2, None)]\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call_permissive__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call_permissive_has_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permissive(context, request):\n            return expected_response\n        view.__call_permissive__ = permissive\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call_permissive_has_no_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_match(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/xml')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, None)]\n        mv.media_views['text/xml'] = [(100, view, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_miss(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/plain', 'text/html')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        mv.media_views['text/xml'] = [(100, None, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n\n\nclass TestDefaultViewMapper(unittest.TestCase):\n    def setUp(self):\n        self.config = testing.setUp()\n        self.registry = self.config.registry\n\n    def tearDown(self):\n        del self.registry\n        testing.tearDown()\n\n    def _makeOne(self, **kw):\n        from pyramid.config.views import DefaultViewMapper\n        kw['registry'] = self.registry\n        return DefaultViewMapper(**kw)\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = self.registry\n        return request\n\n    def test_view_as_function_context_and_request(self):\n        def view(context, request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test__view_as_function_with_attr(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_function_requestonly(self):\n        def view(request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_function_requestonly_with_attr(self):\n        def view(request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_newstyle_class_context_and_request(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_context_and_request_with_attr(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly_with_attr(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request_with_attr(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly_with_attr(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request(self):\n        class View:\n            def __call__(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request_and_attr(self):\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly(self):\n        class View:\n            def __call__(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly_with_attr(self):\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\nclass Test_preserve_view_attrs(unittest.TestCase):\n    def _callFUT(self, view, wrapped_view):\n        from pyramid.config.views import preserve_view_attrs\n        return preserve_view_attrs(view, wrapped_view)\n\n    def test_it_same(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(view, view)\n        self.assertTrue(result is view)\n\n    def test_it_view_is_None(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(None, view)\n        self.assertTrue(result is view)\n\n    def test_it_different_with_existing_original_view(self):\n        def view1(context, request): pass\n        view1.__original_view__ = 'abc'\n        def view2(context, request): pass\n        result = self._callFUT(view1, view2)\n        self.assertEqual(result.__original_view__, 'abc')\n        self.assertFalse(result is view1)\n\n    def test_it_different(self):\n        class DummyView1:\n            \"\"\" 1 \"\"\"\n            __name__ = '1'\n            __module__ = '1'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        class DummyView2:\n            \"\"\" 2 \"\"\"\n            __name__ = '2'\n            __module__ = '2'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        view1 = DummyView1()\n        view2 = DummyView2()\n        result = self._callFUT(view2, view1)\n        self.assertEqual(result, view1)\n        self.assertTrue(view1.__original_view__ is view2)\n        self.assertTrue(view1.__doc__ is view2.__doc__)\n        self.assertTrue(view1.__module__ is view2.__module__)\n        self.assertTrue(view1.__name__ is view2.__name__)\n        self.assertTrue(getattr(view1.__call_permissive__, im_func) is\n                        getattr(view2.__call_permissive__, im_func))\n        self.assertTrue(getattr(view1.__permitted__, im_func) is\n                        getattr(view2.__permitted__, im_func))\n        self.assertTrue(getattr(view1.__predicated__, im_func) is\n                        getattr(view2.__predicated__, im_func))\n\n\nclass TestStaticURLInfo(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import StaticURLInfo\n        return StaticURLInfo\n\n    def _makeOne(self):\n        return self._getTargetClass()()\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = DummyRegistry()\n        return request\n\n    def test_verifyClass(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyClass\n        verifyClass(IStaticURLInfo, self._getTargetClass())\n\n    def test_verifyObject(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyObject\n        verifyObject(IStaticURLInfo, self._makeOne())\n\n    def test_generate_missing(self):\n        inst = self._makeOne()\n        request = self._makeRequest()\n        self.assertRaises(ValueError, inst.generate, 'path', request)\n\n    def test_generate_registration_miss(self):\n        inst = self._makeOne()\n        inst.registrations = [\n            (None, 'spec', 'route_name'),\n            ('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name1(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name2(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/', request)\n        self.assertEqual(result, 'http://example.com/foo/')\n\n    def test_generate_quoting(self):\n        from pyramid.interfaces import IStaticURLInfo\n        config = testing.setUp()\n        try:\n            config.add_static_view('images', path='mypkg:templates')\n            request = testing.DummyRequest()\n            request.registry = config.registry\n            inst = config.registry.getUtility(IStaticURLInfo)\n            result = inst.generate('mypkg:templates/foo%2Fbar', request)\n            self.assertEqual(result, 'http://example.com/images/foo%252Fbar')\n        finally:\n            testing.tearDown()\n\n    def test_generate_route_url(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_unquoted_local(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc def', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_quoted_remote(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'http://example.com/abc%20def')\n\n    def test_generate_url_with_custom_query(self):\n        inst = self._makeOne()\n        registrations = [('http://example.com/', 'package:path/', None)]\n        inst.registrations = registrations\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1,\n                               _query='(openlayers)')\n        self.assertEqual(result,\n                         'http://example.com/abc%20def?(openlayers)')\n\n    def test_generate_url_with_custom_anchor(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        uc = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        result = inst.generate('package:path/abc def', request, a=1, _anchor=uc)\n        self.assertEqual(result,\n                         'http://example.com/abc%20def#La%20Pe%C3%B1a')\n\n    def test_generate_url_cachebust(self):\n        def cachebust(request, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path/', cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_abspath(self):\n        here = os.path.dirname(__file__) + os.sep\n        def cachebust(pathspec, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, here, '__viewname')]\n        inst.cache_busters = [(here, cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': here + 'abc',\n                                  'rawspec': here + 'abc'})\n        request.route_url = route_url\n        inst.generate(here + 'abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_nomatch(self):\n        def fake_cb(*a, **kw): raise AssertionError\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path2/', fake_cb, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'abc',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\n        finally:\n            testing.tearDown()\n\n    def test_add_already_exists(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_package_root(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'package:')\n        expected = [('http://example.com/', 'package:', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_withendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com/', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noscheme(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, '//example.com', 'anotherpackage:path')\n        expected = [('//example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_viewname(self):\n        from pyramid.security import NO_PERMISSION_REQUIRED\n        from pyramid.static import static_view\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1)\n        expected = [(None, 'anotherpackage:path/', '__view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__view/', 'view/*subpath'))\n        self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED)\n        self.assertEqual(config.view_kw['view'].__class__, static_view)\n\n    def test_add_viewname_with_route_prefix(self):\n        config = DummyConfig()\n        config.route_prefix = '/abc'\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path',)\n        expected = [(None, 'anotherpackage:path/', '__/abc/view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__/abc/view/', 'view/*subpath'))\n\n    def test_add_viewname_with_permission(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 permission='abc')\n        self.assertEqual(config.view_kw['permission'], 'abc')\n\n    def test_add_viewname_with_context(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 context=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_for_(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 for_=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_renderer(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 renderer='mypackage:templates/index.pt')\n        self.assertEqual(config.view_kw['renderer'],\n                         'mypackage:templates/index.pt')\n\n    def test_add_cachebust_prevented(self):\n        config = DummyConfig()\n        config.registry.settings['pyramid.prevent_cachebust'] = True\n        inst = self._makeOne()\n        cachebust = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, 'mypackage:path', cachebust)\n        self.assertEqual(inst.cache_busters, [])\n\n    def test_add_cachebuster(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add_cache_buster(config, 'mypackage:path', DummyCacheBuster('foo'))\n        cachebust = inst.cache_busters[-1][1]\n        subpath, kw = cachebust(None, 'some/path', {})\n        self.assertEqual(subpath, 'some/path')\n        self.assertEqual(kw['x'], 'foo')\n\n    def test_add_cachebuster_abspath(self):\n        here = os.path.dirname(__file__)\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, here, cb)\n        self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)])\n\n    def test_add_cachebuster_overwrite(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb2, False)])\n\n    def test_add_cachebuster_overwrite_explicit(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2, True)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb1, False),\n                          ('mypackage:path/', cb2, True)])\n\n    def test_add_cachebuster_for_more_specific_path(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        cb3 = DummyCacheBuster('baz')\n        cb4 = DummyCacheBuster('xyz')\n        cb5 = DummyCacheBuster('w')\n        inst.add_cache_buster(config, 'mypackage:path', cb1)\n        inst.add_cache_buster(config, 'mypackage:path/sub', cb2, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb3)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb4, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/less', cb5, True)\n        self.assertEqual(\n            inst.cache_busters,\n            [('mypackage:path/', cb1, False),\n             ('mypackage:path/sub/other/', cb3, False),\n             ('mypackage:path/sub/', cb2, True),\n             ('mypackage:path/sub/less/', cb5, True),\n             ('mypackage:path/sub/other/', cb4, True)])\n\nclass Test_view_description(unittest.TestCase):\n    def _callFUT(self, view):\n        from pyramid.config.views import view_description\n        return view_description(view)\n\n    def test_with_text(self):\n        def view(): pass\n        view.__text__ = 'some text'\n        result = self._callFUT(view)\n        self.assertEqual(result, 'some text')\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n        self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\n\n\nclass DummyRegistry:\n    utility = None\n\n    def __init__(self):\n        self.settings = {}\n\n    def queryUtility(self, type_or_iface, name=None, default=None):\n        return self.utility or default\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import (\n    IResponse,\n    IRequest,\n    )\n\n@implementer(IResponse)\nclass DummyResponse(object):\n    content_type = None\n    default_content_type = None\n    body = None\n\nclass DummyRequest:\n    subpath = ()\n    matchdict = None\n    request_iface  = IRequest\n\n    def __init__(self, environ=None):\n        if environ is None:\n            environ = {}\n        self.environ = environ\n        self.params = {}\n        self.cookies = {}\n        self.response = DummyResponse()\n\nclass DummyContext:\n    pass\n\nclass DummyAccept(object):\n    def __init__(self, *matches):\n        self.matches = list(matches)\n\n    def best_match(self, offered):\n        if self.matches:\n            for match in self.matches:\n                if match in offered:\n                    self.matches.remove(match)\n                    return match\n    def __contains__(self, val):\n        return val in self.matches\n\nclass DummyConfig:\n    def __init__(self):\n        self.registry = DummyRegistry()\n\n    route_prefix = ''\n    def add_route(self, *args, **kw):\n        self.route_args = args\n        self.route_kw = kw\n\n    def add_view(self, *args, **kw):\n        self.view_args = args\n        self.view_kw = kw\n\n    def action(self, discriminator, callable, introspectables=()):\n        callable()\n\n    def introspectable(self, *arg):\n        return {}\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import IMultiView\n@implementer(IMultiView)\nclass DummyMultiView:\n    def __init__(self):\n        self.views = []\n        self.name = 'name'\n    def add(self, view, order, accept=None, phash=None):\n        self.views.append((view, accept, phash))\n    def __call__(self, context, request):\n        return 'OK1'\n    def __permitted__(self, context, request):\n        \"\"\" \"\"\"\n\nclass DummyCacheBuster(object):\n    def __init__(self, token):\n        self.token = token\n\n    def __call__(self, request, subpath, kw):\n        kw['x'] = self.token\n        return subpath, kw\n\ndef parse_httpdate(s):\n    import datetime\n    # cannot use %Z, must use literal GMT; Jython honors timezone\n    # but CPython does not\n    return datetime.datetime.strptime(s, \"%a, %d %b %Y %H:%M:%S GMT\")\n\ndef assert_similar_datetime(one, two):\n    for attr in ('year', 'month', 'day', 'hour', 'minute'):\n        one_attr = getattr(one, attr)\n        two_attr = getattr(two, attr)\n        if not one_attr == two_attr: # pragma: no cover\n            raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr))\n\nclass DummyStaticURLInfo:\n    def __init__(self):\n        self.added = []\n\n    def add(self, config, name, spec, **kw):\n        self.added.append((config, name, spec, kw))\n\nclass DummyViewDefaultsClass(object):\n    __view_defaults__ = {\n        'containment':'pyramid.tests.test_config.IDummy'\n        }\n    def __init__(self, request):\n        pass\n    def __call__(self):\n        return 'OK'\n\nclass DummyPredicate(object):\n    def __init__(self, val, config):\n        self.val = val\n\n    def text(self):\n        return 'dummy'\n\n    phash = text\n\nclass DummyIntrospector(object):\n    def __init__(self, getval=None):\n        self.related = []\n        self.introspectables = []\n        self.getval = getval\n    def add(self, introspectable):\n        self.introspectables.append(introspectable)\n    def get(self, name, discrim):\n        return self.getval\n    def relate(self, a, b):\n        self.related.append((a, b))\n\nclass DummySession(dict):\n    def get_csrf_token(self):\n        return self['csrf_token']\n",
            "header": {
                "file": {
                    "path": "pyramid/tests/test_config/test_views.py"
                },
                "misc_line": null
            },
            "index_line": {
                "old_commit_hash": "878574e88",
                "new_commit_hash": "c93175ff9",
                "mode": "100644"
            },
            "is_binary_file": false,
            "binary_line": null,
            "minus_file": {
                "path": "a/pyramid/tests/test_config/test_views.py"
            },
            "plus_file": {
                "path": "b/pyramid/tests/test_config/test_views.py"
            },
            "hunks": [
                {
                    "descriptor": {
                        "old_range": {
                            "start": 1815,
                            "length": 6
                        },
                        "new_range": {
                            "start": 1815,
                            "length": 38
                        },
                        "section": "class TestViewsConfigurationMixin(unittest.TestCase):"
                    },
                    "line_group": {
                        "all_lines": [
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "        self.assertRaises(ConfigurationError, configure_view)",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            },
                            {
                                "content": "    def test_add_view_exception_only_no_regular_view(self):",
                                "type": "added"
                            },
                            {
                                "content": "        from zope.interface import implementedBy",
                                "type": "added"
                            },
                            {
                                "content": "        from pyramid.renderers import null_renderer",
                                "type": "added"
                            },
                            {
                                "content": "        view1 = lambda *arg: 'OK'",
                                "type": "added"
                            },
                            {
                                "content": "        config = self._makeOne(autocommit=True)",
                                "type": "added"
                            },
                            {
                                "content": "        config.add_view(view=view1, context=Exception, renderer=null_renderer,",
                                "type": "added"
                            },
                            {
                                "content": "                        exception_only=True)",
                                "type": "added"
                            },
                            {
                                "content": "        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertTrue(view is None)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_add_view_exception_only(self):",
                                "type": "added"
                            },
                            {
                                "content": "        from zope.interface import implementedBy",
                                "type": "added"
                            },
                            {
                                "content": "        from pyramid.renderers import null_renderer",
                                "type": "added"
                            },
                            {
                                "content": "        view1 = lambda *arg: 'OK'",
                                "type": "added"
                            },
                            {
                                "content": "        config = self._makeOne(autocommit=True)",
                                "type": "added"
                            },
                            {
                                "content": "        config.add_view(view=view1, context=Exception, renderer=null_renderer,",
                                "type": "added"
                            },
                            {
                                "content": "                        exception_only=True)",
                                "type": "added"
                            },
                            {
                                "content": "        view = self._getViewCallable(",
                                "type": "added"
                            },
                            {
                                "content": "            config, ctx_iface=implementedBy(Exception), exception_view=True",
                                "type": "added"
                            },
                            {
                                "content": "            )",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertEqual(view1, view)",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_add_view_exception_only_misconfiguration(self):",
                                "type": "added"
                            },
                            {
                                "content": "        view = lambda *arg: 'OK'",
                                "type": "added"
                            },
                            {
                                "content": "        config = self._makeOne(autocommit=True)",
                                "type": "added"
                            },
                            {
                                "content": "        class NotAnException(object):",
                                "type": "added"
                            },
                            {
                                "content": "            pass",
                                "type": "added"
                            },
                            {
                                "content": "        self.assertRaises(",
                                "type": "added"
                            },
                            {
                                "content": "            ConfigurationError,",
                                "type": "added"
                            },
                            {
                                "content": "            config.add_view, view, context=NotAnException, exception_only=True",
                                "type": "added"
                            },
                            {
                                "content": "            )",
                                "type": "added"
                            },
                            {
                                "content": "",
                                "type": "added"
                            },
                            {
                                "content": "    def test_derive_view_function(self):",
                                "type": "context"
                            },
                            {
                                "content": "        from pyramid.renderers import null_renderer",
                                "type": "context"
                            },
                            {
                                "content": "        def view(request):",
                                "type": "context"
                            },
                            {
                                "content": "",
                                "type": "context"
                            }
                        ]
                    },
                    "modified_entities": [
                        {
                            "file_name": "pyramid/tests/test_config/test_views.py",
                            "type": "class",
                            "name": "TestViewsConfigurationMixin",
                            "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 17,
                            "end_lineno": 2236,
                            "parent": null
                        }
                    ],
                    "added_entities": [
                        {
                            "file_name": "pyramid/tests/test_config/test_views.py",
                            "type": "method",
                            "name": "TestViewsConfigurationMixin.test_add_view_exception_only_no_regular_view",
                            "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 1818,
                            "end_lineno": 1826,
                            "parent": {
                                "file_name": "pyramid/tests/test_config/test_views.py",
                                "type": "class",
                                "name": "TestViewsConfigurationMixin",
                                "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 17,
                                "end_lineno": 2236,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/tests/test_config/test_views.py",
                            "type": "method",
                            "name": "TestViewsConfigurationMixin.test_add_view_exception_only_misconfiguration",
                            "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 1840,
                            "end_lineno": 1848,
                            "parent": {
                                "file_name": "pyramid/tests/test_config/test_views.py",
                                "type": "class",
                                "name": "TestViewsConfigurationMixin",
                                "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 17,
                                "end_lineno": 2236,
                                "parent": null
                            }
                        },
                        {
                            "file_name": "pyramid/tests/test_config/test_views.py",
                            "type": "method",
                            "name": "TestViewsConfigurationMixin.test_add_view_exception_only",
                            "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                            "ast_type_str": "ClassDef",
                            "start_lineno": 1828,
                            "end_lineno": 1838,
                            "parent": {
                                "file_name": "pyramid/tests/test_config/test_views.py",
                                "type": "class",
                                "name": "TestViewsConfigurationMixin",
                                "content": "class TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)",
                                "ast_type_str": "ClassDef",
                                "start_lineno": 17,
                                "end_lineno": 2236,
                                "parent": null
                            }
                        }
                    ],
                    "deleted_entities": []
                }
            ]
        }
    ],
    "old_commit_hash": "b0d20b5c3fe7df472633899024cdab685483807a^",
    "new_commit_hash": "b0d20b5c3fe7df472633899024cdab685483807a",
    "commit_message": "add exception_only argument to add_view to only register exception views.",
    "commit_date": "2016-06-02T14:50:53-07:00",
    "metadata": {}
}
{
    "repo_name": "pyramid",
    "new_commit_hash": "b0d20b5c3fe7df472633899024cdab685483807a",
    "test_file_codes": [
        "import os\nimport unittest\nfrom pyramid import testing\n\nfrom pyramid.tests.test_config import IDummy\n\nfrom pyramid.tests.test_config import dummy_view\n\nfrom pyramid.compat import (\n    im_func,\n    text_,\n    )\nfrom pyramid.exceptions import ConfigurationError\nfrom pyramid.exceptions import ConfigurationExecutionError\nfrom pyramid.exceptions import ConfigurationConflictError\n\nclass TestViewsConfigurationMixin(unittest.TestCase):\n    def _makeOne(self, *arg, **kw):\n        from pyramid.config import Configurator\n        config = Configurator(*arg, **kw)\n        return config\n\n    def _getViewCallable(self, config, ctx_iface=None, request_iface=None,\n                         name='', exception_view=False):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        if exception_view:\n            classifier = IExceptionViewClassifier\n        else:\n            classifier = IViewClassifier\n        if ctx_iface is None:\n            ctx_iface = Interface\n        if request_iface is None:\n            request_iface = IRequest\n        return config.registry.adapters.lookup(\n            (classifier, request_iface, ctx_iface), IView, name=name,\n            default=None)\n\n    def _registerRenderer(self, config, name='.txt'):\n        from pyramid.interfaces import IRendererFactory\n        class Renderer:\n            def __init__(self, info):\n                self.__class__.info = info\n            def __call__(self, *arg):\n                return b'Hello!'\n        config.registry.registerUtility(Renderer, IRendererFactory, name=name)\n        return Renderer\n\n    def _makeRequest(self, config):\n        request = DummyRequest()\n        request.registry = config.registry\n        return request\n\n    def _assertNotFound(self, wrapper, *arg):\n        from pyramid.httpexceptions import HTTPNotFound\n        self.assertRaises(HTTPNotFound, wrapper, *arg)\n\n    def _getRouteRequestIface(self, config, name):\n        from pyramid.interfaces import IRouteRequest\n        iface = config.registry.getUtility(IRouteRequest, name)\n        return iface\n\n    def _assertRoute(self, config, name, path, num_predicates=0):\n        from pyramid.interfaces import IRoutesMapper\n        mapper = config.registry.getUtility(IRoutesMapper)\n        routes = mapper.get_routes()\n        route = routes[0]\n        self.assertEqual(len(routes), 1)\n        self.assertEqual(route.name, name)\n        self.assertEqual(route.path, path)\n        self.assertEqual(len(routes[0].predicates), num_predicates)\n        return route\n\n    def test_add_view_view_callable_None_no_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError, config.add_view)\n\n    def test_add_view_with_request_type_and_route_name(self):\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        self.assertRaises(ConfigurationError, config.add_view, view, '', None,\n                          None, True, True)\n\n    def test_add_view_with_request_type(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.interfaces import IRequest\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view,\n                        request_type='pyramid.interfaces.IRequest',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = DummyRequest()\n        self._assertNotFound(wrapper, None, request)\n        directlyProvides(request, IRequest)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_view_callable_None_with_renderer(self):\n        config = self._makeOne(autocommit=True)\n        self._registerRenderer(config, name='dummy')\n        config.add_view(renderer='dummy')\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_with_tmpl_renderer_factory_introspector_missing(self):\n        config = self._makeOne(autocommit=True)\n        config.introspection = False\n        config.introspector = None\n        config.add_view(renderer='dummy.pt')\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_no_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector()\n        config.introspector = introspector\n        config.add_view(renderer='dummy.pt')\n        self.assertFalse(('renderer factories', '.pt') in\n                         introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertRaises(ValueError, view, None, None)\n\n    def test_add_view_with_tmpl_renderer_factory_with_renderer_factory(self):\n        config = self._makeOne(autocommit=True)\n        introspector = DummyIntrospector(True)\n        config.introspector = introspector\n        def dummy_factory(helper):\n            return lambda val, system_vals: 'Hello!'\n        config.add_renderer('.pt', dummy_factory)\n        config.add_view(renderer='dummy.pt')\n        self.assertTrue(\n            ('renderer factories', '.pt') in introspector.related[-1])\n        view = self._getViewCallable(config)\n        self.assertTrue(b'Hello!' in view(None, None).body)\n\n    def test_add_view_wrapped_view_is_decorated(self):\n        def view(request): # request-only wrapper\n            \"\"\" \"\"\"\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper.__module__, view.__module__)\n        self.assertEqual(wrapper.__name__, view.__name__)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        self.assertEqual(wrapper.__discriminator__(None, None).resolve()[0],\n                         'view')\n\n    def test_add_view_view_callable_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        config.add_view(view='pyramid.tests.test_config.dummy_view',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_function_callable(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_function_callable_requestonly(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, name='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name='abc')\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_name_unicode(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        name = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        config.add_view(view=view, name=name, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, name=name)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper(fn):\n            def inner(context, request):\n                return fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=view_wrapper,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_decorator_tuple(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return 'OK'\n        def view_wrapper1(fn):\n            def inner(context, request):\n                return 'wrapped1' + fn(context, request)\n            return inner\n        def view_wrapper2(fn):\n            def inner(context, request):\n                return 'wrapped2' + fn(context, request)\n            return inner\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, decorator=(view_wrapper2, view_wrapper1),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'wrapped2wrapped1OK')\n\n    def test_add_view_with_http_cache(self):\n        import datetime\n        from pyramid.response import Response\n        response = Response('OK')\n        def view(request):\n            \"\"\" ABC \"\"\"\n            return response\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, http_cache=(86400, {'public':True}))\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(wrapper is view)\n        self.assertEqual(wrapper.__doc__, view.__doc__)\n        request = testing.DummyRequest()\n        when = datetime.datetime.utcnow() + datetime.timedelta(days=1)\n        result = wrapper(None, request)\n        self.assertEqual(result, response)\n        headers = dict(response.headerlist)\n        self.assertEqual(headers['Cache-Control'], 'max-age=86400, public')\n        expires = parse_httpdate(headers['Expires'])\n        assert_similar_datetime(expires, when)\n\n    def test_add_view_as_instance(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instancemethod_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        config=self._makeOne(autocommit=True)\n        config.add_view(view=view.index, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_instance_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class AView:\n            def __call__(self, request):\n                \"\"\" \"\"\"\n                return 'OK'\n        view = AView()\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        result = wrapper(None, None)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_as_oldstyle_class(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, context, request):\n                self.context = context\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_as_oldstyle_class_requestonly(self):\n        from pyramid.renderers import null_renderer\n        class view:\n            def __init__(self, request):\n                self.request = request\n\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n        self.assertEqual(request.__view__.__class__, view)\n\n    def test_add_view_context_as_class(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_iface(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(context='pyramid.tests.test_config.IDummy',\n                        view=view,  renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for__as_dottedname(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_='pyramid.tests.test_config.IDummy',\n                        view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_class(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        class Foo:\n            pass\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=Foo, view=view, renderer=null_renderer)\n        foo = implementedBy(Foo)\n        wrapper = self._getViewCallable(config, foo)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_for_as_iface(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(for_=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_context_trumps_for(self):\n        # ``for_`` is older spelling for ``context``\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class Foo:\n            pass\n        config.add_view(context=IDummy, for_=Foo, view=view,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config, IDummy)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_exception_register_secured_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__call_permissive__ = view\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = config.registry.adapters.lookup(\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='', default=None)\n        self.assertEqual(wrapper, view)\n\n    def test_add_view_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_same_phash_overrides_existing_single_view(self):\n        from pyramid.renderers import null_renderer\n        from hashlib import md5\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        phash = md5()\n        phash.update(b'xhr = True')\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = phash.hexdigest()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, xhr=True, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_no_phash(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_default_phash_overrides_default_phash(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.config.util import DEFAULT_PHASH\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'NOT OK'\n        view.__phash__ = DEFAULT_PHASH\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        def newview(context, request):\n            return 'OK'\n        config.add_view(view=newview, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        request = DummyRequest()\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IExceptionViewClassifier\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            ISecuredView, name='')\n        config.add_view(view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_exc_multiview_replaces_existing_securedview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import ISecuredView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            ISecuredView, name='')\n        config.add_view(view=view, context=RuntimeError, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_mixed_case_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/HTML', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.media_views.items()),1)\n        self.assertFalse('text/HTML' in wrapper.media_views)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_views_with_accept_multiview_replaces_existing(self):\n        from pyramid.renderers import null_renderer\n        def view(context, request): return 'OK'\n        def view2(context, request): return 'OK2'\n        def view3(context, request): return 'OK3'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, renderer=null_renderer)\n        config.add_view(view=view2, accept='text/html', renderer=null_renderer)\n        config.add_view(view=view3, accept='text/html', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertEqual(len(wrapper.media_views['text/html']), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK3')\n\n    def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, accept='text/html', context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/html')\n        self.assertEqual(wrapper(None, request), 'OK2')\n\n    def test_add_view_multiview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        def view(context, request):\n            return 'OK'\n        def view2(context, request):\n            return 'OK2'\n        view.__accept__ = 'text/html'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IView, name='')\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual(len(wrapper.views), 1)\n        self.assertEqual(len(wrapper.media_views), 1)\n        self.assertEqual(wrapper(None, None), 'OK2')\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_exc_multiview_replaces_multiview(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        view = DummyMultiView()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view,\n            (IViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        config.registry.registerAdapter(\n            view,\n            (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),\n            IMultiView, name='')\n        view2 = lambda *arg: 'OK2'\n        config.add_view(view=view2, context=RuntimeError,\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError), exception_view=True)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])\n        self.assertEqual(wrapper(None, None), 'OK1')\n\n    def test_add_view_multiview_context_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        class ISuper(Interface):\n            pass\n        class ISub(ISuper):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, ISuper), IView, name='')\n        config.add_view(view=view2, for_=ISub, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, ISuper, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK')\n        wrapper = self._getViewCallable(config, ISub, IRequest)\n        self.assertFalse(IMultiView.providedBy(wrapper))\n        self.assertEqual(wrapper(None, None), 'OK2')\n\n    def test_add_view_multiview_exception_superclass_then_subclass(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IMultiView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IExceptionViewClassifier\n        class Super(Exception):\n            pass\n        class Sub(Super):\n            pass\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'OK2'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Super), IView, name='')\n        config.registry.registerAdapter(\n            view, (IExceptionViewClassifier, IRequest, Super), IView, name='')\n        config.add_view(view=view2, for_=Sub, renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, implementedBy(Super), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Super), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n        wrapper = self._getViewCallable(\n            config, implementedBy(Sub), IRequest)\n        wrapper_exc_view = self._getViewCallable(\n            config, implementedBy(Sub), IRequest, exception_view=True)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertFalse(IMultiView.providedBy(wrapper_exc_view))\n        self.assertEqual(wrapper_exc_view(None, None), 'OK2')\n\n    def test_add_view_multiview_call_ordering(self):\n        from pyramid.renderers import null_renderer as nr\n        from zope.interface import directlyProvides\n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n        def view3(context, request): return 'view3'\n        def view4(context, request): return 'view4'\n        def view5(context, request): return 'view5'\n        def view6(context, request): return 'view6'\n        def view7(context, request): return 'view7'\n        def view8(context, request): return 'view8'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, renderer=nr)\n        config.add_view(view=view2, request_method='POST', renderer=nr)\n        config.add_view(view=view3,request_param='param', renderer=nr)\n        config.add_view(view=view4, containment=IDummy, renderer=nr)\n        config.add_view(view=view5, request_method='POST',\n                        request_param='param',  renderer=nr)\n        config.add_view(view=view6, request_method='POST', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view7, request_param='param', containment=IDummy,\n                        renderer=nr)\n        config.add_view(view=view8, request_method='POST',request_param='param',\n                        containment=IDummy, renderer=nr)\n\n\n        wrapper = self._getViewCallable(config)\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view1')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view2')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.params = {'param':'1'}\n        request.method = 'GET'\n        self.assertEqual(wrapper(ctx, request), 'view3')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {}\n        self.assertEqual(wrapper(ctx, request), 'view4')\n\n        ctx = DummyContext()\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view5')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.params = {}\n        request.method = 'POST'\n        self.assertEqual(wrapper(ctx, request), 'view6')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view7')\n\n        ctx = DummyContext()\n        directlyProvides(ctx, IDummy)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {'param':'1'}\n        self.assertEqual(wrapper(ctx, request), 'view8')\n\n    def test_view_with_most_specific_predicate(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n        config.add_view(unknown, route_name='root', renderer=nr)\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_view_with_most_specific_predicate_with_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.router import Router\n\n        class OtherBase(object): pass\n        class Int1(object): pass\n        class Int2(object): pass\n\n        class Resource(OtherBase, Int1, Int2):\n            def __init__(self, request): pass\n\n        def unknown(context, request): return 'unknown'\n        def view(context, request): return 'hello'\n\n        config = self._makeOne(autocommit=True)\n        config.add_route('root', '/', factory=Resource)\n\n        config.add_view(\n            unknown,\n            route_name='root',\n            renderer=nr,\n            request_method=('POST',),\n            xhr=True,\n        )\n\n        config.add_view(\n            view, renderer=nr, route_name='root',\n            context=Int1, request_method='GET'\n        )\n        config.add_view(\n            view=view, renderer=nr, route_name='root',\n            context=Int2, request_method='POST'\n        )\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        request.params = {}\n        router = Router(config.registry)\n        response = router.handle_request(request)\n        self.assertEqual(response, 'hello')\n\n    def test_add_view_multiview___discriminator__(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        class IFoo(Interface):\n            pass\n        class IBar(Interface):\n            pass\n        @implementer(IFoo)\n        class Foo(object):\n            pass\n        @implementer(IBar)\n        class Bar(object):\n            pass\n        foo = Foo()\n        bar = Bar()\n\n        from pyramid.interfaces import IRequest\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IMultiView\n        view = lambda *arg: 'OK'\n        view.__phash__ = 'abc'\n        config = self._makeOne(autocommit=True)\n        config.registry.registerAdapter(\n            view, (IViewClassifier, IRequest, Interface), IView, name='')\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IFoo)\n        config.add_view(view=view, renderer=null_renderer,\n                        containment=IBar)\n        wrapper = self._getViewCallable(config)\n        self.assertTrue(IMultiView.providedBy(wrapper))\n        request = self._makeRequest(config)\n        self.assertNotEqual(\n            wrapper.__discriminator__(foo, request),\n            wrapper.__discriminator__(bar, request),\n            )\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_default_renderer(self):\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n\n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        class moo(object):\n            def __init__(self, *arg, **kw):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'moo'\n        config.add_renderer(None, moo)\n        config.add_view(view=view)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'moo')\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n        self.assertEqual(result.package, test_config)\n        self.assertEqual(result.name, fixture)\n        self.assertEqual(result.settings, settings)\n\n    def test_add_view_with_request_type_as_iface(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        def view(context, request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(request_type=IDummy, view=view, renderer=null_renderer)\n        wrapper = self._getViewCallable(config, None)\n        request = self._makeRequest(config)\n        directlyProvides(request, IDummy)\n        result = wrapper(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_view_with_request_type_as_noniface(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        self.assertRaises(ConfigurationError,\n                          config.add_view, view, '', None, None, object)\n\n    def test_add_view_with_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        self.assertNotEqual(request_iface, None)\n        wrapper = self._getViewCallable(config, request_iface=request_iface)\n        self.assertNotEqual(wrapper, None)\n        self.assertEqual(wrapper(None, None), 'OK')\n\n    def test_add_view_with_nonexistant_route_name(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, route_name='foo', renderer=null_renderer)\n        self.assertRaises(ConfigurationExecutionError, config.commit)\n\n    def test_add_view_with_route_name_exception(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(view=view, route_name='foo', context=RuntimeError,\n                        renderer=null_renderer)\n        request_iface = self._getRouteRequestIface(config, 'foo')\n        wrapper_exc_view = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface, exception_view=True)\n        self.assertNotEqual(wrapper_exc_view, None)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(RuntimeError),\n            request_iface=request_iface)\n        self.assertEqual(wrapper_exc_view, wrapper)\n        self.assertEqual(wrapper_exc_view(None, None), 'OK')\n\n    def test_add_view_with_request_method_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='POST')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_sequence_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'POST'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_method_sequence_conflict(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view=view, request_method=('POST', 'GET'),\n                        renderer=null_renderer)\n        config.add_view(view=view, request_method=('GET', 'POST'),\n                        renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_request_method_sequence_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method=('POST', 'HEAD'))\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_method_get_implies_head(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'HEAD'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_noval_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_request_param_val_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':'123'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_request_param_val_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_param='abc=123')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.params = {'abc':''}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_xhr_true(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_xhr_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, xhr=True)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.is_xhr = False\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, header='Host:a\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_header_noval_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'whatever'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_noval_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header='Host')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NotHost':'whatever'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'1'}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_header_val_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'Host':'abc'}\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_header_val_missing(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, header=r'Host:\\d')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.headers = {'NoHost':'1'}\n        self.assertRaises(HTTPNotFound, wrapper, None, request)\n\n    def test_add_view_with_accept_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/xml']\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_accept_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, accept='text/xml')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.accept = ['text/html']\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_containment_true(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy, renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_containment_false(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, containment=IDummy)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        self._assertNotFound(wrapper, context, None)\n\n    def test_add_view_with_containment_dottedname(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            containment='pyramid.tests.test_config.IDummy',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        self.assertEqual(wrapper(context, None), 'OK')\n\n    def test_add_view_with_path_info_badregex(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne()\n        config.add_view(view, path_info='\\\\')\n        self.assertRaises(ConfigurationError, config.commit)\n\n    def test_add_view_with_path_info_match(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo', renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_(b'/foo')\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_path_info_nomatch(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, path_info='/foo')\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.upath_info = text_('/')\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_with_check_csrf_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, check_csrf=True, renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = \"POST\"\n        request.session = DummySession({'csrf_token': 'foo'})\n        request.POST = {'csrf_token': 'foo'}\n        request.headers = {}\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_match(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return True\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates,\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_with_custom_predicates_nomatch(self):\n        import warnings\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        def pred2(context, request):\n            return False\n        predicates = (pred1, pred2)\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=predicates)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self._assertNotFound(wrapper, None, request)\n\n    def test_add_view_custom_predicate_bests_standard_predicate(self):\n        import warnings\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        def pred1(context, request):\n            return True\n        with warnings.catch_warnings(record=True) as w:\n            warnings.filterwarnings('always')\n            config.add_view(view=view, custom_predicates=(pred1,),\n                        renderer=null_renderer)\n            config.add_view(view=view2, request_method='GET',\n                            renderer=null_renderer)\n            self.assertEqual(len(w), 1)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):\n        from pyramid.renderers import null_renderer\n        view = lambda *arg: 'OK'\n        view2 = lambda *arg: 'NOT OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view, request_method='GET', xhr=True,\n                        renderer=null_renderer)\n        config.add_view(view=view2, request_method='GET',\n                        renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.method = 'GET'\n        request.is_xhr = True\n        self.assertEqual(wrapper(None, request), 'OK')\n\n    def test_add_view_same_predicates(self):\n        view2 = lambda *arg: 'second'\n        view1 = lambda *arg: 'first'\n        config = self._makeOne()\n        config.add_view(view=view1)\n        config.add_view(view=view2)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_with_csrf_param(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf='st', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {'st': 'foo'}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_csrf_header(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {'X-CSRF-Token': 'foo'}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_missing_csrf_header(self):\n        from pyramid.exceptions import BadCSRFToken\n        from pyramid.renderers import null_renderer\n        def view(request): return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view, require_csrf=True, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        request.scheme = \"http\"\n        request.method = 'POST'\n        request.POST = {}\n        request.headers = {}\n        request.session = DummySession({'csrf_token': 'foo'})\n        self.assertRaises(BadCSRFToken, lambda: view(None, request))\n\n    def test_add_view_with_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, permission='view', renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        outerself = self\n        class DummyPolicy(object):\n            def effective_principals(self, r):\n                outerself.assertEqual(r, request)\n                return ['abc']\n            def permits(self, context, principals, permission):\n                outerself.assertEqual(context, None)\n                outerself.assertEqual(principals, ['abc'])\n                outerself.assertEqual(permission, 'view')\n                return True\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               default_permission='view',\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_no_default_permission_no_explicit_permission(self):\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        class DummyPolicy(object): pass # wont be called\n        policy = DummyPolicy()\n        config = self._makeOne(authorization_policy=policy,\n                               authentication_policy=policy,\n                               autocommit=True)\n        config.add_view(view=view1, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        self.assertEqual(view(None, request), 'OK')\n\n    def test_add_view_with_mapper(self):\n        from pyramid.renderers import null_renderer\n        class Mapper(object):\n            def __init__(self, **kw):\n                self.__class__.kw = kw\n            def __call__(self, view):\n                return view\n        config = self._makeOne(autocommit=True)\n        def view(context, request): return 'OK'\n        config.add_view(view=view, mapper=Mapper, renderer=null_renderer)\n        view = self._getViewCallable(config)\n        self.assertEqual(view(None, None), 'OK')\n        self.assertEqual(Mapper.kw['mapper'], Mapper)\n\n    def test_add_view_with_view_defaults(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_kwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            view='pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg(self):\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from zope.interface import directlyProvides\n        config = self._makeOne(autocommit=True)\n        config.add_view(\n            'pyramid.tests.test_config.test_views.DummyViewDefaultsClass',\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(config)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_view_with_view_config_and_view_defaults_doesnt_conflict(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IFactory'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        config.commit() # does not raise\n\n    def test_add_view_with_view_config_and_view_defaults_conflicts(self):\n        from pyramid.renderers import null_renderer\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        class view2(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n        config = self._makeOne(autocommit=False)\n        config.add_view(\n            view=view,\n            renderer=null_renderer)\n        config.add_view(\n            view=view2,\n            renderer=null_renderer)\n        self.assertRaises(ConfigurationConflictError, config.commit)\n\n    def test_add_view_class_method_no_attr(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import directlyProvides\n        from pyramid.exceptions import ConfigurationError\n\n        config = self._makeOne(autocommit=True)\n        class DummyViewClass(object):\n            def run(self): pass\n\n        def configure_view():\n            config.add_view(view=DummyViewClass.run, renderer=null_renderer)\n\n        self.assertRaises(ConfigurationError, configure_view)\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(config, ctx_iface=implementedBy(Exception))\n        self.assertTrue(view is None)\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n        view = self._getViewCallable(\n            config, ctx_iface=implementedBy(Exception), exception_view=True\n            )\n        self.assertEqual(view1, view)\n\n    def test_add_view_exception_only_misconfiguration(self):\n        view = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n        class NotAnException(object):\n            pass\n        self.assertRaises(\n            ConfigurationError,\n            config.add_view, view, context=NotAnException, exception_only=True\n            )\n\n    def test_derive_view_function(self):\n        from pyramid.renderers import null_renderer\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        result = config.derive_view(view, renderer=null_renderer)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_dottedname(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne()\n        result = config.derive_view(\n            'pyramid.tests.test_config.dummy_view',\n            renderer=null_renderer)\n        self.assertFalse(result is dummy_view)\n        self.assertEqual(result(None, None), 'OK')\n\n    def test_derive_view_with_default_renderer_no_explicit_renderer(self):\n        config = self._makeOne()\n        class moo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return 'moo'\n        config.add_renderer(None, moo)\n        config.commit()\n        def view(request):\n            return 'OK'\n        result = config.derive_view(view)\n        self.assertFalse(result is view)\n        self.assertEqual(result(None, None).body, b'moo')\n\n    def test_derive_view_with_default_renderer_with_explicit_renderer(self):\n        class moo(object): pass\n        class foo(object):\n            def __init__(self, view):\n                pass\n            def __call__(self, *arg, **kw):\n                return b'foo'\n        def view(request):\n            return 'OK'\n        config = self._makeOne()\n        config.add_renderer(None, moo)\n        config.add_renderer('foo', foo)\n        config.commit()\n        result = config.derive_view(view, renderer='foo')\n        self.assertFalse(result is view)\n        request = self._makeRequest(config)\n        self.assertEqual(result(None, request).body, b'foo')\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n        result = wrapped(None, request)\n        self.assertEqual(result.status, '200 OK')\n        self.assertTrue(result.body.startswith(b'<div'))\n\n    def test_add_static_view_package_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static',\n                               'pyramid.tests.test_config:files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n        self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\n\n    def test_add_static_view_absolute(self):\n        import os\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        here = os.path.dirname(__file__)\n        static_path = os.path.join(here, 'files')\n        config.add_static_view('static', static_path)\n        self.assertEqual(info.added,\n                         [(config, 'static', static_path, {})])\n\n    def test_add_forbidden_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: 'OK'\n        config.add_forbidden_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, 'OK')\n\n    def test_add_forbidden_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_forbidden_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        context = HTTPForbidden()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_forbidden_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_forbidden_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_forbidden_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, name='foo')\n\n    def test_add_forbidden_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, permission='foo')\n\n    def test_add_forbidden_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, context='foo')\n\n    def test_add_forbidden_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, for_='foo')\n\n    def test_add_forbidden_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_forbidden_view, http_cache='foo')\n\n    def test_add_forbidden_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPForbidden\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_forbidden_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPForbidden),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    def test_add_notfound_view(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: arg\n        config.add_notfound_view(view, renderer=null_renderer)\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertEqual(result, (None, request))\n\n    def test_add_notfound_view_no_view_argument(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.setup_registry()\n        config.add_notfound_view()\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        context = HTTPNotFound()\n        result = view(context, request)\n        self.assertEqual(result, context)\n\n    def test_add_notfound_view_allows_other_predicates(self):\n        from pyramid.renderers import null_renderer\n        config = self._makeOne(autocommit=True)\n        # doesnt blow up\n        config.add_view_predicate('dummy', DummyPredicate)\n        config.add_notfound_view(renderer=null_renderer, dummy='abc')\n\n    def test_add_notfound_view_disallows_name(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, name='foo')\n\n    def test_add_notfound_view_disallows_permission(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, permission='foo')\n\n    def test_add_notfound_view_disallows_context(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, context='foo')\n\n    def test_add_notfound_view_disallows_for_(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, for_='foo')\n\n    def test_add_notfound_view_disallows_http_cache(self):\n        config = self._makeOne(autocommit=True)\n        self.assertRaises(ConfigurationError,\n                          config.add_notfound_view, http_cache='foo')\n\n    def test_add_notfound_view_append_slash(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPFound, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(view, renderer=null_renderer,append_slash=True)\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPFound))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_append_slash_custom_response(self):\n        from pyramid.response import Response\n        from pyramid.renderers import null_renderer\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        config.add_route('foo', '/foo/')\n        def view(request): return Response('OK')\n        config.add_notfound_view(\n            view, renderer=null_renderer,append_slash=HTTPMovedPermanently\n        )\n        request = self._makeRequest(config)\n        request.environ['PATH_INFO'] = '/foo'\n        request.query_string = 'a=1&b=2'\n        request.path = '/scriptname/foo'\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self.assertTrue(isinstance(result, HTTPMovedPermanently))\n        self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2')\n\n    def test_add_notfound_view_with_view_defaults(self):\n        from pyramid.interfaces import IRequest\n        from pyramid.renderers import null_renderer\n        from pyramid.exceptions import PredicateMismatch\n        from pyramid.httpexceptions import HTTPNotFound\n        from zope.interface import directlyProvides\n        from zope.interface import implementedBy\n        class view(object):\n            __view_defaults__ = {\n                'containment':'pyramid.tests.test_config.IDummy'\n                }\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        config = self._makeOne(autocommit=True)\n        config.add_notfound_view(\n            view=view,\n            renderer=null_renderer)\n        wrapper = self._getViewCallable(\n            config, ctx_iface=implementedBy(HTTPNotFound),\n            request_iface=IRequest)\n        context = DummyContext()\n        directlyProvides(context, IDummy)\n        request = self._makeRequest(config)\n        self.assertEqual(wrapper(context, request), 'OK')\n        context = DummyContext()\n        request = self._makeRequest(config)\n        self.assertRaises(PredicateMismatch, wrapper, context, request)\n\n    # Since Python 3 has to be all cool and fancy and different...\n    def _assertBody(self, response, value):\n        from pyramid.compat import text_type\n        if isinstance(value, text_type): # pragma: nocover\n            self.assertEqual(response.text, value)\n        else: # pragma: nocover\n            self.assertEqual(response.body, value)\n\n    def test_add_notfound_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPNotFound\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_notfound_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPNotFound),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_add_forbidden_view_with_renderer(self):\n        from zope.interface import implementedBy\n        from pyramid.interfaces import IRequest\n        from pyramid.httpexceptions import HTTPForbidden\n        config = self._makeOne(autocommit=True)\n        view = lambda *arg: {}\n        config.introspection = False\n        config.add_forbidden_view(\n            view,\n            renderer='json')\n        request = self._makeRequest(config)\n        view = self._getViewCallable(config,\n                                     ctx_iface=implementedBy(HTTPForbidden),\n                                     request_iface=IRequest)\n        result = view(None, request)\n        self._assertBody(result, '{}')\n\n    def test_set_view_mapper(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        mapper = object()\n        config.set_view_mapper(mapper)\n        result = config.registry.getUtility(IViewMapperFactory)\n        self.assertEqual(result, mapper)\n\n    def test_set_view_mapper_dottedname(self):\n        from pyramid.interfaces import IViewMapperFactory\n        config = self._makeOne(autocommit=True)\n        config.set_view_mapper('pyramid.tests.test_config')\n        result = config.registry.getUtility(IViewMapperFactory)\n        from pyramid.tests import test_config\n        self.assertEqual(result, test_config)\n\nclass Test_requestonly(unittest.TestCase):\n    def _callFUT(self, view, attr=None):\n        from pyramid.config.views import requestonly\n        return requestonly(view, attr=attr)\n\n    def test_defaults(self):\n        def aview(request, a=1, b=2): pass\n        self.assertTrue(self._callFUT(aview))\n\n    def test_otherattr(self):\n        class AView(object):\n            def __init__(self, request, a=1, b=2): pass\n            def bleh(self): pass\n        self.assertTrue(self._callFUT(AView, 'bleh'))\n\nclass Test_isexception(unittest.TestCase):\n    def _callFUT(self, ob):\n        from pyramid.config.views import isexception\n        return isexception(ob)\n\n    def test_is_exception_instance(self):\n        class E(Exception):\n            pass\n        e = E()\n        self.assertEqual(self._callFUT(e), True)\n\n    def test_is_exception_class(self):\n        class E(Exception):\n            pass\n        self.assertEqual(self._callFUT(E), True)\n\n    def test_is_IException(self):\n        from pyramid.interfaces import IException\n        self.assertEqual(self._callFUT(IException), True)\n\n    def test_is_IException_subinterface(self):\n        from pyramid.interfaces import IException\n        class ISubException(IException):\n            pass\n        self.assertEqual(self._callFUT(ISubException), True)\n\nclass TestMultiView(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import MultiView\n        return MultiView\n\n    def _makeOne(self, name='name'):\n        return self._getTargetClass()(name)\n\n    def test_class_implements_ISecuredView(self):\n        from zope.interface.verify import verifyClass\n        from pyramid.interfaces import ISecuredView\n        verifyClass(ISecuredView, self._getTargetClass())\n\n    def test_instance_implements_ISecuredView(self):\n        from zope.interface.verify import verifyObject\n        from pyramid.interfaces import ISecuredView\n        verifyObject(ISecuredView, self._makeOne())\n\n    def test_add(self):\n        mv = self._makeOne()\n        mv.add('view', 100)\n        self.assertEqual(mv.views, [(100, 'view', None)])\n        mv.add('view2', 99)\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view3', 100, 'text/html')\n        self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])\n        mv.add('view4', 99, 'text/html', 'abc')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, 'view4', 'abc'), (100, 'view3', None)])\n        mv.add('view5', 100, 'text/xml')\n        self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])\n        self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))\n        self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])\n        mv.add('view6', 98, 'text/*')\n        self.assertEqual(mv.views, [(98, 'view6', None),\n                                    (99, 'view2', None),\n                                    (100, 'view', None)])\n\n    def test_add_with_phash(self):\n        mv = self._makeOne()\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc')])\n        mv.add('view', 100, phash='def')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n        mv.add('view', 100, phash='abc')\n        self.assertEqual(mv.views, [(100, 'view', 'abc'),\n                                    (100, 'view', 'def')])\n\n    def test_add_with_phash_override_accept(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='abc')\n        mv.add(view3, 99, accept='text/html', phash='def')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'def'), (100, view2, 'abc')])\n\n    def test_add_with_phash_override_accept2(self):\n        mv = self._makeOne()\n        def view1(): pass\n        def view2(): pass\n        def view3(): pass\n        mv.add(view1, 100, accept='text/html', phash='abc')\n        mv.add(view2, 100, accept='text/html', phash='def')\n        mv.add(view3, 99, accept='text/html', phash='ghi')\n        self.assertEqual(mv.media_views['text/html'],\n                         [(99, view3, 'ghi'),\n                          (100, view1, 'abc'),\n                          (100, view2, 'def')]\n                         )\n\n    def test_multiple_with_functions_as_views(self):\n        # this failed on py3 at one point, because functions aren't orderable\n        # and we were sorting the views via a plain sort() rather than\n        # sort(key=itemgetter(0)).\n        def view1(request): pass\n        def view2(request): pass\n        mv = self._makeOne()\n        mv.add(view1, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None)])\n        mv.add(view2, 100, None)\n        self.assertEqual(mv.views, [(100, view1, None), (100, view2, None)])\n\n    def test_get_views_request_has_no_accept(self):\n        request = DummyRequest()\n        mv = self._makeOne()\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views_no_self_accepts(self):\n        request = DummyRequest()\n        request.accept = True\n        mv = self._makeOne()\n        mv.accepts = []\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_get_views(self):\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html')\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        html_views = [(98, lambda *arg: None)]\n        mv.media_views['text/html'] = html_views\n        self.assertEqual(mv.get_views(request), html_views + mv.views)\n\n    def test_get_views_best_match_returns_None(self):\n        request = DummyRequest()\n        request.accept = DummyAccept(None)\n        mv = self._makeOne()\n        mv.accepts = ['text/html']\n        mv.views = [(99, lambda *arg: None)]\n        self.assertEqual(mv.get_views(request), mv.views)\n\n    def test_match_not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_fails(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: False\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.match, context, request)\n\n    def test_match_predicate_succeeds(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        view.__predicated__ = lambda *arg: True\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.match(context, request)\n        self.assertEqual(result, view)\n\n    def test_permitted_no_views(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv.__permitted__, context, request)\n\n    def test_permitted_no_match_with__permitted__(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view, None)]\n        self.assertEqual(mv.__permitted__(None, None), True)\n\n    def test_permitted(self):\n        mv = self._makeOne()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permitted(context, request):\n            return False\n        view.__permitted__ = permitted\n        mv.views = [(100, view, None)]\n        context = DummyContext()\n        request = DummyRequest()\n        result = mv.__permitted__(context, request)\n        self.assertEqual(result, False)\n\n    def test__call__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__intermediate_not_found(self):\n        from pyramid.exceptions import PredicateMismatch\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view1(context, request):\n            raise PredicateMismatch\n        def view2(context, request):\n            return expected_response\n        mv.views = [(100, view1, None), (99, view2, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        def view1(context, request):\n            raise  HTTPNotFound\n        def view2(context, request):\n            \"\"\" \"\"\"\n        mv.views = [(100, view1, None), (99, view2, None)]\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call__(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call_permissive__not_found(self):\n        from pyramid.httpexceptions import HTTPNotFound\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        self.assertRaises(HTTPNotFound, mv, context, request)\n\n    def test___call_permissive_has_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            \"\"\" \"\"\"\n        def permissive(context, request):\n            return expected_response\n        view.__call_permissive__ = permissive\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test___call_permissive_has_no_call_permissive(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.view_name = ''\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        response = mv.__call_permissive__(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_match(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/html', 'text/xml')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, None)]\n        mv.media_views['text/xml'] = [(100, view, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n    def test__call__with_accept_miss(self):\n        mv = self._makeOne()\n        context = DummyContext()\n        request = DummyRequest()\n        request.accept = DummyAccept('text/plain', 'text/html')\n        expected_response = DummyResponse()\n        def view(context, request):\n            return expected_response\n        mv.views = [(100, view, None)]\n        mv.media_views['text/xml'] = [(100, None, None)]\n        mv.accepts = ['text/xml']\n        response = mv(context, request)\n        self.assertEqual(response, expected_response)\n\n\n\nclass TestDefaultViewMapper(unittest.TestCase):\n    def setUp(self):\n        self.config = testing.setUp()\n        self.registry = self.config.registry\n\n    def tearDown(self):\n        del self.registry\n        testing.tearDown()\n\n    def _makeOne(self, **kw):\n        from pyramid.config.views import DefaultViewMapper\n        kw['registry'] = self.registry\n        return DefaultViewMapper(**kw)\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = self.registry\n        return request\n\n    def test_view_as_function_context_and_request(self):\n        def view(context, request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test__view_as_function_with_attr(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_function_requestonly(self):\n        def view(request):\n            return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_function_requestonly_with_attr(self):\n        def view(request):\n            \"\"\" \"\"\"\n        mapper = self._makeOne(attr='__name__')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertRaises(TypeError, result, None, request)\n\n    def test_view_as_newstyle_class_context_and_request(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_context_and_request_with_attr(self):\n        class view(object):\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_newstyle_class_requestonly_with_attr(self):\n        class view(object):\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_context_and_request_with_attr(self):\n        class view:\n            def __init__(self, context, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def __call__(self):\n                return 'OK'\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_oldstyle_class_requestonly_with_attr(self):\n        class view:\n            def __init__(self, request):\n                pass\n            def index(self):\n                return 'OK'\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request(self):\n        class View:\n            def __call__(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertTrue(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_context_and_request_and_attr(self):\n        class View:\n            def index(self, context, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly(self):\n        class View:\n            def __call__(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne()\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\n    def test_view_as_instance_requestonly_with_attr(self):\n        class View:\n            def index(self, request):\n                return 'OK'\n        view = View()\n        mapper = self._makeOne(attr='index')\n        result = mapper(view)\n        self.assertFalse(result is view)\n        request = self._makeRequest()\n        self.assertEqual(result(None, request), 'OK')\n\nclass Test_preserve_view_attrs(unittest.TestCase):\n    def _callFUT(self, view, wrapped_view):\n        from pyramid.config.views import preserve_view_attrs\n        return preserve_view_attrs(view, wrapped_view)\n\n    def test_it_same(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(view, view)\n        self.assertTrue(result is view)\n\n    def test_it_view_is_None(self):\n        def view(context, request):\n            \"\"\" \"\"\"\n        result = self._callFUT(None, view)\n        self.assertTrue(result is view)\n\n    def test_it_different_with_existing_original_view(self):\n        def view1(context, request): pass\n        view1.__original_view__ = 'abc'\n        def view2(context, request): pass\n        result = self._callFUT(view1, view2)\n        self.assertEqual(result.__original_view__, 'abc')\n        self.assertFalse(result is view1)\n\n    def test_it_different(self):\n        class DummyView1:\n            \"\"\" 1 \"\"\"\n            __name__ = '1'\n            __module__ = '1'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        class DummyView2:\n            \"\"\" 2 \"\"\"\n            __name__ = '2'\n            __module__ = '2'\n            def __call__(self, context, request):\n                \"\"\" \"\"\"\n            def __call_permissive__(self, context, request):\n                \"\"\" \"\"\"\n            def __predicated__(self, context, request):\n                \"\"\" \"\"\"\n            def __permitted__(self, context, request):\n                \"\"\" \"\"\"\n        view1 = DummyView1()\n        view2 = DummyView2()\n        result = self._callFUT(view2, view1)\n        self.assertEqual(result, view1)\n        self.assertTrue(view1.__original_view__ is view2)\n        self.assertTrue(view1.__doc__ is view2.__doc__)\n        self.assertTrue(view1.__module__ is view2.__module__)\n        self.assertTrue(view1.__name__ is view2.__name__)\n        self.assertTrue(getattr(view1.__call_permissive__, im_func) is\n                        getattr(view2.__call_permissive__, im_func))\n        self.assertTrue(getattr(view1.__permitted__, im_func) is\n                        getattr(view2.__permitted__, im_func))\n        self.assertTrue(getattr(view1.__predicated__, im_func) is\n                        getattr(view2.__predicated__, im_func))\n\n\nclass TestStaticURLInfo(unittest.TestCase):\n    def _getTargetClass(self):\n        from pyramid.config.views import StaticURLInfo\n        return StaticURLInfo\n\n    def _makeOne(self):\n        return self._getTargetClass()()\n\n    def _makeRequest(self):\n        request = DummyRequest()\n        request.registry = DummyRegistry()\n        return request\n\n    def test_verifyClass(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyClass\n        verifyClass(IStaticURLInfo, self._getTargetClass())\n\n    def test_verifyObject(self):\n        from pyramid.interfaces import IStaticURLInfo\n        from zope.interface.verify import verifyObject\n        verifyObject(IStaticURLInfo, self._makeOne())\n\n    def test_generate_missing(self):\n        inst = self._makeOne()\n        request = self._makeRequest()\n        self.assertRaises(ValueError, inst.generate, 'path', request)\n\n    def test_generate_registration_miss(self):\n        inst = self._makeOne()\n        inst.registrations = [\n            (None, 'spec', 'route_name'),\n            ('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name1(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc', request)\n        self.assertEqual(result, 'http://example.com/foo/abc')\n\n    def test_generate_slash_in_name2(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/foo/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/', request)\n        self.assertEqual(result, 'http://example.com/foo/')\n\n    def test_generate_quoting(self):\n        from pyramid.interfaces import IStaticURLInfo\n        config = testing.setUp()\n        try:\n            config.add_static_view('images', path='mypkg:templates')\n            request = testing.DummyRequest()\n            request.registry = config.registry\n            inst = config.registry.getUtility(IStaticURLInfo)\n            result = inst.generate('mypkg:templates/foo%2Fbar', request)\n            self.assertEqual(result, 'http://example.com/images/foo%252Fbar')\n        finally:\n            testing.tearDown()\n\n    def test_generate_route_url(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_unquoted_local(self):\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname/')]\n        def route_url(n, **kw):\n            self.assertEqual(n, '__viewname/')\n            self.assertEqual(kw, {'subpath':'abc def', 'a':1})\n            return 'url'\n        request = self._makeRequest()\n        request.route_url = route_url\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'url')\n\n    def test_generate_url_quoted_remote(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1)\n        self.assertEqual(result, 'http://example.com/abc%20def')\n\n    def test_generate_url_with_custom_query(self):\n        inst = self._makeOne()\n        registrations = [('http://example.com/', 'package:path/', None)]\n        inst.registrations = registrations\n        request = self._makeRequest()\n        result = inst.generate('package:path/abc def', request, a=1,\n                               _query='(openlayers)')\n        self.assertEqual(result,\n                         'http://example.com/abc%20def?(openlayers)')\n\n    def test_generate_url_with_custom_anchor(self):\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        request = self._makeRequest()\n        uc = text_(b'La Pe\\xc3\\xb1a', 'utf-8')\n        result = inst.generate('package:path/abc def', request, a=1, _anchor=uc)\n        self.assertEqual(result,\n                         'http://example.com/abc%20def#La%20Pe%C3%B1a')\n\n    def test_generate_url_cachebust(self):\n        def cachebust(request, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path/', cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_abspath(self):\n        here = os.path.dirname(__file__) + os.sep\n        def cachebust(pathspec, subpath, kw):\n            kw['foo'] = 'bar'\n            return 'foo' + '/' + subpath, kw\n        inst = self._makeOne()\n        inst.registrations = [(None, here, '__viewname')]\n        inst.cache_busters = [(here, cachebust, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'foo/abc', 'foo': 'bar',\n                                  'pathspec': here + 'abc',\n                                  'rawspec': here + 'abc'})\n        request.route_url = route_url\n        inst.generate(here + 'abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_nomatch(self):\n        def fake_cb(*a, **kw): raise AssertionError\n        inst = self._makeOne()\n        inst.registrations = [(None, 'package:path/', '__viewname')]\n        inst.cache_busters = [('package:path2/', fake_cb, False)]\n        request = self._makeRequest()\n        called = [False]\n        def route_url(n, **kw):\n            called[0] = True\n            self.assertEqual(n, '__viewname')\n            self.assertEqual(kw, {'subpath': 'abc',\n                                  'pathspec': 'package:path/abc',\n                                  'rawspec': 'package:path/abc'})\n        request.route_url = route_url\n        inst.generate('package:path/abc', request)\n        self.assertTrue(called[0])\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\n        finally:\n            testing.tearDown()\n\n    def test_add_already_exists(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.registrations = [('http://example.com/', 'package:path/', None)]\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_package_root(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'package:')\n        expected = [('http://example.com/', 'package:', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_withendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com/', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noendslash(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'http://example.com', 'anotherpackage:path')\n        expected = [('http://example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_url_noscheme(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, '//example.com', 'anotherpackage:path')\n        expected = [('//example.com/', 'anotherpackage:path/', None)]\n        self.assertEqual(inst.registrations, expected)\n\n    def test_add_viewname(self):\n        from pyramid.security import NO_PERMISSION_REQUIRED\n        from pyramid.static import static_view\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1)\n        expected = [(None, 'anotherpackage:path/', '__view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__view/', 'view/*subpath'))\n        self.assertEqual(config.view_kw['permission'], NO_PERMISSION_REQUIRED)\n        self.assertEqual(config.view_kw['view'].__class__, static_view)\n\n    def test_add_viewname_with_route_prefix(self):\n        config = DummyConfig()\n        config.route_prefix = '/abc'\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path',)\n        expected = [(None, 'anotherpackage:path/', '__/abc/view/')]\n        self.assertEqual(inst.registrations, expected)\n        self.assertEqual(config.route_args, ('__/abc/view/', 'view/*subpath'))\n\n    def test_add_viewname_with_permission(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 permission='abc')\n        self.assertEqual(config.view_kw['permission'], 'abc')\n\n    def test_add_viewname_with_context(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 context=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_for_(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 for_=DummyContext)\n        self.assertEqual(config.view_kw['context'], DummyContext)\n\n    def test_add_viewname_with_renderer(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add(config, 'view', 'anotherpackage:path', cache_max_age=1,\n                 renderer='mypackage:templates/index.pt')\n        self.assertEqual(config.view_kw['renderer'],\n                         'mypackage:templates/index.pt')\n\n    def test_add_cachebust_prevented(self):\n        config = DummyConfig()\n        config.registry.settings['pyramid.prevent_cachebust'] = True\n        inst = self._makeOne()\n        cachebust = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, 'mypackage:path', cachebust)\n        self.assertEqual(inst.cache_busters, [])\n\n    def test_add_cachebuster(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        inst.add_cache_buster(config, 'mypackage:path', DummyCacheBuster('foo'))\n        cachebust = inst.cache_busters[-1][1]\n        subpath, kw = cachebust(None, 'some/path', {})\n        self.assertEqual(subpath, 'some/path')\n        self.assertEqual(kw['x'], 'foo')\n\n    def test_add_cachebuster_abspath(self):\n        here = os.path.dirname(__file__)\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb = DummyCacheBuster('foo')\n        inst.add_cache_buster(config, here, cb)\n        self.assertEqual(inst.cache_busters, [(here + os.sep, cb, False)])\n\n    def test_add_cachebuster_overwrite(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb2, False)])\n\n    def test_add_cachebuster_overwrite_explicit(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        inst.add_cache_buster(config, 'mypackage:path/', cb1)\n        inst.add_cache_buster(config, 'mypackage:path', cb2, True)\n        self.assertEqual(inst.cache_busters,\n                         [('mypackage:path/', cb1, False),\n                          ('mypackage:path/', cb2, True)])\n\n    def test_add_cachebuster_for_more_specific_path(self):\n        config = DummyConfig()\n        inst = self._makeOne()\n        cb1 = DummyCacheBuster('foo')\n        cb2 = DummyCacheBuster('bar')\n        cb3 = DummyCacheBuster('baz')\n        cb4 = DummyCacheBuster('xyz')\n        cb5 = DummyCacheBuster('w')\n        inst.add_cache_buster(config, 'mypackage:path', cb1)\n        inst.add_cache_buster(config, 'mypackage:path/sub', cb2, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb3)\n        inst.add_cache_buster(config, 'mypackage:path/sub/other', cb4, True)\n        inst.add_cache_buster(config, 'mypackage:path/sub/less', cb5, True)\n        self.assertEqual(\n            inst.cache_busters,\n            [('mypackage:path/', cb1, False),\n             ('mypackage:path/sub/other/', cb3, False),\n             ('mypackage:path/sub/', cb2, True),\n             ('mypackage:path/sub/less/', cb5, True),\n             ('mypackage:path/sub/other/', cb4, True)])\n\nclass Test_view_description(unittest.TestCase):\n    def _callFUT(self, view):\n        from pyramid.config.views import view_description\n        return view_description(view)\n\n    def test_with_text(self):\n        def view(): pass\n        view.__text__ = 'some text'\n        result = self._callFUT(view)\n        self.assertEqual(result, 'some text')\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n        self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\n\n\nclass DummyRegistry:\n    utility = None\n\n    def __init__(self):\n        self.settings = {}\n\n    def queryUtility(self, type_or_iface, name=None, default=None):\n        return self.utility or default\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import (\n    IResponse,\n    IRequest,\n    )\n\n@implementer(IResponse)\nclass DummyResponse(object):\n    content_type = None\n    default_content_type = None\n    body = None\n\nclass DummyRequest:\n    subpath = ()\n    matchdict = None\n    request_iface  = IRequest\n\n    def __init__(self, environ=None):\n        if environ is None:\n            environ = {}\n        self.environ = environ\n        self.params = {}\n        self.cookies = {}\n        self.response = DummyResponse()\n\nclass DummyContext:\n    pass\n\nclass DummyAccept(object):\n    def __init__(self, *matches):\n        self.matches = list(matches)\n\n    def best_match(self, offered):\n        if self.matches:\n            for match in self.matches:\n                if match in offered:\n                    self.matches.remove(match)\n                    return match\n    def __contains__(self, val):\n        return val in self.matches\n\nclass DummyConfig:\n    def __init__(self):\n        self.registry = DummyRegistry()\n\n    route_prefix = ''\n    def add_route(self, *args, **kw):\n        self.route_args = args\n        self.route_kw = kw\n\n    def add_view(self, *args, **kw):\n        self.view_args = args\n        self.view_kw = kw\n\n    def action(self, discriminator, callable, introspectables=()):\n        callable()\n\n    def introspectable(self, *arg):\n        return {}\n\nfrom zope.interface import implementer\nfrom pyramid.interfaces import IMultiView\n@implementer(IMultiView)\nclass DummyMultiView:\n    def __init__(self):\n        self.views = []\n        self.name = 'name'\n    def add(self, view, order, accept=None, phash=None):\n        self.views.append((view, accept, phash))\n    def __call__(self, context, request):\n        return 'OK1'\n    def __permitted__(self, context, request):\n        \"\"\" \"\"\"\n\nclass DummyCacheBuster(object):\n    def __init__(self, token):\n        self.token = token\n\n    def __call__(self, request, subpath, kw):\n        kw['x'] = self.token\n        return subpath, kw\n\ndef parse_httpdate(s):\n    import datetime\n    # cannot use %Z, must use literal GMT; Jython honors timezone\n    # but CPython does not\n    return datetime.datetime.strptime(s, \"%a, %d %b %Y %H:%M:%S GMT\")\n\ndef assert_similar_datetime(one, two):\n    for attr in ('year', 'month', 'day', 'hour', 'minute'):\n        one_attr = getattr(one, attr)\n        two_attr = getattr(two, attr)\n        if not one_attr == two_attr: # pragma: no cover\n            raise AssertionError('%r != %r in %s' % (one_attr, two_attr, attr))\n\nclass DummyStaticURLInfo:\n    def __init__(self):\n        self.added = []\n\n    def add(self, config, name, spec, **kw):\n        self.added.append((config, name, spec, kw))\n\nclass DummyViewDefaultsClass(object):\n    __view_defaults__ = {\n        'containment':'pyramid.tests.test_config.IDummy'\n        }\n    def __init__(self, request):\n        pass\n    def __call__(self):\n        return 'OK'\n\nclass DummyPredicate(object):\n    def __init__(self, val, config):\n        self.val = val\n\n    def text(self):\n        return 'dummy'\n\n    phash = text\n\nclass DummyIntrospector(object):\n    def __init__(self, getval=None):\n        self.related = []\n        self.introspectables = []\n        self.getval = getval\n    def add(self, introspectable):\n        self.introspectables.append(introspectable)\n    def get(self, name, discrim):\n        return self.getval\n    def relate(self, a, b):\n        self.related.append((a, b))\n\nclass DummySession(dict):\n    def get_csrf_token(self):\n        return self['csrf_token']\n"
    ],
    "test_file_names": [
        "test_1.py"
    ],
    "setup_res_code": 0,
    "setup_res_stdout": "",
    "setup_res_stderr": "Using CPython 3.8.20\nCreating virtual environment at: .venv\nActivate with: source .venv/bin/activate\nResolved 9 packages in 649ms\nPrepared 1 package in 839ms\nInstalled 9 packages in 14ms\n + pastedeploy==3.1.0\n + pyramid==1.8.dev0 (from file:///home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a)\n + repoze-lru==0.7\n + setuptools==75.3.0\n + translationstring==1.4\n + venusian==3.1.1\n + webob==1.8.9\n + zope-deprecation==5.0\n + zope-interface==7.2\nResolved 19 packages in 20ms\nInstalled 10 packages in 7ms\n + beautifulsoup4==4.12.3\n + coverage==7.6.1\n + distlib==0.3.9\n + filelock==3.16.1\n + nose==1.3.7\n + platformdirs==4.3.6\n + soupsieve==2.6\n + virtualenv==20.29.0\n + waitress==3.0.0\n + webtest==3.0.1\nResolved 16 packages in 20ms\nInstalled 12 packages in 8ms\n + cachetools==5.5.0\n + chardet==5.2.0\n + colorama==0.4.6\n + exceptiongroup==1.2.2\n + iniconfig==2.0.0\n + packaging==24.2\n + pluggy==1.5.0\n + pyproject-api==1.8.0\n + pytest==8.3.4\n + tomli==2.2.1\n + tox==4.23.2\n + typing-extensions==4.12.2\n",
    "new_commit_res_code": 1,
    "new_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.8.20, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a\ncollected 1127 items\n\nr2e_tests/test_1.py .......................FF........................... [  4%]\n.....................................................................FF. [ 11%]\n........................................................................ [ 17%]\n.........................F.......F                                       [ 20%]\nr2e_tests/test_config/test_adapters.py .FF..............F...             [ 22%]\nr2e_tests/test_config/test_assets.py ....F.F...F...FF.FF................ [ 25%]\n.....................................F.F................................ [ 31%]\n                                                                         [ 31%]\nr2e_tests/test_config/test_factories.py .....................            [ 33%]\nr2e_tests/test_config/test_i18n.py FFF.FF...                             [ 34%]\nr2e_tests/test_config/test_init.py ..................................... [ 37%]\n...F..F.......F.............F...........F.....................FF...FFF.. [ 44%]\n......................                                                   [ 46%]\nr2e_tests/test_config/test_predicates.py ............................... [ 48%]\n...........................................                              [ 52%]\nr2e_tests/test_config/test_rendering.py ...                              [ 52%]\nr2e_tests/test_config/test_routes.py ........................            [ 55%]\nr2e_tests/test_config/test_security.py ............                      [ 56%]\nr2e_tests/test_config/test_settings.py ........................          [ 58%]\nr2e_tests/test_config/test_testing.py ............                       [ 59%]\nr2e_tests/test_config/test_tweens.py .................................   [ 62%]\nr2e_tests/test_config/test_util.py ..................................... [ 65%]\n..............                                                           [ 66%]\nr2e_tests/test_config/test_views.py ........................F........... [ 69%]\n........................................................................ [ 76%]\n.............FF......................................................... [ 82%]\n.........................................F.......F                       [ 87%]\nr2e_tests/test_scripts/test_common.py ...                                [ 87%]\nr2e_tests/test_scripts/test_pcreate.py ....................              [ 89%]\nr2e_tests/test_scripts/test_pdistreport.py ..                            [ 89%]\nr2e_tests/test_scripts/test_prequest.py F.FFF.FFFFFF.F.FFF.              [ 91%]\nr2e_tests/test_scripts/test_proutes.py ...FFF....FFFF.F.FF....F..FF.     [ 93%]\nr2e_tests/test_scripts/test_pserve.py ............................       [ 96%]\nr2e_tests/test_scripts/test_pshell.py ................                   [ 97%]\nr2e_tests/test_scripts/test_ptweens.py .....                             [ 97%]\nr2e_tests/test_scripts/test_pviews.py ................F......            [100%]\n\n=================================== FAILURES ===================================\n_ TestViewsConfigurationMixin.test_add_static_view_here_no_utility_registered __\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_static_view_here_no_utility_registered>\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n>       result = wrapped(None, request)\n\nr2e_tests/test_1.py:1915: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.static.static_view object at 0x7465215aab50>, context = None\nrequest = <Request at 0x746521836520 GET http://localhost/static/minimal.txt>\n\n    def __call__(self, context, request):\n        if self.use_subpath:\n            path_tuple = request.subpath\n        else:\n            path_tuple = traversal_path_info(request.environ['PATH_INFO'])\n        if self.cachebust_match:\n            path_tuple = self.cachebust_match(path_tuple)\n        path = _secure_path(path_tuple)\n    \n        if path is None:\n            raise HTTPNotFound('Out of bounds: %s' % request.url)\n    \n        if self.package_name: # package resource\n            resource_path = '%s/%s' % (self.docroot.rstrip('/'), path)\n            if resource_isdir(self.package_name, resource_path):\n                if not request.path_url.endswith('/'):\n                    self.add_slash_redirect(request)\n                resource_path = '%s/%s' % (\n                    resource_path.rstrip('/'), self.index\n                )\n    \n            if not resource_exists(self.package_name, resource_path):\n>               raise HTTPNotFound(request.url)\nE               pyramid.httpexceptions.HTTPNotFound: http://localhost/static/minimal.txt\n\npyramid/static.py:123: HTTPNotFound\n____ TestViewsConfigurationMixin.test_add_static_view_package_here_relative ____\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_static_view_package_here_relative>\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n>       self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\nE       AssertionError: Lists differ: [(<py[39 chars]46521582ac0>, 'static', 'r2e_tests:files', {})] != [(<py[39 chars]46521582ac0>, 'static', 'pyramid.tests.test_config:files', {})]\nE       \nE       First differing element 0:\nE       (<pyr[37 chars]746521582ac0>, 'static', 'r2e_tests:files', {})\nE       (<pyr[37 chars]746521582ac0>, 'static', 'pyramid.tests.test_config:files', {})\nE       \nE         [(<pyramid.config.Configurator object at 0x746521582ac0>,\nE           'static',\nE       -   'r2e_tests:files',\nE       +   'pyramid.tests.test_config:files',\nE           {})]\n\nr2e_tests/test_1.py:1936: AssertionError\n_______ TestViewsConfigurationMixin.test_add_view_with_template_renderer _______\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer>\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n    \n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests' from '/home/gcpuser/buckets/lo[93 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_1.py:1143: AssertionError\n_ TestViewsConfigurationMixin.test_add_view_with_template_renderer_no_callable _\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer_no_callable>\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests' from '/home/gcpuser/buckets/lo[93 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_1.py:1184: AssertionError\n_________ TestStaticURLInfo.test_generate_url_cachebust_with_overrides _________\n\nself = <r2e_tests.test_1.TestStaticURLInfo testMethod=test_generate_url_cachebust_with_overrides>\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n>           self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\nE           AssertionError: 'http://example.com/static/foo.png?x=foo' != 'http://example.com/static/foo.png?x=bar'\nE           - http://example.com/static/foo.png?x=foo\nE           ?                                     ^^^\nE           + http://example.com/static/foo.png?x=bar\nE           ?                                     ^^^\n\nr2e_tests/test_1.py:3015: AssertionError\n___________________ Test_view_description.test_without_text ____________________\n\nself = <r2e_tests.test_1.Test_view_description testMethod=test_without_text>\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n>       self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\nE       AssertionError: 'function r2e_tests.test_1.view' != 'function pyramid.tests.test_config.test_views.view'\nE       - function r2e_tests.test_1.view\nE       + function pyramid.tests.test_config.test_views.view\n\nr2e_tests/test_1.py:3186: AssertionError\n__ AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_dotted_names ___\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_resource_url_adapter_dotted_names>\n\n    def test_add_resource_url_adapter_dotted_names(self):\n        from pyramid.interfaces import IResourceURL\n        config = self._makeOne(autocommit=True)\n        config.add_resource_url_adapter(\n            'pyramid.tests.test_config.test_adapters.DummyResourceURL',\n            'pyramid.tests.test_config.test_adapters.DummyIface',\n            )\n        iface = DummyIface()\n>       adapter = config.registry.getMultiAdapter((iface, iface),\n                                                    IResourceURL)\n\nr2e_tests/test_config/test_adapters.py:280: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <Registry r2e_tests.test_config>\nobjects = (<r2e_tests.test_config.test_adapters.DummyIface object at 0x746521f38d30>, <r2e_tests.test_config.test_adapters.DummyIface object at 0x746521f38d30>)\ninterface = <InterfaceClass pyramid.interfaces.IResourceURL>, name = ''\n\n    def getMultiAdapter(self, objects, interface, name=''):\n        adapter = self.adapters.queryMultiAdapter(objects, interface, name)\n        if adapter is None:\n>           raise ComponentLookupError(objects, interface, name)\nE           zope.interface.interfaces.ComponentLookupError: ((<r2e_tests.test_config.test_adapters.DummyIface object at 0x746521f38d30>, <r2e_tests.test_config.test_adapters.DummyIface object at 0x746521f38d30>), <InterfaceClass pyramid.interfaces.IResourceURL>, '')\n\n.venv/lib/python3.8/site-packages/zope/interface/registry.py:379: ComponentLookupError\n_ AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_introspectables _\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_resource_url_adapter_introspectables>\n\n    def test_add_resource_url_adapter_introspectables(self):\n        config = self._makeOne()\n        config.add_resource_url_adapter(DummyResourceURL, DummyIface)\n        actions = config.action_state.actions\n        self.assertEqual(len(actions), 1)\n        intrs  = actions[0]['introspectables']\n        self.assertEqual(len(intrs), 1)\n        intr = intrs[0]\n        self.assertEqual(intr.type_name, 'resource url adapter')\n        self.assertEqual(intr.discriminator,\n                         ('resource url adapter', DummyIface))\n        self.assertEqual(intr.category_name, 'resource url adapters')\n>       self.assertEqual(\n            intr.title,\n            \"resource url adapter for resource iface \"\n            \"<class 'pyramid.tests.test_config.test_adapters.DummyIface'>\"\n            )\nE       AssertionError: \"reso[34 chars]e <class 'r2e_tests.test_config.test_adapters.DummyIface'>\" != \"reso[34 chars]e <class 'pyramid.tests.test_config.test_adapters.DummyIface'>\"\nE       - resource url adapter for resource iface <class 'r2e_tests.test_config.test_adapters.DummyIface'>\nE       ?                                                  ^^^\nE       + resource url adapter for resource iface <class 'pyramid.tests.test_config.test_adapters.DummyIface'>\nE       ?                                                 ++ ^^^^^\n\nr2e_tests/test_config/test_adapters.py:326: AssertionError\n________ AdaptersConfiguratorMixinTests.test_add_traverser_dotted_names ________\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_traverser_dotted_names>\n\n    def test_add_traverser_dotted_names(self):\n        from pyramid.interfaces import ITraverser\n        config = self._makeOne(autocommit=True)\n        config.add_traverser(\n            'pyramid.tests.test_config.test_adapters.DummyTraverser',\n            'pyramid.tests.test_config.test_adapters.DummyIface')\n        iface = DummyIface()\n>       traverser = config.registry.getAdapter(iface, ITraverser)\n\nr2e_tests/test_config/test_adapters.py:237: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <Registry r2e_tests.test_config>\nobject = <r2e_tests.test_config.test_adapters.DummyIface object at 0x74652186cee0>\ninterface = <InterfaceClass pyramid.interfaces.ITraverser>, name = ''\n\n    def getAdapter(self, object, interface, name=''):\n        adapter = self.adapters.queryAdapter(object, interface, name)\n        if adapter is None:\n>           raise ComponentLookupError(object, interface, name)\nE           zope.interface.interfaces.ComponentLookupError: (<r2e_tests.test_config.test_adapters.DummyIface object at 0x74652186cee0>, <InterfaceClass pyramid.interfaces.ITraverser>, '')\n\n.venv/lib/python3.8/site-packages/zope/interface/registry.py:368: ComponentLookupError\n___ TestAssetsConfiguratorMixin.test_override_asset_directory_with_directory ___\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_directory_with_directory>\n\n    def test_override_asset_directory_with_directory(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/')\n    \n        resource_name = 'bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:106: AssertionError\n____ TestAssetsConfiguratorMixin.test_override_asset_directory_with_package ____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_directory_with_package>\n\n    def test_override_asset_directory_with_package(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/',\n            'pyramid.tests.test_config.pkgs.asset.subpackage',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, '')\n    \n        resource_name = 'templates/bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:129: AssertionError\n________ TestAssetsConfiguratorMixin.test_override_asset_file_with_file ________\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_file_with_file>\n\n    def test_override_asset_file_with_file(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/foo.pt',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/bar.pt',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/foo.pt')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/bar.pt')\n    \n        resource_name = ''\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:60: AssertionError\n____ TestAssetsConfiguratorMixin.test_override_asset_package_with_directory ____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_package_with_directory>\n\n    def test_override_asset_package_with_directory(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, '')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/')\n    \n        resource_name = 'bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:152: AssertionError\n_____ TestAssetsConfiguratorMixin.test_override_asset_package_with_package _____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_package_with_package>\n\n    def test_override_asset_package_with_package(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset',\n            'pyramid.tests.test_config.pkgs.asset.subpackage',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, '')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, '')\n    \n        resource_name = 'templates/bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:83: AssertionError\n_________ TestOverrideProvider.test_get_resource_filename_no_overrides _________\n\nself = <r2e_tests.test_config.test_assets.TestOverrideProvider testMethod=test_get_resource_filename_no_overrides>\n\n    def test_get_resource_filename_no_overrides(self):\n        resource_name = 'test_assets.py'\n        import pyramid.tests.test_config\n        provider = self._makeOne(pyramid.tests.test_config)\n        expected = os.path.join(here, resource_name)\n        result = provider.get_resource_filename(None, resource_name)\n>       self.assertEqual(result, expected)\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:297: AssertionError\n____ TestOverrideProvider.test_get_resource_filename_override_returns_None _____\n\nself = <r2e_tests.test_config.test_assets.TestOverrideProvider testMethod=test_get_resource_filename_override_returns_None>\n\n    def test_get_resource_filename_override_returns_None(self):\n        overrides = DummyOverrides(None)\n        self._registerOverrides(overrides)\n        resource_name = 'test_assets.py'\n        import pyramid.tests.test_config\n        provider = self._makeOne(pyramid.tests.test_config)\n        expected = os.path.join(here, resource_name)\n        result = provider.get_resource_filename(None, resource_name)\n>       self.assertEqual(result, expected)\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:345: AssertionError\n___________________ TestPackageAssetSource.test_get_filename ___________________\n\nself = <r2e_tests.test_config.test_assets.TestPackageAssetSource testMethod=test_get_filename>\n\n    def test_get_filename(self):\n        source = self._makeOne('')\n>       self.assertEqual(source.get_filename('test_assets.py'),\n                         os.path.join(here, 'test_assets.py'))\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:716: AssertionError\n_____________ TestPackageAssetSource.test_get_filename_with_prefix _____________\n\nself = <r2e_tests.test_config.test_assets.TestPackageAssetSource testMethod=test_get_filename_with_prefix>\n\n    def test_get_filename_with_prefix(self):\n        source = self._makeOne('test_assets.py')\n>       self.assertEqual(source.get_filename(''),\n                         os.path.join(here, 'test_assets.py'))\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:721: AssertionError\n_________ TestI18NConfiguratorMixin.test_add_translation_dirs_abspath __________\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_abspath>\n\n    def test_add_translation_dirs_abspath(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n>       config.add_translation_dirs(locale)\n\nr2e_tests/test_config/test_i18n.py:86: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x746521354190>\nspecs = ('/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale',)\nintrospectables = []\nspec = '/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\npackage_name = None\n\n    @action_method\n    def add_translation_dirs(self, *specs):\n        \"\"\" Add one or more :term:`translation directory` paths to the\n        current configuration state.  The ``specs`` argument is a\n        sequence that may contain absolute directory paths\n        (e.g. ``/usr/share/locale``) or :term:`asset specification`\n        names naming a directory path (e.g. ``some.package:locale``)\n        or a combination of the two.\n    \n        Example:\n    \n        .. code-block:: python\n    \n           config.add_translation_dirs('/usr/share/locale',\n                                       'some.package:locale')\n    \n        Later calls to ``add_translation_dir`` insert directories into the\n        beginning of the list of translation directories created by earlier\n        calls.  This means that the same translation found in a directory\n        added later in the configuration process will be found before one\n        added earlier in the configuration process.  However, if multiple\n        specs are provided in a single call to ``add_translation_dirs``, the\n        directories will be inserted into the beginning of the directory list\n        in the order they're provided in the ``*specs`` list argument (items\n        earlier in the list trump ones later in the list).\n        \"\"\"\n        directories = []\n        introspectables = []\n    \n        for spec in specs[::-1]: # reversed\n            package_name, filename = self._split_spec(spec)\n            if package_name is None: # absolute filename\n                directory = filename\n            else:\n                __import__(package_name)\n                package = sys.modules[package_name]\n                directory = os.path.join(package_path(package), filename)\n    \n            if not os.path.isdir(os.path.realpath(directory)):\n>               raise ConfigurationError('\"%s\" is not a directory' %\n                                         directory)\nE               pyramid.exceptions.ConfigurationError: \"/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale\" is not a directory\n\npyramid/config/i18n.py:86: ConfigurationError\n________ TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec ________\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_asset_spec>\n\n    def test_add_translation_dirs_asset_spec(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale])\nE       AssertionError: Lists differ: ['/ho[70 chars]72633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'] != ['/ho[70 chars]72633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       - ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale']\nE       ?                                                                                                      -- ^^^^^\nE       \nE       + ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale']\nE       ?                                                                                                       ^^^\n\nr2e_tests/test_config/test_i18n.py:54: AssertionError\n_ TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec_existing_translation_dirs _\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_asset_spec_existing_translation_dirs>\n\n    def test_add_translation_dirs_asset_spec_existing_translation_dirs(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        directories = ['abc']\n        config.registry.registerUtility(directories, ITranslationDirectories)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale')\n        result = config.registry.getUtility(ITranslationDirectories)\n>       self.assertEqual(result, [locale, 'abc'])\nE       AssertionError: Lists differ: ['/ho[77 chars]9024cdab685483807a/pyramid/tests/pkgs/localeapp/locale', 'abc'] != ['/ho[77 chars]9024cdab685483807a/r2e_tests/pkgs/localeapp/locale', 'abc']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       - ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale',\nE       ?                                                                                                      -- ^^^^^\nE       \nE       + ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale',\nE       ?                                                                                                       ^^^\nE       \nE          'abc']\n\nr2e_tests/test_config/test_i18n.py:64: AssertionError\n______ TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs ______\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_multiple_specs>\n\n    def test_add_translation_dirs_multiple_specs(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale',\n                                    'pyramid.tests.pkgs.localeapp:locale2')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale, locale2])\nE       AssertionError: Lists differ: ['/ho[91 chars]807a/pyramid/tests/pkgs/localeapp/locale', '/h[130 chars]le2'] != ['/ho[91 chars]807a/r2e_tests/pkgs/localeapp/locale', '/home/[122 chars]le2']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       Diff is 1002 characters long. Set self.maxDiff to None to see it.\n\nr2e_tests/test_config/test_i18n.py:71: AssertionError\n_ TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs_multiple_calls _\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_multiple_specs_multiple_calls>\n\n    def test_add_translation_dirs_multiple_specs_multiple_calls(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale',\n                                    'pyramid.tests.pkgs.localeapp:locale2')\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale3')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale3, locale, locale2])\nE       AssertionError: Lists differ: ['/ho[91 chars]807a/pyramid/tests/pkgs/localeapp/locale3', '/[269 chars]le2'] != ['/ho[91 chars]807a/r2e_tests/pkgs/localeapp/locale3', '/home[257 chars]le2']\nE       \nE       First differing element 0:\nE       '/hom[69 chars]72633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale3'\nE       '/hom[69 chars]72633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale3'\nE       \nE       Diff is 1504 characters long. Set self.maxDiff to None to see it.\n\nr2e_tests/test_config/test_i18n.py:80: AssertionError\n___________________ ConfiguratorTests.test_ctor_no_registry ____________________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_ctor_no_registry>\n\n    def test_ctor_no_registry(self):\n        import sys\n        from pyramid.interfaces import ISettings\n        from pyramid.config import Configurator\n        from pyramid.interfaces import IRendererFactory\n        config = Configurator()\n        this_pkg = sys.modules['pyramid.tests.test_config']\n        self.assertTrue(config.registry.getUtility(ISettings))\n>       self.assertEqual(config.package, this_pkg)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:68: AssertionError\n_________ ConfiguratorTests.test_ctor_noreg_debug_logger_None_default __________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_ctor_noreg_debug_logger_None_default>\n\n    def test_ctor_noreg_debug_logger_None_default(self):\n        from pyramid.interfaces import IDebugLogger\n        config = self._makeOne()\n        logger = config.registry.getUtility(IDebugLogger)\n>       self.assertEqual(logger.name, 'pyramid.tests.test_config')\nE       AssertionError: 'r2e_tests.test_config' != 'pyramid.tests.test_config'\nE       - r2e_tests.test_config\nE       ?  ^^^\nE       + pyramid.tests.test_config\nE       ? ++ ^^^^^\n\nr2e_tests/test_config/test_init.py:124: AssertionError\n_____________ ConfiguratorTests.test_include_constant_root_package _____________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_include_constant_root_package>\n\n    def test_include_constant_root_package(self):\n        from pyramid import tests\n        from pyramid.tests import test_config\n        config = self._makeOne(root_package=tests)\n        results = {}\n        def include(config):\n            results['package'] = config.package\n            results['root_package'] = config.root_package\n        config.include(include)\n        self.assertEqual(results['root_package'], tests)\n>       self.assertEqual(results['package'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:777: AssertionError\n_______________ ConfiguratorTests.test_scan_integration_conflict _______________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_scan_integration_conflict>\n\n    def test_scan_integration_conflict(self):\n        from pyramid.tests.test_config.pkgs import selfscan\n        from pyramid.config import Configurator\n        c = Configurator()\n        c.scan(selfscan)\n        c.scan(selfscan)\n        try:\n>           c.commit()\n\nr2e_tests/test_config/test_init.py:1039: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/config/__init__.py:654: in commit\n    self.action_state.execute_actions(introspector=self.introspector)\npyramid/config/__init__.py:1163: in execute_actions\n    action = next(pending_actions, None)\npyramid/config/__init__.py:1121: in resume\n    for a, b in zip_longest(actions, executed_actions):\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nactions = [{'args': (), 'callable': <function ViewsConfiguratorMixin.add_view.<locals>.register at 0x74652143e790>, 'discriminat...652143eca0>, 'discriminator': ('view', None, 'two', None, 'd41d8cd98f00b204e9800998ecf8427e'), 'includepath': (), ...}]\n\n    def resolveConflicts(actions):\n        \"\"\"Resolve conflicting actions\n    \n        Given an actions list, identify and try to resolve conflicting actions.\n        Actions conflict if they have the same non-None discriminator.\n        Conflicting actions can be resolved if the include path of one of\n        the actions is a prefix of the includepaths of the other\n        conflicting actions and is unequal to the include paths in the\n        other conflicting actions.\n        \"\"\"\n    \n        def orderandpos(v):\n            n, v = v\n            if not isinstance(v, dict):\n                # old-style tuple action\n                v = expand_action(*v)\n            return (v['order'] or 0, n)\n    \n        sactions = sorted(enumerate(actions), key=orderandpos)\n    \n        def orderonly(v):\n            n, v = v\n            if not isinstance(v, dict):\n                # old-style tuple action\n                v = expand_action(*v)\n            return v['order'] or 0\n    \n        for order, actiongroup in itertools.groupby(sactions, orderonly):\n            # \"order\" is an integer grouping. Actions in a lower order will be\n            # executed before actions in a higher order.  All of the actions in\n            # one grouping will be executed (its callable, if any will be called)\n            # before any of the actions in the next.\n    \n            unique = {}\n            output = []\n    \n            for i, action in actiongroup:\n                # Within an order, actions are executed sequentially based on\n                # original action ordering (\"i\").\n    \n                if not isinstance(action, dict):\n                    # old-style tuple action\n                    action = expand_action(*action)\n    \n                # \"ainfo\" is a tuple of (order, i, action) where \"order\" is a\n                # user-supplied grouping, \"i\" is an integer expressing the relative\n                # position of this action in the action list being resolved, and\n                # \"action\" is an action dictionary.  The purpose of an ainfo is to\n                # associate an \"order\" and an \"i\" with a particular action; \"order\"\n                # and \"i\" exist for sorting purposes after conflict resolution.\n                ainfo = (order, i, action)\n    \n                discriminator = undefer(action['discriminator'])\n                action['discriminator'] = discriminator\n    \n                if discriminator is None:\n                    # The discriminator is None, so this action can never conflict.\n                    # We can add it directly to the result.\n                    output.append(ainfo)\n                    continue\n    \n                L = unique.setdefault(discriminator, [])\n                L.append(ainfo)\n    \n            # Check for conflicts\n            conflicts = {}\n    \n            for discriminator, ainfos in unique.items():\n                # We use (includepath, order, i) as a sort key because we need to\n                # sort the actions by the paths so that the shortest path with a\n                # given prefix comes first.  The \"first\" action is the one with the\n                # shortest include path.  We break sorting ties using \"order\", then\n                # \"i\".\n                def bypath(ainfo):\n                    path, order, i = ainfo[2]['includepath'], ainfo[0], ainfo[1]\n                    return path, order, i\n    \n                ainfos.sort(key=bypath)\n                ainfo, rest = ainfos[0], ainfos[1:]\n                output.append(ainfo)\n                _, _, action = ainfo\n                basepath, baseinfo, discriminator = (\n                    action['includepath'],\n                    action['info'],\n                    action['discriminator'],\n                    )\n    \n                for _, _, action in rest:\n                    includepath = action['includepath']\n                    # Test whether path is a prefix of opath\n                    if (includepath[:len(basepath)] != basepath or  # not a prefix\n                            includepath == basepath):\n                        L = conflicts.setdefault(discriminator, [baseinfo])\n                        L.append(action['info'])\n    \n            if conflicts:\n>               raise ConfigurationConflictError(conflicts)\nE               pyramid.exceptions.ConfigurationConflictError: Conflicting configuration actions\nE                 For: ('view', None, '', None, 'd41d8cd98f00b204e9800998ecf8427e')\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/__init__.py:\nE                       def abc(request):\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/__init__.py:\nE                       def abc(request):\nE                 For: ('view', None, 'two', None, 'd41d8cd98f00b204e9800998ecf8427e')\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/another.py:\nE                       def two(request):\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/another.py:\nE                       def two(request):\n\npyramid/config/__init__.py:1299: ConfigurationConflictError\n\nDuring handling of the above exception, another exception occurred:\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_scan_integration_conflict>\n\n    def test_scan_integration_conflict(self):\n        from pyramid.tests.test_config.pkgs import selfscan\n        from pyramid.config import Configurator\n        c = Configurator()\n        c.scan(selfscan)\n        c.scan(selfscan)\n        try:\n            c.commit()\n        except ConfigurationConflictError as why:\n            def scanconflicts(e):\n                conflicts = e._conflicts.values()\n                for conflict in conflicts:\n                    for confinst in conflict:\n                        yield confinst.src\n            which = list(scanconflicts(why))\n            self.assertEqual(len(which), 4)\n>           self.assertTrue(\"@view_config(renderer='string')\" in which)\nE           AssertionError: False is not true\n\nr2e_tests/test_config/test_init.py:1048: AssertionError\n_______ ConfiguratorTests.test_setup_registry_debug_logger_None_default ________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_setup_registry_debug_logger_None_default>\n\n    def test_setup_registry_debug_logger_None_default(self):\n        from pyramid.registry import Registry\n        from pyramid.interfaces import IDebugLogger\n        reg = Registry()\n        config = self._makeOne(reg)\n        config.setup_registry()\n        logger = reg.getUtility(IDebugLogger)\n>       self.assertEqual(logger.name, 'pyramid.tests.test_config')\nE       AssertionError: 'r2e_tests.test_config' != 'pyramid.tests.test_config'\nE       - r2e_tests.test_config\nE       ?  ^^^\nE       + pyramid.tests.test_config\nE       ? ++ ^^^^^\n\nr2e_tests/test_config/test_init.py:444: AssertionError\n____ TestConfigurator_add_directive.test_add_directive_with_custom_callable ____\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_add_directive_with_custom_callable>\n\n    def test_add_directive_with_custom_callable(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n                'dummy_callable', 'pyramid.tests.test_config.dummy_callable')\n        self.assertTrue(hasattr(config, 'dummy_callable'))\n        config.dummy_callable('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1247: AssertionError\n________ TestConfigurator_add_directive.test_add_directive_with_partial ________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_add_directive_with_partial>\n\n    def test_add_directive_with_partial(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n                'dummy_partial', 'pyramid.tests.test_config.dummy_partial')\n        self.assertTrue(hasattr(config, 'dummy_partial'))\n        config.dummy_partial()\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'partial')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1234: AssertionError\n_________ TestConfigurator_add_directive.test_extend_with_dotted_name __________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_extend_with_dotted_name>\n\n    def test_extend_with_dotted_name(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n            'dummy_extend', 'pyramid.tests.test_config.dummy_extend')\n        self.assertTrue(hasattr(config, 'dummy_extend'))\n        config.dummy_extend('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1221: AssertionError\n_______ TestConfigurator_add_directive.test_extend_with_python_callable ________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_extend_with_python_callable>\n\n    def test_extend_with_python_callable(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n            'dummy_extend', dummy_extend)\n        self.assertTrue(hasattr(config, 'dummy_extend'))\n        config.dummy_extend('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1260: AssertionError\n_________ TestConfigurator__add_predicate.test_factory_as_dotted_name __________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator__add_predicate testMethod=test_factory_as_dotted_name>\n\n    def test_factory_as_dotted_name(self):\n        config = self._makeOne()\n    \n        def _fakeAction(discriminator, callable=None, args=(),\n                        kw=None, order=0, introspectables=(), **extra):\n            self.assertEqual(len(introspectables), 1)\n            self.assertEqual(introspectables[0]['name'], 'testing')\n            self.assertEqual(introspectables[0]['factory'], DummyPredicate)\n    \n        config.action = _fakeAction\n>       config._add_predicate(\n            'route',\n            'testing',\n            'pyramid.tests.test_config.test_init.DummyPredicate'\n            )\n\nr2e_tests/test_config/test_init.py:1324: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/config/__init__.py:543: in _add_predicate\n    self.action(discriminator, register, introspectables=(intr,),\nr2e_tests/test_config/test_init.py:1321: in _fakeAction\n    self.assertEqual(introspectables[0]['factory'], DummyPredicate)\nE   AssertionError: <class 'pyramid.tests.test_config.test_init.DummyPredicate'> != <class 'r2e_tests.test_config.test_init.DummyPredicate'>\n____ TestViewsConfigurationMixin.test_add_static_view_package_here_relative ____\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_static_view_package_here_relative>\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n>       self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\nE       AssertionError: Lists differ: [(<py[39 chars]46521be4f70>, 'static', 'r2e_tests.test_config:files', {})] != [(<py[39 chars]46521be4f70>, 'static', 'pyramid.tests.test_config:files', {})]\nE       \nE       First differing element 0:\nE       (<pyr[37 chars]746521be4f70>, 'static', 'r2e_tests.test_config:files', {})\nE       (<pyr[37 chars]746521be4f70>, 'static', 'pyramid.tests.test_config:files', {})\nE       \nE         [(<pyramid.config.Configurator object at 0x746521be4f70>,\nE           'static',\nE       -   'r2e_tests.test_config:files',\nE       ?     ^^^\nE       \nE       +   'pyramid.tests.test_config:files',\nE       ?    ++ ^^^^^\nE       \nE           {})]\n\nr2e_tests/test_config/test_views.py:1936: AssertionError\n_______ TestViewsConfigurationMixin.test_add_view_with_template_renderer _______\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer>\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n    \n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_views.py:1143: AssertionError\n_ TestViewsConfigurationMixin.test_add_view_with_template_renderer_no_callable _\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer_no_callable>\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_views.py:1184: AssertionError\n_________ TestStaticURLInfo.test_generate_url_cachebust_with_overrides _________\n\nself = <r2e_tests.test_config.test_views.TestStaticURLInfo testMethod=test_generate_url_cachebust_with_overrides>\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n>           self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\nE           AssertionError: 'http://example.com/static/foo.png?x=foo' != 'http://example.com/static/foo.png?x=bar'\nE           - http://example.com/static/foo.png?x=foo\nE           ?                                     ^^^\nE           + http://example.com/static/foo.png?x=bar\nE           ?                                     ^^^\n\nr2e_tests/test_config/test_views.py:3015: AssertionError\n___________________ Test_view_description.test_without_text ____________________\n\nself = <r2e_tests.test_config.test_views.Test_view_description testMethod=test_without_text>\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n>       self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\nE       AssertionError: 'function r2e_tests.test_config.test_views.view' != 'function pyramid.tests.test_config.test_views.view'\nE       - function r2e_tests.test_config.test_views.view\nE       ?           ^^^\nE       + function pyramid.tests.test_config.test_views.view\nE       ?          ++ ^^^^^\n\nr2e_tests/test_config/test_views.py:3186: AssertionError\n_______________ TestPRequestCommand.test_command_display_headers _______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_display_headers>\n\n    def test_command_display_headers(self):\n        command = self._makeOne(\n            ['', '--display-headers', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(\n            self._out,\n            ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc'])\nE       AssertionError: Lists differ: ['200 OK', b'abc'] != ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc']\nE       \nE       First differing element 1:\nE       b'abc'\nE       'Content-Type: text/html; charset=UTF-8'\nE       \nE       Second list contains 1 additional elements.\nE       First extra element 2:\nE       'abc'\nE       \nE       - ['200 OK', b'abc']\nE       + ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc']\n\nr2e_tests/test_scripts/test_prequest.py:202: AssertionError\n_________ TestPRequestCommand.test_command_has_content_type_header_var _________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_content_type_header_var>\n\n    def test_command_has_content_type_header_var(self):\n        command = self._makeOne(\n            ['', '--header=content-type:app/foo','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['CONTENT_TYPE'], 'app/foo')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:92: AssertionError\n_____________ TestPRequestCommand.test_command_has_good_header_var _____________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_good_header_var>\n\n    def test_command_has_good_header_var(self):\n        command = self._makeOne(\n            ['', '--header=name:value','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:69: AssertionError\n__________ TestPRequestCommand.test_command_has_multiple_header_vars ___________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_multiple_header_vars>\n\n    def test_command_has_multiple_header_vars(self):\n        command = self._makeOne(\n            ['',\n             '--header=name:value',\n             '--header=name2:value2',\n             'development.ini',\n             '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._environ['HTTP_NAME2'], 'value2')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:107: AssertionError\n_________________ TestPRequestCommand.test_command_method_get __________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_get>\n\n    def test_command_method_get(self):\n        command = self._makeOne(['', '--method=GET', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'GET')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:116: AssertionError\n_______________ TestPRequestCommand.test_command_method_options ________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_options>\n\n    def test_command_method_options(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=OPTIONS', 'development.ini',\n                                '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'OPTIONS')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:184: AssertionError\n________________ TestPRequestCommand.test_command_method_patch _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_patch>\n\n    def test_command_method_patch(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PATCH', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PATCH')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:158: AssertionError\n_________________ TestPRequestCommand.test_command_method_post _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_post>\n\n    def test_command_method_post(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=POST', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'POST')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:130: AssertionError\n_______________ TestPRequestCommand.test_command_method_propfind _______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_propfind>\n\n    def test_command_method_propfind(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PROPFIND', 'development.ini',\n                                '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PROPFIND')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:171: AssertionError\n_________________ TestPRequestCommand.test_command_method_put __________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_put>\n\n    def test_command_method_put(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PUT', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PUT')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:144: AssertionError\n________ TestPRequestCommand.test_command_path_doesnt_start_with_slash _________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_path_doesnt_start_with_slash>\n\n    def test_command_path_doesnt_start_with_slash(self):\n        command = self._makeOne(['', 'development.ini', 'abc'])\n        command.run()\n        self.assertEqual(self._path_info, '/abc')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:50: AssertionError\n__________________ TestPRequestCommand.test_command_two_args ___________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_two_args>\n\n    def test_command_two_args(self):\n        command = self._makeOne(['', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:42: AssertionError\n________________ TestPRequestCommand.test_command_w_basic_auth _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_w_basic_auth>\n\n    def test_command_w_basic_auth(self):\n        command = self._makeOne(\n            ['', '--login=user:password',\n                 '--header=name:value','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._environ['HTTP_AUTHORIZATION'],\n                        'Basic dXNlcjpwYXNzd29yZA==')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:82: AssertionError\n______________ TestPRequestCommand.test_command_with_query_string ______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_with_query_string>\n\n    def test_command_with_query_string(self):\n        command = self._makeOne(['', 'development.ini', '/abc?a=1&b=2&c'])\n        command.run()\n        self.assertEqual(self._environ['QUERY_STRING'], 'a=1&b=2&c')\n        self.assertEqual(self._path_info, '/abc')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:193: AssertionError\n_______________ TestPRoutesCommand.test_config_format_ini_commas _______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_commas>\n\n    def test_config_format_ini_commas(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method,name')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:728: AssertionError\n______________ TestPRoutesCommand.test_config_format_ini_newlines ______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_newlines>\n\n    def test_config_format_ini_newlines(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method\\nname')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:662: AssertionError\n_______________ TestPRoutesCommand.test_config_format_ini_spaces _______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_spaces>\n\n    def test_config_format_ini_spaces(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method name')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:695: AssertionError\n_________ TestPRoutesCommand.test_one_route_all_methods_view_only_post _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_all_methods_view_only_post>\n\n    def test_one_route_all_methods_view_only_post(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method='POST'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:310: AssertionError\n_________ TestPRoutesCommand.test_one_route_only_post_view_all_methods _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_only_post_view_all_methods>\n\n    def test_one_route_only_post_view_all_methods(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:337: AssertionError\n________ TestPRoutesCommand.test_one_route_only_post_view_post_and_get _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_only_post_view_post_and_get>\n\n    def test_one_route_only_post_view_post_and_get(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=('POST', 'GET')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:365: AssertionError\n_____ TestPRoutesCommand.test_one_route_with_long_name_one_view_registered _____\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_with_long_name_one_view_registered>\n\n    def test_one_route_with_long_name_one_view_registered(self):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRouteRequest\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IView\n        registry = self._makeRegistry()\n    \n        def view():pass\n    \n        class IMyRoute(Interface):\n            pass\n    \n        registry.registerAdapter(\n            view,\n            (IViewClassifier, IMyRoute, Interface),\n            IView, ''\n        )\n    \n        registry.registerUtility(IMyRoute, IRouteRequest,\n                                 name='very_long_name_123')\n    \n        command = self._makeOne()\n        route = dummy.DummyRoute(\n            'very_long_name_123',\n            '/and_very_long_pattern_as_well'\n        )\n        mapper = dummy.DummyMapper(route)\n        command._get_mapper = lambda *arg: mapper\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()[:3]\n>       self.assertEqual(\n            compare_to,\n            ['very_long_name_123',\n             '/and_very_long_pattern_as_well',\n             'pyramid.tests.test_scripts.test_proutes.view']\n        )\nE       AssertionError: Lists differ: ['ver[36 chars]ttern_as_well', 'r2e_tests.test_scripts.test_proutes.view'] != ['ver[36 chars]ttern_as_well', 'pyramid.tests.test_scripts.test_proutes.view']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view'\nE       'pyramid.tests.test_scripts.test_proutes.view'\nE       \nE         ['very_long_name_123',\nE          '/and_very_long_pattern_as_well',\nE       -  'r2e_tests.test_scripts.test_proutes.view']\nE       ?    ^^^\nE       \nE       +  'pyramid.tests.test_scripts.test_proutes.view']\nE       ?   ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:196: AssertionError\n______ TestPRoutesCommand.test_route_is_get_view_request_method_not_post _______\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_is_get_view_request_method_not_post>\n\n    def test_route_is_get_view_request_method_not_post(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='GET')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            'GET'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'GET'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'GET']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'GET']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'GET']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:505: AssertionError\n____________ TestPRoutesCommand.test_route_request_method_mismatch _____________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_request_method_mismatch>\n\n    def test_route_request_method_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method='GET'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '<route', 'mismatch>'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1[20 chars]ch>'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.v[24 chars]ch>']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE         ['foo',\nE          '/a/b',\nE       -  'r2e_tests.test_scripts.test_proutes.view1',\nE       ?    ^^^\nE       \nE       +  'pyramid.tests.test_scripts.test_proutes.view1',\nE       ?   ++ ^^^^^\nE       \nE          '<route',\nE          'mismatch>']\n\nr2e_tests/test_scripts/test_proutes.py:394: AssertionError\n__________________ TestPRoutesCommand.test_route_static_views __________________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_static_views>\n\n    def test_route_static_views(self):\n        from pyramid.renderers import null_renderer as nr\n        config = self._makeConfig(autocommit=True)\n        config.add_static_view('static', 'static', cache_max_age=3600)\n        path2 = os.path.normpath('/var/www/static')\n        config.add_static_view(name='static2', path=path2)\n        config.add_static_view(\n            name='pyramid_scaffold',\n            path='pyramid:scaffolds/starter/+package+/static'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 5)\n    \n        expected = [\n            ['__static/', '/static/*subpath',\n             'pyramid.tests.test_scripts:static/', '*'],\n            ['__static2/', '/static2/*subpath', path2 + os.sep, '*'],\n            ['__pyramid_scaffold/', '/pyramid_scaffold/*subpath',\n             'pyramid:scaffolds/starter/+package+/static/',  '*'],\n        ]\n    \n        for index, line in enumerate(L[2:]):\n            data = line.split()\n>           self.assertEqual(data, expected[index])\nE           AssertionError: Lists differ: ['__static/', '/static/*subpath', 'r2e_tests.test_scripts:static/', '*'] != ['__static/', '/static/*subpath', 'pyramid.tests.test_scripts:static/', '*']\nE           \nE           First differing element 2:\nE           'r2e_tests.test_scripts:static/'\nE           'pyramid.tests.test_scripts:static/'\nE           \nE           - ['__static/', '/static/*subpath', 'r2e_tests.test_scripts:static/', '*']\nE           ?                                     ^^^\nE           \nE           + ['__static/', '/static/*subpath', 'pyramid.tests.test_scripts:static/', '*']\nE           ?                                    ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:425: AssertionError\n___________ TestPRoutesCommand.test_single_route_one_view_registered ___________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_single_route_one_view_registered>\n\n    def test_single_route_one_view_registered(self):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRouteRequest\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IView\n        registry = self._makeRegistry()\n    \n        def view():pass\n        class IMyRoute(Interface):\n            pass\n        registry.registerAdapter(view,\n                                 (IViewClassifier, IMyRoute, Interface),\n                                 IView, '')\n        registry.registerUtility(IMyRoute, IRouteRequest, name='a')\n        command = self._makeOne()\n        route = dummy.DummyRoute('a', '/a')\n        mapper = dummy.DummyMapper(route)\n        command._get_mapper = lambda *arg: mapper\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()[:3]\n>       self.assertEqual(\n            compare_to,\n            ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\n        )\nE       AssertionError: Lists differ: ['a', '/a', 'r2e_tests.test_scripts.test_proutes.view'] != ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view'\nE       'pyramid.tests.test_scripts.test_proutes.view'\nE       \nE       - ['a', '/a', 'r2e_tests.test_scripts.test_proutes.view']\nE       ?               ^^^\nE       \nE       + ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\nE       ?              ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:156: AssertionError\n______________________ TestPRoutesCommand.test_view_glob _______________________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_view_glob>\n\n    def test_view_glob(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        config.add_route('bar', '/b/a')\n        config.add_view(\n            route_name='bar',\n            view=view2,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        command.options.glob = '*foo*'\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '!POST,*'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:576: AssertionError\n_____________ TestPRoutesCommand.test_view_request_method_not_post _____________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_view_request_method_not_post>\n\n    def test_view_request_method_not_post(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '!POST,*'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:535: AssertionError\n_____ TestPViewsCommand.test_views_command_single_view_function_traversal ______\n\nself = <r2e_tests.test_scripts.test_pviews.TestPViewsCommand testMethod=test_views_command_single_view_function_traversal>\n\n    def test_views_command_single_view_function_traversal(self):\n        from pyramid.registry import Registry\n        registry = Registry()\n        command = self._makeOne(registry=registry)\n        L = []\n        command.out = L.append\n        def view(): pass\n        view.__request_attrs__ = {'context': 'context', 'view_name': 'a'}\n        command._find_view = lambda arg1: view\n        command.args = ('/foo/bar/myapp.ini#myapp', '/a')\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(L[1], 'URL = /a')\n        self.assertEqual(L[3], '    context: context')\n        self.assertEqual(L[4], '    view name: a')\n>       self.assertEqual(L[8],\n                         '    pyramid.tests.test_scripts.test_pviews.view')\nE       AssertionError: '    r2e_tests.test_scripts.test_pviews.view' != '    pyramid.tests.test_scripts.test_pviews.view'\nE       -     r2e_tests.test_scripts.test_pviews.view\nE       ?      ^^^\nE       +     pyramid.tests.test_scripts.test_pviews.view\nE       ?     ++ ^^^^^\n\nr2e_tests/test_scripts/test_pviews.py:296: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_allows_other_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_context\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_for_\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_no_view_argument\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_allows_other_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash_custom_response\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_context\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_for_\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_no_view_argument\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_absolute\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_package_relative\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instance\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instance_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_class_method_no_attr\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_trumps_for\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_custom_more_preds_first_bests_fewer_preds_last\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_custom_predicate_bests_standard_predicate\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_default_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_no_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_default_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_no_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_multiview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_mulview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only_misconfiguration\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only_no_regular_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_register_secured_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for__as_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for_as_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_mixed_case_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview___discriminator__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_call_ordering\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_context_superclass_then_subclass\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_exception_superclass_then_subclass\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_multiview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_register_secured_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_same_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_no_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_check_csrf_predicates_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_csrf_header\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_csrf_param\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_decorator\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_decorator_tuple\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_default_permission_no_explicit_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_default_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_function_callable\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_function_callable_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_badregex\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_missing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_mapper\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_missing_csrf_header\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_name_unicode\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_no_default_permission_no_explicit_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_nonexistant_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_badregex\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_get_implies_head\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_conflict\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_and_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_noniface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_route_name_exception\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_introspector_missing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_no_renderer_factory\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_with_renderer_factory\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_conflicts\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_doesnt_conflict\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_kwarg\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_xhr_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_xhr_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_wrapped_view_is_decorated\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_views_with_accept_multiview_replaces_existing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_function\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_no_explicit_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_with_explicit_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_set_view_mapper\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_set_view_mapper_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate_with_mismatch\nPASSED r2e_tests/test_1.py::Test_requestonly::test_defaults\nPASSED r2e_tests/test_1.py::Test_requestonly::test_otherattr\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_IException\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_IException_subinterface\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_exception_class\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_exception_instance\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__intermediate_not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__raise_not_found_isnt_interpreted_as_pred_mismatch\nPASSED r2e_tests/test_1.py::TestMultiView::test___call_permissive_has_call_permissive\nPASSED r2e_tests/test_1.py::TestMultiView::test___call_permissive_has_no_call_permissive\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__with_accept_match\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__with_accept_miss\nPASSED r2e_tests/test_1.py::TestMultiView::test__call_permissive__not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test_add\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash_override_accept\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash_override_accept2\nPASSED r2e_tests/test_1.py::TestMultiView::test_class_implements_ISecuredView\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_best_match_returns_None\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_no_self_accepts\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_request_has_no_accept\nPASSED r2e_tests/test_1.py::TestMultiView::test_instance_implements_ISecuredView\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_predicate_fails\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_predicate_succeeds\nPASSED r2e_tests/test_1.py::TestMultiView::test_multiple_with_functions_as_views\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted_no_match_with__permitted__\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted_no_views\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test__view_as_function_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_context_and_request_and_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_different\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_different_with_existing_original_view\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_same\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_view_is_None\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_already_exists\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebust_prevented\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_abspath\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_for_more_specific_path\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_overwrite\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_overwrite_explicit\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_package_root\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_noendslash\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_noscheme\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_withendslash\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_context\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_for_\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_permission\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_renderer\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_route_prefix\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_missing\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_quoting\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_registration_miss\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_route_url\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_slash_in_name1\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_slash_in_name2\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_abspath\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_nomatch\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_quoted_remote\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_unquoted_local\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_with_custom_anchor\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_with_custom_query\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_verifyClass\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_verifyObject\nPASSED r2e_tests/test_1.py::Test_view_description::test_with_text\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_object_event_subscriber\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_default_resource_iface_means_Interface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_nodefault_resource_iface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter_dottednames\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter_self\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_defaults\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_dottednames\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_iface_specified\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_predicate\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_default_type_predicates_False\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_default_type_predicates_True\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_specific_type_and_predicates_False\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_specific_type_and_predicates_True\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_default_iface_means_Interface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_introspectables\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_nondefault_iface\nPASSED r2e_tests/test_config/test_adapters.py::Test_eventonly::test_defaults\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test__override_already_registered\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test__override_not_yet_registered\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_absfile\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_file\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_absfile\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_directory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_missing_abspath\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_package\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_samename\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_override_returns_True\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_override_returns_False\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_override_returns_values\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_class_conforms_to_IPEP302Loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_class_conforms_to_IPackageOverrides\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_package_already_has_loader_of_different_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_package_already_has_loader_of_same_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_registers_loader_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_sets_loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_sets_local_state\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_filtered_sources\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_code_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_code_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_data_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_data_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_filename\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_source_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_source_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_has_resource\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_has_resource_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_directory\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_emptystring\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_file\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_instance_conforms_to_IPEP302Loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_instance_conforms_to_IPackageOverrides\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_is_package_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_is_package_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestDirectoryOverride::test_it_match\nPASSED r2e_tests/test_config/test_assets.py::TestDirectoryOverride::test_it_no_match\nPASSED r2e_tests/test_config/test_assets.py::TestFileOverride::test_it_match\nPASSED r2e_tests/test_config/test_assets.py::TestFileOverride::test_it_no_match\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable_and_no_name\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_text_type_name\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_unnamed_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_multiple_request_methods_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_request_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_request_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_response_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_response_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory_as_None\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_session_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_session_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_multiple_request_properties\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_multiple_request_properties_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_callable\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_property\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_unnamed_callable\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_missing_dir\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_no_specs\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_set_locale_negotiator\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_set_locale_negotiator_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__matches\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__matches_no_action_wrap\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__missing_when_directives_dont_exist\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__missing_when_directives_exist\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_adds__lock\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_adds_clear_view_lookup_cache\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_has_listeners\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_notify\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_queryAdapterOrSelf\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_registerSelfAdapter\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_already_absolute\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_notastring\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_relative\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_autocommit_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_autocommit_with_introspectables_introspection_off\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_kw_is_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_kw_is_not_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_with_config_info\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_without_config_info\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_nonautocommit_with_introspectables_introspection_off\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_autocommit_no_conflicts\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_begin\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_begin_with_request\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_resolved_with_include\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_resolved_with_two_includes_and_local\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_simple\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_with_two_includes\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_conflict_set_forbidden_view\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_conflict_set_notfound_view\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_alternate_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_authentication_policy\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_authorization_policy_only\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_permission\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_view_mapper\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_webob_response_adapter_registered\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_exceptionresponse_view_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_exceptionresponse_view_custom\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_httpexception_view_default\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_no_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_custom_settings\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_debug_logger_non_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_session_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_introspection\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_package_registry\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_end\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_hook_zca\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_dotted_name\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_missing_source_file\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_module_defaults_to_includeme\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_module_defaults_to_includeme_missing\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_nested_route_prefix\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_python_callable\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_route_prefix\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_introspector_decorator\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_make_wsgi_app\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_notstring_success\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_string_fail\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_string_success\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_dottedname_package\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_extra_kw\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_ignore\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_onerror\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_alternate_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authentication_policy\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authentication_policy_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authorization_policy_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authorization_policy_only\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_calls_fix_registry\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_custom_settings\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_name\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_non_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_default_permission\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_dottedname_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_explicit_notfound_trumps_iexceptionresponse\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_includes\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_includes_spaces\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_locale_negotiator\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_locale_negotiator_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_no_default_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_exceptionresponse_views\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_view_predicates\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_webob_iresponse_adapter\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_request_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_request_factory_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_response_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_tweens\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_unhook_zca\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package_module\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package_package\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_directive_persists_across_configurator_creations\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_action_method_successful\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_same_name_doesnt_conflict\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator__add_predicate::test_factory_as_object\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_simple\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_includepath\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_includepath_and_info\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_info\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_order\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_dicts\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_error\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_tuples\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_with_introspectable_no_callable\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_it\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_processSpec\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action_error\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action_without_clear\nPASSED r2e_tests/test_config/test_init.py::Test_reentrant_action_functional::test_functional\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_conflict\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_success_dicts\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_success_tuples\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_with_actions_grouped_by_order\nPASSED r2e_tests/test_config/test_init.py::TestGlobalRegistriesIntegration::test_global_registries\nPASSED r2e_tests/test_config/test_init.py::TestGlobalRegistriesIntegration::test_global_registries_empty\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___true_single\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_ctor_get_but_no_head\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_ctor_compilefail\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___false_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_exists_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_exists_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_multi_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___matchdict_is_None\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___true_single\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_text_func_has___text__\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_text_func_repr\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_has_remainder_already\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_matches\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_matches_with_highorder_chars\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_False\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_str\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___false_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_withval\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_False\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_context_has_no_name\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_list_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_str_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_tuple_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_doesnt_provide_superset\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_provides_superset\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_provides_superset_implicit\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_no_authentication_policy\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_text_noniter\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_default_renderers\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_renderer\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_renderer_dottedname_factory\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_defaults\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_discriminator\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_path_no_pattern\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_pattern_with_path\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_attr\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_context\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_permission\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_renderer\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_accept\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_custom_predicates\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_factory\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_factory_dottedname\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_header\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info_highorder\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info_regex\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_pregenerator\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_request_method\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_request_param\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_route_prefix\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_static\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_xhr\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_get_routes_mapper_already_registered\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_get_routes_mapper_not_yet_registered\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_add_permission\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_changing_set_default_csrf_options\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_no_authz_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_no_authz_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_with_authz_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_with_authz_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_no_authn_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_no_authn_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_with_authn_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_with_authn_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_default_csrf_options\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_default_permission\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test__set_settings_as_None\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test__set_settings_as_dictwithvalues\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_None\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_already_registered\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_not_yet_registered\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_get_settings_nosettings\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_get_settings_withsettings\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_all\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_authorization\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_notfound\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_routematch\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_templates\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_default_locale_name\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_fail\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_raises_attribute_error\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_success\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_noargs\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_originals_kept\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_prevent_cachebust\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_prevent_http_cache\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_all\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_assets\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_resources\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_templates\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer_explicitrenderer\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer_twice\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_defaults\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_dottedname\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_multiple\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_single\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_template\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_resources\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy_forget_result\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy_remember_result\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_dottedname\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_instance\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_name_ingress\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_name_main\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_over_ingress\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_over_ingress_iterable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_under_main\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_under_main_iterable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_unsuitable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_conflict\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_distinct\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_over_nonstringoriter\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_under_nonstringoriter\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_underover\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test___call___explicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test___call___implicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_add_explicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_add_implicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_1\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_2\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_3\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_4\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_5\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_conflict_direct\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_conflict_indirect\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_and_under_partials\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_partial\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_partial_with_fallback\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_under_partial\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_under_partial_with_fallback\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_missing_fallbacks\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_multiple_matching_fallbacks\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_partial_fallbacks\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_custom_predicates_can_affect_traversal\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_different_custom_predicates_with_same_hash\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_dict\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_dict_fails\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_string\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_string_fails\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_notted\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_importance_and_number\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_importance_of_predicates\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_number_of_predicates\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_xhr_and_request_method_trump_only_containment\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_predicate_text_is_correct\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_request_method_ordering_hashes_same\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_request_method_sequence\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_has_remainder_already\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_matches\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_matches_with_highorder_chars\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_unknown_predicate\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_annotations\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_with_attr_false\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_with_attr_true\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_nocall\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_method_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_firstname_request_with_secondname\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_no_init\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_init_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_init_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_no_init\nPASSED r2e_tests/test_config/test_util.py::TestNotted::test_it_with_phash_val\nPASSED r2e_tests/test_config/test_util.py::TestNotted::test_it_without_phash_val\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_allows_other_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_context\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_for_\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_no_view_argument\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_allows_other_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash_custom_response\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_context\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_for_\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_no_view_argument\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_absolute\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_here_no_utility_registered\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_package_relative\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instance\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instance_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_class_method_no_attr\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_trumps_for\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_custom_more_preds_first_bests_fewer_preds_last\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_custom_predicate_bests_standard_predicate\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_default_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_no_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_default_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_no_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_multiview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_mulview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only_misconfiguration\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only_no_regular_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_register_secured_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for__as_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for_as_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_mixed_case_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview___discriminator__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_call_ordering\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_context_superclass_then_subclass\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_exception_superclass_then_subclass\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_multiview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_register_secured_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_same_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_no_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_check_csrf_predicates_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_csrf_header\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_csrf_param\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_decorator\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_decorator_tuple\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_default_permission_no_explicit_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_default_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_function_callable\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_function_callable_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_badregex\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_missing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_mapper\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_missing_csrf_header\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_name_unicode\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_no_default_permission_no_explicit_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_nonexistant_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_badregex\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_get_implies_head\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_conflict\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_and_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_noniface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_route_name_exception\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_introspector_missing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_no_renderer_factory\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_with_renderer_factory\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_conflicts\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_doesnt_conflict\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_kwarg\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_xhr_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_xhr_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_wrapped_view_is_decorated\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_views_with_accept_multiview_replaces_existing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_function\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_no_explicit_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_with_explicit_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_set_view_mapper\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_set_view_mapper_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate_with_mismatch\nPASSED r2e_tests/test_config/test_views.py::Test_requestonly::test_defaults\nPASSED r2e_tests/test_config/test_views.py::Test_requestonly::test_otherattr\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_IException\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_IException_subinterface\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_exception_class\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_exception_instance\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__intermediate_not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__raise_not_found_isnt_interpreted_as_pred_mismatch\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call_permissive_has_call_permissive\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call_permissive_has_no_call_permissive\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__with_accept_match\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__with_accept_miss\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call_permissive__not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash_override_accept\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash_override_accept2\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_class_implements_ISecuredView\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_best_match_returns_None\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_no_self_accepts\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_request_has_no_accept\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_instance_implements_ISecuredView\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_predicate_fails\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_predicate_succeeds\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_multiple_with_functions_as_views\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted_no_match_with__permitted__\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted_no_views\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test__view_as_function_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_context_and_request_and_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_different\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_different_with_existing_original_view\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_same\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_view_is_None\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_already_exists\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebust_prevented\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_abspath\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_for_more_specific_path\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_overwrite\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_overwrite_explicit\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_package_root\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_noendslash\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_noscheme\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_withendslash\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_context\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_for_\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_permission\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_route_prefix\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_missing\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_quoting\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_registration_miss\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_route_url\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_slash_in_name1\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_slash_in_name2\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_abspath\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_quoted_remote\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_unquoted_local\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_with_custom_anchor\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_with_custom_query\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_verifyClass\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_verifyObject\nPASSED r2e_tests/test_config/test_views.py::Test_view_description::test_with_text\nPASSED r2e_tests/test_scripts/test_common.py::Test_logging_file_config::test_it\nPASSED r2e_tests/test_scripts/test_common.py::TestParseVars::test_parse_vars_bad\nPASSED r2e_tests/test_scripts/test_common.py::TestParseVars::test_parse_vars_good\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_confirm_override_conflicting_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_force_override_conflicting_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_force_override_site_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_absolute_path\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_multiple_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_single_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_with_path_as_project_target_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_no_project_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_no_scaffold_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_no_scaffold_no_args\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_show_scaffolds_exist\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_show_scaffolds_none_exist\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_dev_pyramid_long_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_dev_pyramid_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_hyphen_in_project_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_long_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_unparsable_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_unknown_scaffold_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pdistreport.py::TestPDistReportCommand::test_no_dists\nPASSED r2e_tests/test_scripts/test_pdistreport.py::TestPDistReportCommand::test_with_dists\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_bad_config_header\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_configures_logging\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_not_enough_args\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_response_has_no_charset\nPASSED r2e_tests/test_scripts/test_prequest.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test__get_mapper\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_bad_args\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_bad_format\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_good_args\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_good_format\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_no_mapper\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_no_routes\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_as_wsgiapp\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_no_view\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_with_no_slash_prefix\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_multiview_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_no_route_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_no_views_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_one_view_registered_with_factory\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_static_routes_included_in_list\nPASSED r2e_tests/test_scripts/test_proutes.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_get_options_no_command\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_get_options_with_command\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_parse_vars_bad\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_parse_vars_good\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_record_pid_not_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_record_pid_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_current_pid_is_not_pid_in_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_current_pid_is_not_written_pid\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_not_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_stale_pid_write_exception\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_unlink_exception\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_no_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_not_a_number\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_no_args\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_bad_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_invalid_pid_in_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_no_such_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile_no_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile_not_a_number\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_flush\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_open\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_write\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_writeline\nPASSED r2e_tests/test_scripts/test_pserve.py::Test__methodwrapper::test___call__fail\nPASSED r2e_tests/test_scripts/test_pserve.py::Test__methodwrapper::test___call__succeed\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_custom_section_override\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_default_shell_option\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_errors_with_unknown_shell\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_check_variable_override_order\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_custom_items\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_default_shell\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_ipython\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_pythonstartup\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_setup_from_options\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_setup\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_list_shells\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_entry_points\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_ordering\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_override\nPASSED r2e_tests/test_scripts/test_pshell.py::Test_python_shell_runner::test_it\nPASSED r2e_tests/test_scripts/test_pshell.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test__get_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_implicit_and_explicit_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_implicit_tweens_only\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_no_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_all_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_none_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_some_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_no_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_no_match_multiview_registered\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_multiview_no_view_registered\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_no_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_traversal\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_traversal_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multi_view_nested\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview_with_permission\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview_with_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_not_found\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_not_found_url_starts_without_slash\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_route\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_route_with_route_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal_with_permission\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal_with_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::Test_main::test_it\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_here_no_utility_registered\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_package_here_relative\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer_no_callable\nFAILED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_with_overrides\nFAILED r2e_tests/test_1.py::Test_view_description::test_without_text - Assert...\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_adapter_dotted_names\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_adapter_introspectables\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_dotted_names\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_directory\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_package\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_file\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_directory\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_package\nFAILED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_no_overrides\nFAILED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_override_returns_None\nFAILED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename\nFAILED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename_with_prefix\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_abspath\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_asset_spec\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_asset_spec_existing_translation_dirs\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_multiple_specs\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_multiple_specs_multiple_calls\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_no_registry\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_debug_logger_None_default\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_constant_root_package\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_conflict\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_None_default\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_add_directive_with_custom_callable\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_add_directive_with_partial\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_with_dotted_name\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_with_python_callable\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator__add_predicate::test_factory_as_dotted_name\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_package_here_relative\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer_no_callable\nFAILED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_with_overrides\nFAILED r2e_tests/test_config/test_views.py::Test_view_description::test_without_text\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_display_headers\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_content_type_header_var\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_good_header_var\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_multiple_header_vars\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_get\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_options\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_patch\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_post\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_propfind\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_put\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_path_doesnt_start_with_slash\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_two_args\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_w_basic_auth\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_with_query_string\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_commas\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_newlines\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_spaces\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_all_methods_view_only_post\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_only_post_view_all_methods\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_only_post_view_post_and_get\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_with_long_name_one_view_registered\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_is_get_view_request_method_not_post\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_request_method_mismatch\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_static_views\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_one_view_registered\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_view_glob\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_view_request_method_not_post\nFAILED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_function_traversal\n======================= 66 failed, 1061 passed in 6.04s ========================\n",
    "new_commit_res_stderr": "",
    "old_commit_res_code": 1,
    "old_commit_res_stdout": "============================= test session starts ==============================\nplatform linux -- Python 3.8.20, pytest-8.3.4, pluggy-1.5.0\nrootdir: /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a\ncollected 1127 items\n\nr2e_tests/test_1.py .......................FF........................F.F [  4%]\n.....................................................................FF. [ 11%]\n........................................................................ [ 17%]\n.........................F.......F                                       [ 20%]\nr2e_tests/test_config/test_adapters.py .FF..............F...             [ 22%]\nr2e_tests/test_config/test_assets.py ....F.F...F...FF.FF................ [ 25%]\n.....................................F.F................................ [ 31%]\n                                                                         [ 31%]\nr2e_tests/test_config/test_factories.py .....................            [ 33%]\nr2e_tests/test_config/test_i18n.py FFF.FF...                             [ 34%]\nr2e_tests/test_config/test_init.py ..................................... [ 37%]\n...F..F.......F.............F...........F.....................FF...FFF.. [ 44%]\n......................                                                   [ 46%]\nr2e_tests/test_config/test_predicates.py ............................... [ 48%]\n...........................................                              [ 52%]\nr2e_tests/test_config/test_rendering.py ...                              [ 52%]\nr2e_tests/test_config/test_routes.py ........................            [ 55%]\nr2e_tests/test_config/test_security.py ............                      [ 56%]\nr2e_tests/test_config/test_settings.py ........................          [ 58%]\nr2e_tests/test_config/test_testing.py ............                       [ 59%]\nr2e_tests/test_config/test_tweens.py .................................   [ 62%]\nr2e_tests/test_config/test_util.py ..................................... [ 65%]\n..............                                                           [ 66%]\nr2e_tests/test_config/test_views.py ........................F........... [ 69%]\n.............F.F........................................................ [ 76%]\n.............FF......................................................... [ 82%]\n.........................................F.......F                       [ 87%]\nr2e_tests/test_scripts/test_common.py ...                                [ 87%]\nr2e_tests/test_scripts/test_pcreate.py ....................              [ 89%]\nr2e_tests/test_scripts/test_pdistreport.py ..                            [ 89%]\nr2e_tests/test_scripts/test_prequest.py F.FFF.FFFFFF.F.FFF.              [ 91%]\nr2e_tests/test_scripts/test_proutes.py ...FFF....FFFF.F.FF....F..FF.     [ 93%]\nr2e_tests/test_scripts/test_pserve.py ............................       [ 96%]\nr2e_tests/test_scripts/test_pshell.py ................                   [ 97%]\nr2e_tests/test_scripts/test_ptweens.py .....                             [ 97%]\nr2e_tests/test_scripts/test_pviews.py ................F......            [100%]\n\n=================================== FAILURES ===================================\n_ TestViewsConfigurationMixin.test_add_static_view_here_no_utility_registered __\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_static_view_here_no_utility_registered>\n\n    def test_add_static_view_here_no_utility_registered(self):\n        from pyramid.renderers import null_renderer\n        from zope.interface import Interface\n        from pyramid.interfaces import IView\n        from pyramid.interfaces import IViewClassifier\n        config = self._makeOne(autocommit=True)\n        config.add_static_view('static', 'files', renderer=null_renderer)\n        request_type = self._getRouteRequestIface(config, '__static/')\n        self._assertRoute(config, '__static/', 'static/*subpath')\n        wrapped = config.registry.adapters.lookup(\n            (IViewClassifier, request_type, Interface), IView, name='')\n        from pyramid.request import Request\n        request = Request.blank('/static/minimal.txt')\n        request.subpath = ('minimal.txt', )\n>       result = wrapped(None, request)\n\nr2e_tests/test_1.py:1915: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.static.static_view object at 0x7350d27eb4f0>, context = None\nrequest = <Request at 0x7350d28107f0 GET http://localhost/static/minimal.txt>\n\n    def __call__(self, context, request):\n        if self.use_subpath:\n            path_tuple = request.subpath\n        else:\n            path_tuple = traversal_path_info(request.environ['PATH_INFO'])\n        if self.cachebust_match:\n            path_tuple = self.cachebust_match(path_tuple)\n        path = _secure_path(path_tuple)\n    \n        if path is None:\n            raise HTTPNotFound('Out of bounds: %s' % request.url)\n    \n        if self.package_name: # package resource\n            resource_path = '%s/%s' % (self.docroot.rstrip('/'), path)\n            if resource_isdir(self.package_name, resource_path):\n                if not request.path_url.endswith('/'):\n                    self.add_slash_redirect(request)\n                resource_path = '%s/%s' % (\n                    resource_path.rstrip('/'), self.index\n                )\n    \n            if not resource_exists(self.package_name, resource_path):\n>               raise HTTPNotFound(request.url)\nE               pyramid.httpexceptions.HTTPNotFound: http://localhost/static/minimal.txt\n\npyramid/static.py:123: HTTPNotFound\n____ TestViewsConfigurationMixin.test_add_static_view_package_here_relative ____\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_static_view_package_here_relative>\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n>       self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\nE       AssertionError: Lists differ: [(<py[39 chars]350d284c640>, 'static', 'r2e_tests:files', {})] != [(<py[39 chars]350d284c640>, 'static', 'pyramid.tests.test_config:files', {})]\nE       \nE       First differing element 0:\nE       (<pyr[37 chars]7350d284c640>, 'static', 'r2e_tests:files', {})\nE       (<pyr[37 chars]7350d284c640>, 'static', 'pyramid.tests.test_config:files', {})\nE       \nE         [(<pyramid.config.Configurator object at 0x7350d284c640>,\nE           'static',\nE       -   'r2e_tests:files',\nE       +   'pyramid.tests.test_config:files',\nE           {})]\n\nr2e_tests/test_1.py:1936: AssertionError\n___________ TestViewsConfigurationMixin.test_add_view_exception_only ___________\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_exception_only>\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n>       config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n\nr2e_tests/test_1.py:1833: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:530: in wrapper\n    return wrapped(self, *arg, **defaults)\npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\npyramid/config/views.py:1060: in add_view\n    self.action(discriminator, register, introspectables=introspectables)\npyramid/config/__init__.py:609: in action\n    undefer(discriminator)\npyramid/registry.py:271: in undefer\n    v = v.resolve()\npyramid/registry.py:263: in resolve\n    return self.value\npyramid/decorator.py:45: in __get__\n    val = self.wrapped(inst)\npyramid/registry.py:260: in value\n    return self.func()\npyramid/config/views.py:810: in discrim_func\n    self._check_view_options(**dvals)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x7350d2765fd0>\nkw = {'exception_only': True}\nderivers = <pyramid.util.TopologicalSorter object at 0x7350d2796fa0>\nderiver = <function csrf_view at 0x7350d2f15670>, opt = 'require_csrf'\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n>           raise ConfigurationError('Unknown view options: %s' % (kw,))\nE           pyramid.exceptions.ConfigurationError: Unknown view options: {'exception_only': True}\n\npyramid/config/views.py:1070: ConfigurationError\n___ TestViewsConfigurationMixin.test_add_view_exception_only_no_regular_view ___\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_exception_only_no_regular_view>\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n>       config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n\nr2e_tests/test_1.py:1823: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:530: in wrapper\n    return wrapped(self, *arg, **defaults)\npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\npyramid/config/views.py:1060: in add_view\n    self.action(discriminator, register, introspectables=introspectables)\npyramid/config/__init__.py:609: in action\n    undefer(discriminator)\npyramid/registry.py:271: in undefer\n    v = v.resolve()\npyramid/registry.py:263: in resolve\n    return self.value\npyramid/decorator.py:45: in __get__\n    val = self.wrapped(inst)\npyramid/registry.py:260: in value\n    return self.func()\npyramid/config/views.py:810: in discrim_func\n    self._check_view_options(**dvals)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x7350d2c5ae20>\nkw = {'exception_only': True}\nderivers = <pyramid.util.TopologicalSorter object at 0x7350d28089a0>\nderiver = <function csrf_view at 0x7350d2f15670>, opt = 'require_csrf'\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n>           raise ConfigurationError('Unknown view options: %s' % (kw,))\nE           pyramid.exceptions.ConfigurationError: Unknown view options: {'exception_only': True}\n\npyramid/config/views.py:1070: ConfigurationError\n_______ TestViewsConfigurationMixin.test_add_view_with_template_renderer _______\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer>\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n    \n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests' from '/home/gcpuser/buckets/lo[93 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_1.py:1143: AssertionError\n_ TestViewsConfigurationMixin.test_add_view_with_template_renderer_no_callable _\n\nself = <r2e_tests.test_1.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer_no_callable>\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests' from '/home/gcpuser/buckets/lo[93 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_1.py:1184: AssertionError\n_________ TestStaticURLInfo.test_generate_url_cachebust_with_overrides _________\n\nself = <r2e_tests.test_1.TestStaticURLInfo testMethod=test_generate_url_cachebust_with_overrides>\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n>           self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\nE           AssertionError: 'http://example.com/static/foo.png?x=foo' != 'http://example.com/static/foo.png?x=bar'\nE           - http://example.com/static/foo.png?x=foo\nE           ?                                     ^^^\nE           + http://example.com/static/foo.png?x=bar\nE           ?                                     ^^^\n\nr2e_tests/test_1.py:3015: AssertionError\n___________________ Test_view_description.test_without_text ____________________\n\nself = <r2e_tests.test_1.Test_view_description testMethod=test_without_text>\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n>       self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\nE       AssertionError: 'function r2e_tests.test_1.view' != 'function pyramid.tests.test_config.test_views.view'\nE       - function r2e_tests.test_1.view\nE       + function pyramid.tests.test_config.test_views.view\n\nr2e_tests/test_1.py:3186: AssertionError\n__ AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_dotted_names ___\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_resource_url_adapter_dotted_names>\n\n    def test_add_resource_url_adapter_dotted_names(self):\n        from pyramid.interfaces import IResourceURL\n        config = self._makeOne(autocommit=True)\n        config.add_resource_url_adapter(\n            'pyramid.tests.test_config.test_adapters.DummyResourceURL',\n            'pyramid.tests.test_config.test_adapters.DummyIface',\n            )\n        iface = DummyIface()\n>       adapter = config.registry.getMultiAdapter((iface, iface),\n                                                    IResourceURL)\n\nr2e_tests/test_config/test_adapters.py:280: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <Registry r2e_tests.test_config>\nobjects = (<r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d268f550>, <r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d268f550>)\ninterface = <InterfaceClass pyramid.interfaces.IResourceURL>, name = ''\n\n    def getMultiAdapter(self, objects, interface, name=''):\n        adapter = self.adapters.queryMultiAdapter(objects, interface, name)\n        if adapter is None:\n>           raise ComponentLookupError(objects, interface, name)\nE           zope.interface.interfaces.ComponentLookupError: ((<r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d268f550>, <r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d268f550>), <InterfaceClass pyramid.interfaces.IResourceURL>, '')\n\n.venv/lib/python3.8/site-packages/zope/interface/registry.py:379: ComponentLookupError\n_ AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_introspectables _\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_resource_url_adapter_introspectables>\n\n    def test_add_resource_url_adapter_introspectables(self):\n        config = self._makeOne()\n        config.add_resource_url_adapter(DummyResourceURL, DummyIface)\n        actions = config.action_state.actions\n        self.assertEqual(len(actions), 1)\n        intrs  = actions[0]['introspectables']\n        self.assertEqual(len(intrs), 1)\n        intr = intrs[0]\n        self.assertEqual(intr.type_name, 'resource url adapter')\n        self.assertEqual(intr.discriminator,\n                         ('resource url adapter', DummyIface))\n        self.assertEqual(intr.category_name, 'resource url adapters')\n>       self.assertEqual(\n            intr.title,\n            \"resource url adapter for resource iface \"\n            \"<class 'pyramid.tests.test_config.test_adapters.DummyIface'>\"\n            )\nE       AssertionError: \"reso[34 chars]e <class 'r2e_tests.test_config.test_adapters.DummyIface'>\" != \"reso[34 chars]e <class 'pyramid.tests.test_config.test_adapters.DummyIface'>\"\nE       - resource url adapter for resource iface <class 'r2e_tests.test_config.test_adapters.DummyIface'>\nE       ?                                                  ^^^\nE       + resource url adapter for resource iface <class 'pyramid.tests.test_config.test_adapters.DummyIface'>\nE       ?                                                 ++ ^^^^^\n\nr2e_tests/test_config/test_adapters.py:326: AssertionError\n________ AdaptersConfiguratorMixinTests.test_add_traverser_dotted_names ________\n\nself = <r2e_tests.test_config.test_adapters.AdaptersConfiguratorMixinTests testMethod=test_add_traverser_dotted_names>\n\n    def test_add_traverser_dotted_names(self):\n        from pyramid.interfaces import ITraverser\n        config = self._makeOne(autocommit=True)\n        config.add_traverser(\n            'pyramid.tests.test_config.test_adapters.DummyTraverser',\n            'pyramid.tests.test_config.test_adapters.DummyIface')\n        iface = DummyIface()\n>       traverser = config.registry.getAdapter(iface, ITraverser)\n\nr2e_tests/test_config/test_adapters.py:237: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <Registry r2e_tests.test_config>\nobject = <r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d2531430>\ninterface = <InterfaceClass pyramid.interfaces.ITraverser>, name = ''\n\n    def getAdapter(self, object, interface, name=''):\n        adapter = self.adapters.queryAdapter(object, interface, name)\n        if adapter is None:\n>           raise ComponentLookupError(object, interface, name)\nE           zope.interface.interfaces.ComponentLookupError: (<r2e_tests.test_config.test_adapters.DummyIface object at 0x7350d2531430>, <InterfaceClass pyramid.interfaces.ITraverser>, '')\n\n.venv/lib/python3.8/site-packages/zope/interface/registry.py:368: ComponentLookupError\n___ TestAssetsConfiguratorMixin.test_override_asset_directory_with_directory ___\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_directory_with_directory>\n\n    def test_override_asset_directory_with_directory(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/')\n    \n        resource_name = 'bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:106: AssertionError\n____ TestAssetsConfiguratorMixin.test_override_asset_directory_with_package ____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_directory_with_package>\n\n    def test_override_asset_directory_with_package(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/',\n            'pyramid.tests.test_config.pkgs.asset.subpackage',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, '')\n    \n        resource_name = 'templates/bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:129: AssertionError\n________ TestAssetsConfiguratorMixin.test_override_asset_file_with_file ________\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_file_with_file>\n\n    def test_override_asset_file_with_file(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset:templates/foo.pt',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/bar.pt',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, 'templates/foo.pt')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/bar.pt')\n    \n        resource_name = ''\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:60: AssertionError\n____ TestAssetsConfiguratorMixin.test_override_asset_package_with_directory ____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_package_with_directory>\n\n    def test_override_asset_package_with_directory(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset',\n            'pyramid.tests.test_config.pkgs.asset.subpackage:templates/',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, '')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, 'templates/')\n    \n        resource_name = 'bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:152: AssertionError\n_____ TestAssetsConfiguratorMixin.test_override_asset_package_with_package _____\n\nself = <r2e_tests.test_config.test_assets.TestAssetsConfiguratorMixin testMethod=test_override_asset_package_with_package>\n\n    def test_override_asset_package_with_package(self):\n        from pyramid.config.assets import PackageAssetSource\n        config = self._makeOne(autocommit=True)\n        override = DummyUnderOverride()\n        config.override_asset(\n            'pyramid.tests.test_config.pkgs.asset',\n            'pyramid.tests.test_config.pkgs.asset.subpackage',\n            _override=override)\n        from pyramid.tests.test_config.pkgs import asset\n        from pyramid.tests.test_config.pkgs.asset import subpackage\n        self.assertEqual(override.package, asset)\n        self.assertEqual(override.path, '')\n        source = override.source\n        self.assertTrue(isinstance(source, PackageAssetSource))\n        self.assertEqual(source.package, subpackage)\n        self.assertEqual(source.prefix, '')\n    \n        resource_name = 'templates/bar.pt'\n        expected = os.path.join(here, 'pkgs', 'asset',\n                                'subpackage', 'templates', 'bar.pt')\n>       self.assertEqual(override.source.get_filename(resource_name),\n                         expected)\nE       AssertionError: '/hom[90 chars]807a/pyramid/tests/test_config/pkgs/asset/subp[19 chars]r.pt' != '/hom[90 chars]807a/r2e_tests/test_config/pkgs/asset/subpacka[15 chars]r.pt'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/pkgs/asset/subpackage/templates/bar.pt\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:83: AssertionError\n_________ TestOverrideProvider.test_get_resource_filename_no_overrides _________\n\nself = <r2e_tests.test_config.test_assets.TestOverrideProvider testMethod=test_get_resource_filename_no_overrides>\n\n    def test_get_resource_filename_no_overrides(self):\n        resource_name = 'test_assets.py'\n        import pyramid.tests.test_config\n        provider = self._makeOne(pyramid.tests.test_config)\n        expected = os.path.join(here, resource_name)\n        result = provider.get_resource_filename(None, resource_name)\n>       self.assertEqual(result, expected)\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:297: AssertionError\n____ TestOverrideProvider.test_get_resource_filename_override_returns_None _____\n\nself = <r2e_tests.test_config.test_assets.TestOverrideProvider testMethod=test_get_resource_filename_override_returns_None>\n\n    def test_get_resource_filename_override_returns_None(self):\n        overrides = DummyOverrides(None)\n        self._registerOverrides(overrides)\n        resource_name = 'test_assets.py'\n        import pyramid.tests.test_config\n        provider = self._makeOne(pyramid.tests.test_config)\n        expected = os.path.join(here, resource_name)\n        result = provider.get_resource_filename(None, resource_name)\n>       self.assertEqual(result, expected)\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:345: AssertionError\n___________________ TestPackageAssetSource.test_get_filename ___________________\n\nself = <r2e_tests.test_config.test_assets.TestPackageAssetSource testMethod=test_get_filename>\n\n    def test_get_filename(self):\n        source = self._makeOne('')\n>       self.assertEqual(source.get_filename('test_assets.py'),\n                         os.path.join(here, 'test_assets.py'))\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:716: AssertionError\n_____________ TestPackageAssetSource.test_get_filename_with_prefix _____________\n\nself = <r2e_tests.test_config.test_assets.TestPackageAssetSource testMethod=test_get_filename_with_prefix>\n\n    def test_get_filename_with_prefix(self):\n        source = self._makeOne('test_assets.py')\n>       self.assertEqual(source.get_filename(''),\n                         os.path.join(here, 'test_assets.py'))\nE       AssertionError: '/hom[73 chars]3899024cdab685483807a/pyramid/tests/test_config/test_assets.py' != '/hom[73 chars]3899024cdab685483807a/r2e_tests/test_config/test_assets.py'\nE       - /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/test_assets.py\nE       ?                                                                                                    -- ^^^^^\nE       + /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/test_config/test_assets.py\nE       ?                                                                                                     ^^^\n\nr2e_tests/test_config/test_assets.py:721: AssertionError\n_________ TestI18NConfiguratorMixin.test_add_translation_dirs_abspath __________\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_abspath>\n\n    def test_add_translation_dirs_abspath(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n>       config.add_translation_dirs(locale)\n\nr2e_tests/test_config/test_i18n.py:86: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x7350d2d6d1f0>\nspecs = ('/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale',)\nintrospectables = []\nspec = '/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\npackage_name = None\n\n    @action_method\n    def add_translation_dirs(self, *specs):\n        \"\"\" Add one or more :term:`translation directory` paths to the\n        current configuration state.  The ``specs`` argument is a\n        sequence that may contain absolute directory paths\n        (e.g. ``/usr/share/locale``) or :term:`asset specification`\n        names naming a directory path (e.g. ``some.package:locale``)\n        or a combination of the two.\n    \n        Example:\n    \n        .. code-block:: python\n    \n           config.add_translation_dirs('/usr/share/locale',\n                                       'some.package:locale')\n    \n        Later calls to ``add_translation_dir`` insert directories into the\n        beginning of the list of translation directories created by earlier\n        calls.  This means that the same translation found in a directory\n        added later in the configuration process will be found before one\n        added earlier in the configuration process.  However, if multiple\n        specs are provided in a single call to ``add_translation_dirs``, the\n        directories will be inserted into the beginning of the directory list\n        in the order they're provided in the ``*specs`` list argument (items\n        earlier in the list trump ones later in the list).\n        \"\"\"\n        directories = []\n        introspectables = []\n    \n        for spec in specs[::-1]: # reversed\n            package_name, filename = self._split_spec(spec)\n            if package_name is None: # absolute filename\n                directory = filename\n            else:\n                __import__(package_name)\n                package = sys.modules[package_name]\n                directory = os.path.join(package_path(package), filename)\n    \n            if not os.path.isdir(os.path.realpath(directory)):\n>               raise ConfigurationError('\"%s\" is not a directory' %\n                                         directory)\nE               pyramid.exceptions.ConfigurationError: \"/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale\" is not a directory\n\npyramid/config/i18n.py:86: ConfigurationError\n________ TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec ________\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_asset_spec>\n\n    def test_add_translation_dirs_asset_spec(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale])\nE       AssertionError: Lists differ: ['/ho[70 chars]72633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'] != ['/ho[70 chars]72633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       - ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale']\nE       ?                                                                                                      -- ^^^^^\nE       \nE       + ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale']\nE       ?                                                                                                       ^^^\n\nr2e_tests/test_config/test_i18n.py:54: AssertionError\n_ TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec_existing_translation_dirs _\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_asset_spec_existing_translation_dirs>\n\n    def test_add_translation_dirs_asset_spec_existing_translation_dirs(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        directories = ['abc']\n        config.registry.registerUtility(directories, ITranslationDirectories)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale')\n        result = config.registry.getUtility(ITranslationDirectories)\n>       self.assertEqual(result, [locale, 'abc'])\nE       AssertionError: Lists differ: ['/ho[77 chars]9024cdab685483807a/pyramid/tests/pkgs/localeapp/locale', 'abc'] != ['/ho[77 chars]9024cdab685483807a/r2e_tests/pkgs/localeapp/locale', 'abc']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       - ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale',\nE       ?                                                                                                      -- ^^^^^\nE       \nE       + ['/home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale',\nE       ?                                                                                                       ^^^\nE       \nE          'abc']\n\nr2e_tests/test_config/test_i18n.py:64: AssertionError\n______ TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs ______\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_multiple_specs>\n\n    def test_add_translation_dirs_multiple_specs(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale',\n                                    'pyramid.tests.pkgs.localeapp:locale2')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale, locale2])\nE       AssertionError: Lists differ: ['/ho[91 chars]807a/pyramid/tests/pkgs/localeapp/locale', '/h[130 chars]le2'] != ['/ho[91 chars]807a/r2e_tests/pkgs/localeapp/locale', '/home/[122 chars]le2']\nE       \nE       First differing element 0:\nE       '/hom[68 chars]472633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale'\nE       '/hom[68 chars]472633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale'\nE       \nE       Diff is 1002 characters long. Set self.maxDiff to None to see it.\n\nr2e_tests/test_config/test_i18n.py:71: AssertionError\n_ TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs_multiple_calls _\n\nself = <r2e_tests.test_config.test_i18n.TestI18NConfiguratorMixin testMethod=test_add_translation_dirs_multiple_specs_multiple_calls>\n\n    def test_add_translation_dirs_multiple_specs_multiple_calls(self):\n        from pyramid.interfaces import ITranslationDirectories\n        config = self._makeOne(autocommit=True)\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale',\n                                    'pyramid.tests.pkgs.localeapp:locale2')\n        config.add_translation_dirs('pyramid.tests.pkgs.localeapp:locale3')\n>       self.assertEqual(config.registry.getUtility(ITranslationDirectories),\n                         [locale3, locale, locale2])\nE       AssertionError: Lists differ: ['/ho[91 chars]807a/pyramid/tests/pkgs/localeapp/locale3', '/[269 chars]le2'] != ['/ho[91 chars]807a/r2e_tests/pkgs/localeapp/locale3', '/home[257 chars]le2']\nE       \nE       First differing element 0:\nE       '/hom[69 chars]72633899024cdab685483807a/pyramid/tests/pkgs/localeapp/locale3'\nE       '/hom[69 chars]72633899024cdab685483807a/r2e_tests/pkgs/localeapp/locale3'\nE       \nE       Diff is 1504 characters long. Set self.maxDiff to None to see it.\n\nr2e_tests/test_config/test_i18n.py:80: AssertionError\n___________________ ConfiguratorTests.test_ctor_no_registry ____________________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_ctor_no_registry>\n\n    def test_ctor_no_registry(self):\n        import sys\n        from pyramid.interfaces import ISettings\n        from pyramid.config import Configurator\n        from pyramid.interfaces import IRendererFactory\n        config = Configurator()\n        this_pkg = sys.modules['pyramid.tests.test_config']\n        self.assertTrue(config.registry.getUtility(ISettings))\n>       self.assertEqual(config.package, this_pkg)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:68: AssertionError\n_________ ConfiguratorTests.test_ctor_noreg_debug_logger_None_default __________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_ctor_noreg_debug_logger_None_default>\n\n    def test_ctor_noreg_debug_logger_None_default(self):\n        from pyramid.interfaces import IDebugLogger\n        config = self._makeOne()\n        logger = config.registry.getUtility(IDebugLogger)\n>       self.assertEqual(logger.name, 'pyramid.tests.test_config')\nE       AssertionError: 'r2e_tests.test_config' != 'pyramid.tests.test_config'\nE       - r2e_tests.test_config\nE       ?  ^^^\nE       + pyramid.tests.test_config\nE       ? ++ ^^^^^\n\nr2e_tests/test_config/test_init.py:124: AssertionError\n_____________ ConfiguratorTests.test_include_constant_root_package _____________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_include_constant_root_package>\n\n    def test_include_constant_root_package(self):\n        from pyramid import tests\n        from pyramid.tests import test_config\n        config = self._makeOne(root_package=tests)\n        results = {}\n        def include(config):\n            results['package'] = config.package\n            results['root_package'] = config.root_package\n        config.include(include)\n        self.assertEqual(results['root_package'], tests)\n>       self.assertEqual(results['package'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:777: AssertionError\n_______________ ConfiguratorTests.test_scan_integration_conflict _______________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_scan_integration_conflict>\n\n    def test_scan_integration_conflict(self):\n        from pyramid.tests.test_config.pkgs import selfscan\n        from pyramid.config import Configurator\n        c = Configurator()\n        c.scan(selfscan)\n        c.scan(selfscan)\n        try:\n>           c.commit()\n\nr2e_tests/test_config/test_init.py:1039: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/config/__init__.py:654: in commit\n    self.action_state.execute_actions(introspector=self.introspector)\npyramid/config/__init__.py:1163: in execute_actions\n    action = next(pending_actions, None)\npyramid/config/__init__.py:1121: in resume\n    for a, b in zip_longest(actions, executed_actions):\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nactions = [{'args': (), 'callable': <function ViewsConfiguratorMixin.add_view.<locals>.register at 0x7350d231cd30>, 'discriminat...50d22f01f0>, 'discriminator': ('view', None, 'two', None, 'd41d8cd98f00b204e9800998ecf8427e'), 'includepath': (), ...}]\n\n    def resolveConflicts(actions):\n        \"\"\"Resolve conflicting actions\n    \n        Given an actions list, identify and try to resolve conflicting actions.\n        Actions conflict if they have the same non-None discriminator.\n        Conflicting actions can be resolved if the include path of one of\n        the actions is a prefix of the includepaths of the other\n        conflicting actions and is unequal to the include paths in the\n        other conflicting actions.\n        \"\"\"\n    \n        def orderandpos(v):\n            n, v = v\n            if not isinstance(v, dict):\n                # old-style tuple action\n                v = expand_action(*v)\n            return (v['order'] or 0, n)\n    \n        sactions = sorted(enumerate(actions), key=orderandpos)\n    \n        def orderonly(v):\n            n, v = v\n            if not isinstance(v, dict):\n                # old-style tuple action\n                v = expand_action(*v)\n            return v['order'] or 0\n    \n        for order, actiongroup in itertools.groupby(sactions, orderonly):\n            # \"order\" is an integer grouping. Actions in a lower order will be\n            # executed before actions in a higher order.  All of the actions in\n            # one grouping will be executed (its callable, if any will be called)\n            # before any of the actions in the next.\n    \n            unique = {}\n            output = []\n    \n            for i, action in actiongroup:\n                # Within an order, actions are executed sequentially based on\n                # original action ordering (\"i\").\n    \n                if not isinstance(action, dict):\n                    # old-style tuple action\n                    action = expand_action(*action)\n    \n                # \"ainfo\" is a tuple of (order, i, action) where \"order\" is a\n                # user-supplied grouping, \"i\" is an integer expressing the relative\n                # position of this action in the action list being resolved, and\n                # \"action\" is an action dictionary.  The purpose of an ainfo is to\n                # associate an \"order\" and an \"i\" with a particular action; \"order\"\n                # and \"i\" exist for sorting purposes after conflict resolution.\n                ainfo = (order, i, action)\n    \n                discriminator = undefer(action['discriminator'])\n                action['discriminator'] = discriminator\n    \n                if discriminator is None:\n                    # The discriminator is None, so this action can never conflict.\n                    # We can add it directly to the result.\n                    output.append(ainfo)\n                    continue\n    \n                L = unique.setdefault(discriminator, [])\n                L.append(ainfo)\n    \n            # Check for conflicts\n            conflicts = {}\n    \n            for discriminator, ainfos in unique.items():\n                # We use (includepath, order, i) as a sort key because we need to\n                # sort the actions by the paths so that the shortest path with a\n                # given prefix comes first.  The \"first\" action is the one with the\n                # shortest include path.  We break sorting ties using \"order\", then\n                # \"i\".\n                def bypath(ainfo):\n                    path, order, i = ainfo[2]['includepath'], ainfo[0], ainfo[1]\n                    return path, order, i\n    \n                ainfos.sort(key=bypath)\n                ainfo, rest = ainfos[0], ainfos[1:]\n                output.append(ainfo)\n                _, _, action = ainfo\n                basepath, baseinfo, discriminator = (\n                    action['includepath'],\n                    action['info'],\n                    action['discriminator'],\n                    )\n    \n                for _, _, action in rest:\n                    includepath = action['includepath']\n                    # Test whether path is a prefix of opath\n                    if (includepath[:len(basepath)] != basepath or  # not a prefix\n                            includepath == basepath):\n                        L = conflicts.setdefault(discriminator, [baseinfo])\n                        L.append(action['info'])\n    \n            if conflicts:\n>               raise ConfigurationConflictError(conflicts)\nE               pyramid.exceptions.ConfigurationConflictError: Conflicting configuration actions\nE                 For: ('view', None, '', None, 'd41d8cd98f00b204e9800998ecf8427e')\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/__init__.py:\nE                       def abc(request):\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/__init__.py:\nE                       def abc(request):\nE                 For: ('view', None, 'two', None, 'd41d8cd98f00b204e9800998ecf8427e')\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/another.py:\nE                       def two(request):\nE                   Line 4 of file /home/gcpuser/buckets/local_repoeval_bucket/repos/pyramid_b0d20b5c3fe7df472633899024cdab685483807a/pyramid/tests/test_config/pkgs/selfscan/another.py:\nE                       def two(request):\n\npyramid/config/__init__.py:1299: ConfigurationConflictError\n\nDuring handling of the above exception, another exception occurred:\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_scan_integration_conflict>\n\n    def test_scan_integration_conflict(self):\n        from pyramid.tests.test_config.pkgs import selfscan\n        from pyramid.config import Configurator\n        c = Configurator()\n        c.scan(selfscan)\n        c.scan(selfscan)\n        try:\n            c.commit()\n        except ConfigurationConflictError as why:\n            def scanconflicts(e):\n                conflicts = e._conflicts.values()\n                for conflict in conflicts:\n                    for confinst in conflict:\n                        yield confinst.src\n            which = list(scanconflicts(why))\n            self.assertEqual(len(which), 4)\n>           self.assertTrue(\"@view_config(renderer='string')\" in which)\nE           AssertionError: False is not true\n\nr2e_tests/test_config/test_init.py:1048: AssertionError\n_______ ConfiguratorTests.test_setup_registry_debug_logger_None_default ________\n\nself = <r2e_tests.test_config.test_init.ConfiguratorTests testMethod=test_setup_registry_debug_logger_None_default>\n\n    def test_setup_registry_debug_logger_None_default(self):\n        from pyramid.registry import Registry\n        from pyramid.interfaces import IDebugLogger\n        reg = Registry()\n        config = self._makeOne(reg)\n        config.setup_registry()\n        logger = reg.getUtility(IDebugLogger)\n>       self.assertEqual(logger.name, 'pyramid.tests.test_config')\nE       AssertionError: 'r2e_tests.test_config' != 'pyramid.tests.test_config'\nE       - r2e_tests.test_config\nE       ?  ^^^\nE       + pyramid.tests.test_config\nE       ? ++ ^^^^^\n\nr2e_tests/test_config/test_init.py:444: AssertionError\n____ TestConfigurator_add_directive.test_add_directive_with_custom_callable ____\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_add_directive_with_custom_callable>\n\n    def test_add_directive_with_custom_callable(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n                'dummy_callable', 'pyramid.tests.test_config.dummy_callable')\n        self.assertTrue(hasattr(config, 'dummy_callable'))\n        config.dummy_callable('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1247: AssertionError\n________ TestConfigurator_add_directive.test_add_directive_with_partial ________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_add_directive_with_partial>\n\n    def test_add_directive_with_partial(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n                'dummy_partial', 'pyramid.tests.test_config.dummy_partial')\n        self.assertTrue(hasattr(config, 'dummy_partial'))\n        config.dummy_partial()\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'partial')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1234: AssertionError\n_________ TestConfigurator_add_directive.test_extend_with_dotted_name __________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_extend_with_dotted_name>\n\n    def test_extend_with_dotted_name(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n            'dummy_extend', 'pyramid.tests.test_config.dummy_extend')\n        self.assertTrue(hasattr(config, 'dummy_extend'))\n        config.dummy_extend('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1221: AssertionError\n_______ TestConfigurator_add_directive.test_extend_with_python_callable ________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator_add_directive testMethod=test_extend_with_python_callable>\n\n    def test_extend_with_python_callable(self):\n        from pyramid.tests import test_config\n        config = self.config\n        config.add_directive(\n            'dummy_extend', dummy_extend)\n        self.assertTrue(hasattr(config, 'dummy_extend'))\n        config.dummy_extend('discrim')\n        after = config.action_state\n        action = after.actions[-1]\n        self.assertEqual(action['discriminator'], 'discrim')\n        self.assertEqual(action['callable'], None)\n>       self.assertEqual(action['args'], test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_init.py:1260: AssertionError\n_________ TestConfigurator__add_predicate.test_factory_as_dotted_name __________\n\nself = <r2e_tests.test_config.test_init.TestConfigurator__add_predicate testMethod=test_factory_as_dotted_name>\n\n    def test_factory_as_dotted_name(self):\n        config = self._makeOne()\n    \n        def _fakeAction(discriminator, callable=None, args=(),\n                        kw=None, order=0, introspectables=(), **extra):\n            self.assertEqual(len(introspectables), 1)\n            self.assertEqual(introspectables[0]['name'], 'testing')\n            self.assertEqual(introspectables[0]['factory'], DummyPredicate)\n    \n        config.action = _fakeAction\n>       config._add_predicate(\n            'route',\n            'testing',\n            'pyramid.tests.test_config.test_init.DummyPredicate'\n            )\n\nr2e_tests/test_config/test_init.py:1324: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/config/__init__.py:543: in _add_predicate\n    self.action(discriminator, register, introspectables=(intr,),\nr2e_tests/test_config/test_init.py:1321: in _fakeAction\n    self.assertEqual(introspectables[0]['factory'], DummyPredicate)\nE   AssertionError: <class 'pyramid.tests.test_config.test_init.DummyPredicate'> != <class 'r2e_tests.test_config.test_init.DummyPredicate'>\n____ TestViewsConfigurationMixin.test_add_static_view_package_here_relative ____\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_static_view_package_here_relative>\n\n    def test_add_static_view_package_here_relative(self):\n        from pyramid.interfaces import IStaticURLInfo\n        info = DummyStaticURLInfo()\n        config = self._makeOne(autocommit=True)\n        config.registry.registerUtility(info, IStaticURLInfo)\n        config.add_static_view('static', 'files')\n>       self.assertEqual(\n            info.added,\n            [(config, 'static', 'pyramid.tests.test_config:files', {})])\nE       AssertionError: Lists differ: [(<py[39 chars]350d2486cd0>, 'static', 'r2e_tests.test_config:files', {})] != [(<py[39 chars]350d2486cd0>, 'static', 'pyramid.tests.test_config:files', {})]\nE       \nE       First differing element 0:\nE       (<pyr[37 chars]7350d2486cd0>, 'static', 'r2e_tests.test_config:files', {})\nE       (<pyr[37 chars]7350d2486cd0>, 'static', 'pyramid.tests.test_config:files', {})\nE       \nE         [(<pyramid.config.Configurator object at 0x7350d2486cd0>,\nE           'static',\nE       -   'r2e_tests.test_config:files',\nE       ?     ^^^\nE       \nE       +   'pyramid.tests.test_config:files',\nE       ?    ++ ^^^^^\nE       \nE           {})]\n\nr2e_tests/test_config/test_views.py:1936: AssertionError\n___________ TestViewsConfigurationMixin.test_add_view_exception_only ___________\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_exception_only>\n\n    def test_add_view_exception_only(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n>       config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n\nr2e_tests/test_config/test_views.py:1833: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:530: in wrapper\n    return wrapped(self, *arg, **defaults)\npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\npyramid/config/views.py:1060: in add_view\n    self.action(discriminator, register, introspectables=introspectables)\npyramid/config/__init__.py:609: in action\n    undefer(discriminator)\npyramid/registry.py:271: in undefer\n    v = v.resolve()\npyramid/registry.py:263: in resolve\n    return self.value\npyramid/decorator.py:45: in __get__\n    val = self.wrapped(inst)\npyramid/registry.py:260: in value\n    return self.func()\npyramid/config/views.py:810: in discrim_func\n    self._check_view_options(**dvals)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x7350d250fe50>\nkw = {'exception_only': True}\nderivers = <pyramid.util.TopologicalSorter object at 0x7350d25ef220>\nderiver = <function csrf_view at 0x7350d2f15670>, opt = 'require_csrf'\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n>           raise ConfigurationError('Unknown view options: %s' % (kw,))\nE           pyramid.exceptions.ConfigurationError: Unknown view options: {'exception_only': True}\n\npyramid/config/views.py:1070: ConfigurationError\n___ TestViewsConfigurationMixin.test_add_view_exception_only_no_regular_view ___\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_exception_only_no_regular_view>\n\n    def test_add_view_exception_only_no_regular_view(self):\n        from zope.interface import implementedBy\n        from pyramid.renderers import null_renderer\n        view1 = lambda *arg: 'OK'\n        config = self._makeOne(autocommit=True)\n>       config.add_view(view=view1, context=Exception, renderer=null_renderer,\n                        exception_only=True)\n\nr2e_tests/test_config/test_views.py:1823: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \npyramid/util.py:530: in wrapper\n    return wrapped(self, *arg, **defaults)\npyramid/util.py:574: in wrapper\n    result = wrapped(self, *arg, **kw)\npyramid/config/views.py:1060: in add_view\n    self.action(discriminator, register, introspectables=introspectables)\npyramid/config/__init__.py:609: in action\n    undefer(discriminator)\npyramid/registry.py:271: in undefer\n    v = v.resolve()\npyramid/registry.py:263: in resolve\n    return self.value\npyramid/decorator.py:45: in __get__\n    val = self.wrapped(inst)\npyramid/registry.py:260: in value\n    return self.func()\npyramid/config/views.py:810: in discrim_func\n    self._check_view_options(**dvals)\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \n\nself = <pyramid.config.Configurator object at 0x7350d1f2faf0>\nkw = {'exception_only': True}\nderivers = <pyramid.util.TopologicalSorter object at 0x7350d1ee9c10>\nderiver = <function csrf_view at 0x7350d2f15670>, opt = 'require_csrf'\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n>           raise ConfigurationError('Unknown view options: %s' % (kw,))\nE           pyramid.exceptions.ConfigurationError: Unknown view options: {'exception_only': True}\n\npyramid/config/views.py:1070: ConfigurationError\n_______ TestViewsConfigurationMixin.test_add_view_with_template_renderer _______\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer>\n\n    def test_add_view_with_template_renderer(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        class view(object):\n            def __init__(self, context, request):\n                self.request = request\n                self.context = context\n    \n            def __call__(self):\n                return {'a':'1'}\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=view, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_views.py:1143: AssertionError\n_ TestViewsConfigurationMixin.test_add_view_with_template_renderer_no_callable _\n\nself = <r2e_tests.test_config.test_views.TestViewsConfigurationMixin testMethod=test_add_view_with_template_renderer_no_callable>\n\n    def test_add_view_with_template_renderer_no_callable(self):\n        from pyramid.tests import test_config\n        from pyramid.interfaces import ISettings\n        config = self._makeOne(autocommit=True)\n        renderer = self._registerRenderer(config)\n        fixture = 'pyramid.tests.test_config:files/minimal.txt'\n        config.introspection = False\n        config.add_view(view=None, renderer=fixture)\n        wrapper = self._getViewCallable(config)\n        request = self._makeRequest(config)\n        result = wrapper(None, request)\n        self.assertEqual(result.body, b'Hello!')\n        settings = config.registry.queryUtility(ISettings)\n        result = renderer.info\n        self.assertEqual(result.registry, config.registry)\n        self.assertEqual(result.type, '.txt')\n>       self.assertEqual(result.package, test_config)\nE       AssertionError: <module 'r2e_tests.test_config' from '/home/gcpuse[117 chars].py'> != <module 'pyramid.tests.test_config' from '/home/gc[125 chars].py'>\n\nr2e_tests/test_config/test_views.py:1184: AssertionError\n_________ TestStaticURLInfo.test_generate_url_cachebust_with_overrides _________\n\nself = <r2e_tests.test_config.test_views.TestStaticURLInfo testMethod=test_generate_url_cachebust_with_overrides>\n\n    def test_generate_url_cachebust_with_overrides(self):\n        config = testing.setUp()\n        try:\n            request = testing.DummyRequest()\n            config.add_static_view('static', 'path')\n            config.override_asset(\n                'pyramid.tests.test_config:path/',\n                'pyramid.tests.test_config:other_path/')\n            def cb(val):\n                def cb_(request, subpath, kw):\n                    kw['_query'] = {'x': val}\n                    return subpath, kw\n                return cb_\n            config.add_cache_buster('path', cb('foo'))\n            result = request.static_url('path/foo.png')\n            self.assertEqual(result, 'http://example.com/static/foo.png?x=foo')\n            config.add_cache_buster('other_path', cb('bar'), explicit=True)\n            result = request.static_url('path/foo.png')\n>           self.assertEqual(result, 'http://example.com/static/foo.png?x=bar')\nE           AssertionError: 'http://example.com/static/foo.png?x=foo' != 'http://example.com/static/foo.png?x=bar'\nE           - http://example.com/static/foo.png?x=foo\nE           ?                                     ^^^\nE           + http://example.com/static/foo.png?x=bar\nE           ?                                     ^^^\n\nr2e_tests/test_config/test_views.py:3015: AssertionError\n___________________ Test_view_description.test_without_text ____________________\n\nself = <r2e_tests.test_config.test_views.Test_view_description testMethod=test_without_text>\n\n    def test_without_text(self):\n        def view(): pass\n        result = self._callFUT(view)\n>       self.assertEqual(result,\n                         'function pyramid.tests.test_config.test_views.view')\nE       AssertionError: 'function r2e_tests.test_config.test_views.view' != 'function pyramid.tests.test_config.test_views.view'\nE       - function r2e_tests.test_config.test_views.view\nE       ?           ^^^\nE       + function pyramid.tests.test_config.test_views.view\nE       ?          ++ ^^^^^\n\nr2e_tests/test_config/test_views.py:3186: AssertionError\n_______________ TestPRequestCommand.test_command_display_headers _______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_display_headers>\n\n    def test_command_display_headers(self):\n        command = self._makeOne(\n            ['', '--display-headers', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(\n            self._out,\n            ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc'])\nE       AssertionError: Lists differ: ['200 OK', b'abc'] != ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc']\nE       \nE       First differing element 1:\nE       b'abc'\nE       'Content-Type: text/html; charset=UTF-8'\nE       \nE       Second list contains 1 additional elements.\nE       First extra element 2:\nE       'abc'\nE       \nE       - ['200 OK', b'abc']\nE       + ['200 OK', 'Content-Type: text/html; charset=UTF-8', 'abc']\n\nr2e_tests/test_scripts/test_prequest.py:202: AssertionError\n_________ TestPRequestCommand.test_command_has_content_type_header_var _________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_content_type_header_var>\n\n    def test_command_has_content_type_header_var(self):\n        command = self._makeOne(\n            ['', '--header=content-type:app/foo','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['CONTENT_TYPE'], 'app/foo')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:92: AssertionError\n_____________ TestPRequestCommand.test_command_has_good_header_var _____________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_good_header_var>\n\n    def test_command_has_good_header_var(self):\n        command = self._makeOne(\n            ['', '--header=name:value','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:69: AssertionError\n__________ TestPRequestCommand.test_command_has_multiple_header_vars ___________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_has_multiple_header_vars>\n\n    def test_command_has_multiple_header_vars(self):\n        command = self._makeOne(\n            ['',\n             '--header=name:value',\n             '--header=name2:value2',\n             'development.ini',\n             '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._environ['HTTP_NAME2'], 'value2')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:107: AssertionError\n_________________ TestPRequestCommand.test_command_method_get __________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_get>\n\n    def test_command_method_get(self):\n        command = self._makeOne(['', '--method=GET', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'GET')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:116: AssertionError\n_______________ TestPRequestCommand.test_command_method_options ________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_options>\n\n    def test_command_method_options(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=OPTIONS', 'development.ini',\n                                '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'OPTIONS')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:184: AssertionError\n________________ TestPRequestCommand.test_command_method_patch _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_patch>\n\n    def test_command_method_patch(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PATCH', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PATCH')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:158: AssertionError\n_________________ TestPRequestCommand.test_command_method_post _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_post>\n\n    def test_command_method_post(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=POST', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'POST')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:130: AssertionError\n_______________ TestPRequestCommand.test_command_method_propfind _______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_propfind>\n\n    def test_command_method_propfind(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PROPFIND', 'development.ini',\n                                '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PROPFIND')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:171: AssertionError\n_________________ TestPRequestCommand.test_command_method_put __________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_method_put>\n\n    def test_command_method_put(self):\n        from pyramid.compat import NativeIO\n        command = self._makeOne(['', '--method=PUT', 'development.ini', '/'])\n        stdin = NativeIO()\n        command.stdin = stdin\n        command.run()\n        self.assertEqual(self._environ['REQUEST_METHOD'], 'PUT')\n        self.assertEqual(self._environ['CONTENT_LENGTH'], '-1')\n        self.assertEqual(self._environ['wsgi.input'], stdin)\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:144: AssertionError\n________ TestPRequestCommand.test_command_path_doesnt_start_with_slash _________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_path_doesnt_start_with_slash>\n\n    def test_command_path_doesnt_start_with_slash(self):\n        command = self._makeOne(['', 'development.ini', 'abc'])\n        command.run()\n        self.assertEqual(self._path_info, '/abc')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:50: AssertionError\n__________________ TestPRequestCommand.test_command_two_args ___________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_two_args>\n\n    def test_command_two_args(self):\n        command = self._makeOne(['', 'development.ini', '/'])\n        command.run()\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:42: AssertionError\n________________ TestPRequestCommand.test_command_w_basic_auth _________________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_w_basic_auth>\n\n    def test_command_w_basic_auth(self):\n        command = self._makeOne(\n            ['', '--login=user:password',\n                 '--header=name:value','development.ini', '/'])\n        command.run()\n        self.assertEqual(self._environ['HTTP_NAME'], 'value')\n        self.assertEqual(self._environ['HTTP_AUTHORIZATION'],\n                        'Basic dXNlcjpwYXNzd29yZA==')\n        self.assertEqual(self._path_info, '/')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:82: AssertionError\n______________ TestPRequestCommand.test_command_with_query_string ______________\n\nself = <r2e_tests.test_scripts.test_prequest.TestPRequestCommand testMethod=test_command_with_query_string>\n\n    def test_command_with_query_string(self):\n        command = self._makeOne(['', 'development.ini', '/abc?a=1&b=2&c'])\n        command.run()\n        self.assertEqual(self._environ['QUERY_STRING'], 'a=1&b=2&c')\n        self.assertEqual(self._path_info, '/abc')\n        self.assertEqual(self._spec, 'development.ini')\n        self.assertEqual(self._app_name, None)\n>       self.assertEqual(self._out, ['abc'])\nE       AssertionError: Lists differ: [b'abc'] != ['abc']\nE       \nE       First differing element 0:\nE       b'abc'\nE       'abc'\nE       \nE       - [b'abc']\nE       ?  -\nE       \nE       + ['abc']\n\nr2e_tests/test_scripts/test_prequest.py:193: AssertionError\n_______________ TestPRoutesCommand.test_config_format_ini_commas _______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_commas>\n\n    def test_config_format_ini_commas(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method,name')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:728: AssertionError\n______________ TestPRoutesCommand.test_config_format_ini_newlines ______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_newlines>\n\n    def test_config_format_ini_newlines(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method\\nname')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:662: AssertionError\n_______________ TestPRoutesCommand.test_config_format_ini_spaces _______________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_config_format_ini_spaces>\n\n    def test_config_format_ini_spaces(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        config_factory = dummy.DummyConfigParserFactory()\n        command.ConfigParser = config_factory\n        config_factory.items = [('format', 'method name')]\n    \n        result = command.run()\n>       self.assertEqual(result, 0)\nE       AssertionError: 2 != 0\n\nr2e_tests/test_scripts/test_proutes.py:695: AssertionError\n_________ TestPRoutesCommand.test_one_route_all_methods_view_only_post _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_all_methods_view_only_post>\n\n    def test_one_route_all_methods_view_only_post(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method='POST'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:310: AssertionError\n_________ TestPRoutesCommand.test_one_route_only_post_view_all_methods _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_only_post_view_all_methods>\n\n    def test_one_route_only_post_view_all_methods(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:337: AssertionError\n________ TestPRoutesCommand.test_one_route_only_post_view_post_and_get _________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_only_post_view_post_and_get>\n\n    def test_one_route_only_post_view_post_and_get(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=('POST', 'GET')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1', 'POST'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'POST']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:365: AssertionError\n_____ TestPRoutesCommand.test_one_route_with_long_name_one_view_registered _____\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_one_route_with_long_name_one_view_registered>\n\n    def test_one_route_with_long_name_one_view_registered(self):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRouteRequest\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IView\n        registry = self._makeRegistry()\n    \n        def view():pass\n    \n        class IMyRoute(Interface):\n            pass\n    \n        registry.registerAdapter(\n            view,\n            (IViewClassifier, IMyRoute, Interface),\n            IView, ''\n        )\n    \n        registry.registerUtility(IMyRoute, IRouteRequest,\n                                 name='very_long_name_123')\n    \n        command = self._makeOne()\n        route = dummy.DummyRoute(\n            'very_long_name_123',\n            '/and_very_long_pattern_as_well'\n        )\n        mapper = dummy.DummyMapper(route)\n        command._get_mapper = lambda *arg: mapper\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()[:3]\n>       self.assertEqual(\n            compare_to,\n            ['very_long_name_123',\n             '/and_very_long_pattern_as_well',\n             'pyramid.tests.test_scripts.test_proutes.view']\n        )\nE       AssertionError: Lists differ: ['ver[36 chars]ttern_as_well', 'r2e_tests.test_scripts.test_proutes.view'] != ['ver[36 chars]ttern_as_well', 'pyramid.tests.test_scripts.test_proutes.view']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view'\nE       'pyramid.tests.test_scripts.test_proutes.view'\nE       \nE         ['very_long_name_123',\nE          '/and_very_long_pattern_as_well',\nE       -  'r2e_tests.test_scripts.test_proutes.view']\nE       ?    ^^^\nE       \nE       +  'pyramid.tests.test_scripts.test_proutes.view']\nE       ?   ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:196: AssertionError\n______ TestPRoutesCommand.test_route_is_get_view_request_method_not_post _______\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_is_get_view_request_method_not_post>\n\n    def test_route_is_get_view_request_method_not_post(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='GET')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            'GET'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'GET'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'GET']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', 'GET']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', 'GET']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:505: AssertionError\n____________ TestPRoutesCommand.test_route_request_method_mismatch _____________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_request_method_mismatch>\n\n    def test_route_request_method_mismatch(self):\n        from pyramid.renderers import null_renderer as nr\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b', request_method='POST')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method='GET'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '<route', 'mismatch>'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1[20 chars]ch>'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.v[24 chars]ch>']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE         ['foo',\nE          '/a/b',\nE       -  'r2e_tests.test_scripts.test_proutes.view1',\nE       ?    ^^^\nE       \nE       +  'pyramid.tests.test_scripts.test_proutes.view1',\nE       ?   ++ ^^^^^\nE       \nE          '<route',\nE          'mismatch>']\n\nr2e_tests/test_scripts/test_proutes.py:394: AssertionError\n__________________ TestPRoutesCommand.test_route_static_views __________________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_route_static_views>\n\n    def test_route_static_views(self):\n        from pyramid.renderers import null_renderer as nr\n        config = self._makeConfig(autocommit=True)\n        config.add_static_view('static', 'static', cache_max_age=3600)\n        path2 = os.path.normpath('/var/www/static')\n        config.add_static_view(name='static2', path=path2)\n        config.add_static_view(\n            name='pyramid_scaffold',\n            path='pyramid:scaffolds/starter/+package+/static'\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 5)\n    \n        expected = [\n            ['__static/', '/static/*subpath',\n             'pyramid.tests.test_scripts:static/', '*'],\n            ['__static2/', '/static2/*subpath', path2 + os.sep, '*'],\n            ['__pyramid_scaffold/', '/pyramid_scaffold/*subpath',\n             'pyramid:scaffolds/starter/+package+/static/',  '*'],\n        ]\n    \n        for index, line in enumerate(L[2:]):\n            data = line.split()\n>           self.assertEqual(data, expected[index])\nE           AssertionError: Lists differ: ['__static/', '/static/*subpath', 'r2e_tests.test_scripts:static/', '*'] != ['__static/', '/static/*subpath', 'pyramid.tests.test_scripts:static/', '*']\nE           \nE           First differing element 2:\nE           'r2e_tests.test_scripts:static/'\nE           'pyramid.tests.test_scripts:static/'\nE           \nE           - ['__static/', '/static/*subpath', 'r2e_tests.test_scripts:static/', '*']\nE           ?                                     ^^^\nE           \nE           + ['__static/', '/static/*subpath', 'pyramid.tests.test_scripts:static/', '*']\nE           ?                                    ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:425: AssertionError\n___________ TestPRoutesCommand.test_single_route_one_view_registered ___________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_single_route_one_view_registered>\n\n    def test_single_route_one_view_registered(self):\n        from zope.interface import Interface\n        from pyramid.interfaces import IRouteRequest\n        from pyramid.interfaces import IViewClassifier\n        from pyramid.interfaces import IView\n        registry = self._makeRegistry()\n    \n        def view():pass\n        class IMyRoute(Interface):\n            pass\n        registry.registerAdapter(view,\n                                 (IViewClassifier, IMyRoute, Interface),\n                                 IView, '')\n        registry.registerUtility(IMyRoute, IRouteRequest, name='a')\n        command = self._makeOne()\n        route = dummy.DummyRoute('a', '/a')\n        mapper = dummy.DummyMapper(route)\n        command._get_mapper = lambda *arg: mapper\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()[:3]\n>       self.assertEqual(\n            compare_to,\n            ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\n        )\nE       AssertionError: Lists differ: ['a', '/a', 'r2e_tests.test_scripts.test_proutes.view'] != ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view'\nE       'pyramid.tests.test_scripts.test_proutes.view'\nE       \nE       - ['a', '/a', 'r2e_tests.test_scripts.test_proutes.view']\nE       ?               ^^^\nE       \nE       + ['a', '/a', 'pyramid.tests.test_scripts.test_proutes.view']\nE       ?              ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:156: AssertionError\n______________________ TestPRoutesCommand.test_view_glob _______________________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_view_glob>\n\n    def test_view_glob(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n        def view2(context, request): return 'view2'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        config.add_route('bar', '/b/a')\n        config.add_view(\n            route_name='bar',\n            view=view2,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        command.options.glob = '*foo*'\n    \n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '!POST,*'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:576: AssertionError\n_____________ TestPRoutesCommand.test_view_request_method_not_post _____________\n\nself = <r2e_tests.test_scripts.test_proutes.TestPRoutesCommand testMethod=test_view_request_method_not_post>\n\n    def test_view_request_method_not_post(self):\n        from pyramid.renderers import null_renderer as nr\n        from pyramid.config import not_\n    \n        def view1(context, request): return 'view1'\n    \n        config = self._makeConfig(autocommit=True)\n        config.add_route('foo', '/a/b')\n        config.add_view(\n            route_name='foo',\n            view=view1,\n            renderer=nr,\n            request_method=not_('POST')\n        )\n    \n        command = self._makeOne()\n        L = []\n        command.out = L.append\n        command.bootstrap = (dummy.DummyBootstrap(registry=config.registry),)\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(len(L), 3)\n        compare_to = L[-1].split()\n        expected = [\n            'foo', '/a/b',\n            'pyramid.tests.test_scripts.test_proutes.view1',\n            '!POST,*'\n        ]\n>       self.assertEqual(compare_to, expected)\nE       AssertionError: Lists differ: ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*'] != ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       \nE       First differing element 2:\nE       'r2e_tests.test_scripts.test_proutes.view1'\nE       'pyramid.tests.test_scripts.test_proutes.view1'\nE       \nE       - ['foo', '/a/b', 'r2e_tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                   ^^^\nE       \nE       + ['foo', '/a/b', 'pyramid.tests.test_scripts.test_proutes.view1', '!POST,*']\nE       ?                  ++ ^^^^^\n\nr2e_tests/test_scripts/test_proutes.py:535: AssertionError\n_____ TestPViewsCommand.test_views_command_single_view_function_traversal ______\n\nself = <r2e_tests.test_scripts.test_pviews.TestPViewsCommand testMethod=test_views_command_single_view_function_traversal>\n\n    def test_views_command_single_view_function_traversal(self):\n        from pyramid.registry import Registry\n        registry = Registry()\n        command = self._makeOne(registry=registry)\n        L = []\n        command.out = L.append\n        def view(): pass\n        view.__request_attrs__ = {'context': 'context', 'view_name': 'a'}\n        command._find_view = lambda arg1: view\n        command.args = ('/foo/bar/myapp.ini#myapp', '/a')\n        result = command.run()\n        self.assertEqual(result, 0)\n        self.assertEqual(L[1], 'URL = /a')\n        self.assertEqual(L[3], '    context: context')\n        self.assertEqual(L[4], '    view name: a')\n>       self.assertEqual(L[8],\n                         '    pyramid.tests.test_scripts.test_pviews.view')\nE       AssertionError: '    r2e_tests.test_scripts.test_pviews.view' != '    pyramid.tests.test_scripts.test_pviews.view'\nE       -     r2e_tests.test_scripts.test_pviews.view\nE       ?      ^^^\nE       +     pyramid.tests.test_scripts.test_pviews.view\nE       ?     ++ ^^^^^\n\nr2e_tests/test_scripts/test_pviews.py:296: AssertionError\n==================================== PASSES ====================================\n=========================== short test summary info ============================\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_allows_other_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_context\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_for_\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_no_view_argument\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_allows_other_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash_custom_response\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_context\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_for_\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_no_view_argument\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_notfound_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_absolute\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_package_relative\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instance\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instance_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_class_method_no_attr\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_context_trumps_for\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_custom_more_preds_first_bests_fewer_preds_last\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_custom_predicate_bests_standard_predicate\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_default_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_no_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_default_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_no_phash\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_multiview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_mulview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exc_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only_misconfiguration\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_register_secured_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for__as_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for_as_class\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_for_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_mixed_case_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview___discriminator__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_call_ordering\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_context_superclass_then_subclass\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_exception_superclass_then_subclass\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_multiview\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_register_secured_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_same_predicates\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_no_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_with_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_view_callable_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_accept_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_check_csrf_predicates_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_containment_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_csrf_header\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_csrf_param\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_decorator\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_decorator_tuple\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_default_permission_no_explicit_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_default_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_function_callable\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_function_callable_requestonly\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_badregex\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_missing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_header_val_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_http_cache\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_mapper\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_missing_csrf_header\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_name_unicode\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_no_default_permission_no_explicit_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_nonexistant_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_badregex\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_match\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_path_info_nomatch\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_permission\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_get_implies_head\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_conflict\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_method_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_and_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_iface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_noniface\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_route_name\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_route_name_exception\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_introspector_missing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_no_renderer_factory\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_with_renderer_factory\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_conflicts\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_doesnt_conflict\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_kwarg\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_xhr_false\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_xhr_true\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_wrapped_view_is_decorated\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_views_with_accept_multiview_replaces_existing\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_function\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_no_explicit_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_with_explicit_renderer\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_set_view_mapper\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_set_view_mapper_dottedname\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate\nPASSED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate_with_mismatch\nPASSED r2e_tests/test_1.py::Test_requestonly::test_defaults\nPASSED r2e_tests/test_1.py::Test_requestonly::test_otherattr\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_IException\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_IException_subinterface\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_exception_class\nPASSED r2e_tests/test_1.py::Test_isexception::test_is_exception_instance\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__intermediate_not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test___call__raise_not_found_isnt_interpreted_as_pred_mismatch\nPASSED r2e_tests/test_1.py::TestMultiView::test___call_permissive_has_call_permissive\nPASSED r2e_tests/test_1.py::TestMultiView::test___call_permissive_has_no_call_permissive\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__with_accept_match\nPASSED r2e_tests/test_1.py::TestMultiView::test__call__with_accept_miss\nPASSED r2e_tests/test_1.py::TestMultiView::test__call_permissive__not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test_add\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash_override_accept\nPASSED r2e_tests/test_1.py::TestMultiView::test_add_with_phash_override_accept2\nPASSED r2e_tests/test_1.py::TestMultiView::test_class_implements_ISecuredView\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_best_match_returns_None\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_no_self_accepts\nPASSED r2e_tests/test_1.py::TestMultiView::test_get_views_request_has_no_accept\nPASSED r2e_tests/test_1.py::TestMultiView::test_instance_implements_ISecuredView\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_not_found\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_predicate_fails\nPASSED r2e_tests/test_1.py::TestMultiView::test_match_predicate_succeeds\nPASSED r2e_tests/test_1.py::TestMultiView::test_multiple_with_functions_as_views\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted_no_match_with__permitted__\nPASSED r2e_tests/test_1.py::TestMultiView::test_permitted_no_views\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test__view_as_function_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_function_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_context_and_request_and_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_instance_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_1.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_different\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_different_with_existing_original_view\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_same\nPASSED r2e_tests/test_1.py::Test_preserve_view_attrs::test_it_view_is_None\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_already_exists\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebust_prevented\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_abspath\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_for_more_specific_path\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_overwrite\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_cachebuster_overwrite_explicit\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_package_root\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_noendslash\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_noscheme\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_url_withendslash\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_context\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_for_\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_permission\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_renderer\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_add_viewname_with_route_prefix\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_missing\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_quoting\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_registration_miss\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_route_url\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_slash_in_name1\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_slash_in_name2\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_abspath\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_nomatch\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_quoted_remote\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_unquoted_local\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_with_custom_anchor\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_with_custom_query\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_verifyClass\nPASSED r2e_tests/test_1.py::TestStaticURLInfo::test_verifyObject\nPASSED r2e_tests/test_1.py::Test_view_description::test_with_text\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_object_event_subscriber\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_default_resource_iface_means_Interface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_nodefault_resource_iface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter_dottednames\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_response_adapter_self\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_defaults\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_dottednames\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_iface_specified\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_predicate\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_default_type_predicates_False\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_default_type_predicates_True\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_specific_type_and_predicates_False\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_subscriber_with_specific_type_and_predicates_True\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_default_iface_means_Interface\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_introspectables\nPASSED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_nondefault_iface\nPASSED r2e_tests/test_config/test_adapters.py::Test_eventonly::test_defaults\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test__override_already_registered\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test__override_not_yet_registered\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_absfile\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_file\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_absfile\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_directory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_missing_abspath\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_package\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_absdirectory\nPASSED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_samename\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_stream_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_string_override_returns_value\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_has_resource_override_returns_True\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_override_returns_False\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_isdir_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_no_overrides\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_override_returns_None\nPASSED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_resource_listdir_override_returns_values\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_class_conforms_to_IPEP302Loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_class_conforms_to_IPackageOverrides\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_package_already_has_loader_of_different_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_package_already_has_loader_of_same_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_registers_loader_type\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_sets_loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_ctor_sets_local_state\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_filtered_sources\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_code_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_code_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_data_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_data_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_filename\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_source_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_source_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_has_resource\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_has_resource_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_directory\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_emptystring\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_insert_file\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_instance_conforms_to_IPEP302Loader\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_instance_conforms_to_IPackageOverrides\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_is_package_pkg_has___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_is_package_pkg_has_no___loader__\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestPackageOverrides::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_exists_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_stream_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_string_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_exists_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_filename_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_stream_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string_file_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_get_string_with_prefix\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_false\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_isdir_true\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_listdir\nPASSED r2e_tests/test_config/test_assets.py::TestFSAssetSource::test_listdir_doesnt_exist\nPASSED r2e_tests/test_config/test_assets.py::TestDirectoryOverride::test_it_match\nPASSED r2e_tests/test_config/test_assets.py::TestDirectoryOverride::test_it_no_match\nPASSED r2e_tests/test_config/test_assets.py::TestFileOverride::test_it_match\nPASSED r2e_tests/test_config/test_assets.py::TestFileOverride::test_it_no_match\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable_and_no_name\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_None_callable_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_text_type_name\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_add_request_method_with_unnamed_callable\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_multiple_request_methods_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_request_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_request_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_response_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_response_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory_as_None\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_root_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_session_factory\nPASSED r2e_tests/test_config/test_factories.py::TestFactoriesMixin::test_set_session_factory_dottedname\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_multiple_request_properties\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_multiple_request_properties_conflict\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_callable\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_property\nPASSED r2e_tests/test_config/test_factories.py::TestDeprecatedFactoriesMixinMethods::test_set_request_property_with_unnamed_callable\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_missing_dir\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_no_specs\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_set_locale_negotiator\nPASSED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_set_locale_negotiator_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__matches\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__matches_no_action_wrap\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__missing_when_directives_dont_exist\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test___getattr__missing_when_directives_exist\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_adds__lock\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_adds_clear_view_lookup_cache\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_has_listeners\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_notify\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_queryAdapterOrSelf\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test__fix_registry_registerSelfAdapter\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_already_absolute\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_notastring\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_absolute_asset_spec_relative\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_autocommit_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_autocommit_with_introspectables_introspection_off\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_kw_is_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_kw_is_not_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_with_config_info\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_branching_nonautocommit_without_config_info\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_action_nonautocommit_with_introspectables_introspection_off\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_autocommit_no_conflicts\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_begin\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_begin_with_request\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_resolved_with_include\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_resolved_with_two_includes_and_local\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_simple\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_commit_conflict_with_two_includes\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_conflict_set_forbidden_view\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_conflict_set_notfound_view\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_alternate_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_authentication_policy\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_authorization_policy_only\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_permission\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_view_mapper\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_default_webob_response_adapter_registered\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_exceptionresponse_view_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_exceptionresponse_view_custom\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_httpexception_view_default\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_no_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_custom_settings\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_debug_logger_non_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_session_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_introspection\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_package_registry\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_with_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_end\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_hook_zca\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_dotted_name\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_missing_source_file\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_module_defaults_to_includeme\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_module_defaults_to_includeme_missing\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_nested_route_prefix\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_python_callable\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_with_route_prefix\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_introspector_decorator\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_make_wsgi_app\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_notstring_success\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_string_fail\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_maybe_dotted_string_success\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_dottedname_package\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_extra_kw\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_ignore\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_with_onerror\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_alternate_renderers\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authentication_policy\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authentication_policy_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authorization_policy_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_authorization_policy_only\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_calls_fix_registry\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_custom_settings\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_name\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_non_None\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_default_permission\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_dottedname_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_explicit_notfound_trumps_iexceptionresponse\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_includes\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_includes_spaces\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_locale_negotiator\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_locale_negotiator_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_no_default_root_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_exceptionresponse_views\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_view_predicates\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_registers_default_webob_iresponse_adapter\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_request_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_request_factory_dottedname\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_response_factory\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_tweens\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_unhook_zca\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package_module\nPASSED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_with_package_package\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_directive_persists_across_configurator_creations\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_action_method_successful\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_same_name_doesnt_conflict\nPASSED r2e_tests/test_config/test_init.py::TestConfigurator__add_predicate::test_factory_as_object\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_simple\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_includepath\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_includepath_and_info\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_info\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_action_with_order\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_dicts\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_error\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_tuples\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_with_introspectable_no_callable\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_execute_actions_with_introspectables\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_it\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_processSpec\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action_error\nPASSED r2e_tests/test_config/test_init.py::TestActionState::test_reentrant_action_without_clear\nPASSED r2e_tests/test_config/test_init.py::Test_reentrant_action_functional::test_functional\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_conflict\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_success_dicts\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_success_tuples\nPASSED r2e_tests/test_config/test_init.py::Test_resolveConflicts::test_it_with_actions_grouped_by_order\nPASSED r2e_tests/test_config/test_init.py::TestGlobalRegistriesIntegration::test_global_registries\nPASSED r2e_tests/test_config/test_init.py::TestGlobalRegistriesIntegration::test_global_registries_empty\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestXHRPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test___call___true_single\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_ctor_get_but_no_head\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestMethodPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_ctor_compilefail\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestPathInfoPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___false_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test___call___true_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_exists_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_phash_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_exists_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_multi_equal_sign\nPASSED r2e_tests/test_config/test_predicates.py::TestRequestParamPredicate::test_text_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___matchdict_is_None\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___true_multi\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test___call___true_single\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestMatchParamPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test___call___true\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_text_func_has___text__\nPASSED r2e_tests/test_config/test_predicates.py::TestCustomPredicate::test_text_func_repr\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_has_remainder_already\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_matches\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test___call__traverse_matches_with_highorder_chars\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::TestTraversePredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_False\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_it_call_val_str\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_CheckCSRFTokenPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___false\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___false_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test___call___true_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_phash_withval\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_exists\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_withregex\nPASSED r2e_tests/test_config/test_predicates.py::TestHeaderPredicate::test_text_withval\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_False\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_context_has_no_name\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_list_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_str_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_it_call_val_tuple_True\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_PhysicalPathPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_doesnt_provide_superset\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_provides_superset\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_authentication_policy_provides_superset_implicit\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_it_call_no_authentication_policy\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_phash\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_text\nPASSED r2e_tests/test_config/test_predicates.py::Test_EffectivePrincipalsPredicate::test_text_noniter\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_default_renderers\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_renderer\nPASSED r2e_tests/test_config/test_rendering.py::TestRenderingConfiguratorMixin::test_add_renderer_dottedname_factory\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_defaults\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_discriminator\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_path_no_pattern\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_pattern_with_path\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_attr\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_context\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_permission\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_no_view_with_view_renderer\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_accept\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_custom_predicates\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_factory\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_factory_dottedname\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_header\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info_highorder\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_path_info_regex\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_pregenerator\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_request_method\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_request_param\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_route_prefix\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_static\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_add_route_with_xhr\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_get_routes_mapper_already_registered\nPASSED r2e_tests/test_config/test_routes.py::RoutesConfiguratorMixinTests::test_get_routes_mapper_not_yet_registered\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_add_permission\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_changing_set_default_csrf_options\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_no_authz_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_no_authz_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_with_authz_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authentication_policy_with_authz_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_no_authn_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_no_authn_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_with_authn_policy\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_authorization_policy_with_authn_policy_autocommit\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_default_csrf_options\nPASSED r2e_tests/test_config/test_security.py::ConfiguratorSecurityMethodsTests::test_set_default_permission\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test__set_settings_as_None\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test__set_settings_as_dictwithvalues\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_None\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_already_registered\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_add_settings_settings_not_yet_registered\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_get_settings_nosettings\nPASSED r2e_tests/test_config/test_settings.py::TestSettingsConfiguratorMixin::test_get_settings_withsettings\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_all\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_authorization\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_notfound\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_routematch\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_debug_templates\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_default_locale_name\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_fail\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_raises_attribute_error\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_getattr_success\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_noargs\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_originals_kept\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_prevent_cachebust\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_prevent_http_cache\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_all\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_assets\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_resources\nPASSED r2e_tests/test_config/test_settings.py::TestSettings::test_reload_templates\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer_explicitrenderer\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_renderer_twice\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_defaults\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_dottedname\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_multiple\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_subscriber_single\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_add_template\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_resources\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy_forget_result\nPASSED r2e_tests/test_config/test_testing.py::TestingConfiguratorMixinTests::test_testing_securitypolicy_remember_result\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_dottedname\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_instance\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_name_ingress\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_name_main\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_over_ingress\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_over_ingress_iterable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_under_main\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_under_main_iterable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tween_unsuitable\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_conflict\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_distinct\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_over_nonstringoriter\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_under_nonstringoriter\nPASSED r2e_tests/test_config/test_tweens.py::TestTweensConfiguratorMixin::test_add_tweens_names_with_underover\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test___call___explicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test___call___implicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_add_explicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_add_implicit\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_1\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_2\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_3\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_4\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_5\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_conflict_direct\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_conflict_indirect\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_and_under_partials\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_partial\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_over_partial_with_fallback\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_under_partial\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_missing_under_partial_with_fallback\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_missing_fallbacks\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_multiple_matching_fallbacks\nPASSED r2e_tests/test_config/test_tweens.py::TestTweens::test_implicit_ordering_with_partial_fallbacks\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_custom_predicates_can_affect_traversal\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_different_custom_predicates_with_same_hash\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_dict\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_dict_fails\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_string\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_match_param_from_string_fails\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_notted\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_importance_and_number\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_importance_of_predicates\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_number_of_predicates\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_ordering_xhr_and_request_method_trump_only_containment\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_predicate_text_is_correct\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_request_method_ordering_hashes_same\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_request_method_sequence\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_has_remainder_already\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_matches\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_traverse_matches_with_highorder_chars\nPASSED r2e_tests/test_config/test_util.py::TestPredicateList::test_unknown_predicate\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_annotations\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_with_attr_false\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_function_with_attr_true\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_defaultargs_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_nocall\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_instance_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_method_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_firstname_request_with_secondname\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_newstyle_class_init_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_defaultargs_firstname_not_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_defaultargs_firstname_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_noargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_onearg_named_somethingelse\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_init_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_oldstyle_class_no_init\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_init_onearg_named_request\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_init_toomanyargs\nPASSED r2e_tests/test_config/test_util.py::Test_takes_one_arg::test_requestonly_newstyle_class_no_init\nPASSED r2e_tests/test_config/test_util.py::TestNotted::test_it_with_phash_val\nPASSED r2e_tests/test_config/test_util.py::TestNotted::test_it_without_phash_val\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_allows_other_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_context\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_for_\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_disallows_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_no_view_argument\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_forbidden_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_allows_other_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_append_slash_custom_response\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_context\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_for_\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_disallows_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_no_view_argument\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_notfound_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_absolute\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_here_no_utility_registered\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_package_relative\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instance\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instance_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_instancemethod_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_class_method_no_attr\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_context_trumps_for\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_custom_more_preds_first_bests_fewer_preds_last\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_custom_predicate_bests_standard_predicate\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_default_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_default_phash_overrides_no_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_default_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_default_phash_overrides_no_phash\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_multiview_replaces_multiview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_mulview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exc_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only_misconfiguration\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_register_secured_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for__as_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for_as_class\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_for_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_mixed_case_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview___discriminator__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_call_ordering\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_context_superclass_then_subclass\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_exception_superclass_then_subclass\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_securedview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_existing_view_with___accept__\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_multiview_replaces_multiview\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_register_secured_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_same_phash_overrides_existing_single_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_same_predicates\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_no_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_None_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_view_callable_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_multiview_replaces_existing_view\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_accept_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_check_csrf_predicates_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_containment_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_csrf_header\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_csrf_param\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_custom_predicates_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_decorator\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_decorator_tuple\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_default_permission_no_explicit_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_default_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_function_callable\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_function_callable_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_badregex\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_noval_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_missing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_header_val_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_http_cache\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_mapper\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_missing_csrf_header\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_name_unicode\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_no_default_permission_no_explicit_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_nonexistant_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_badregex\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_match\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_path_info_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_permission\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_get_implies_head\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_conflict\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_sequence_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_method_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_noval_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_param_val_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_and_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_iface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_request_type_as_noniface\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_route_name\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_route_name_exception\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_introspector_missing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_no_renderer_factory\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_tmpl_renderer_factory_with_renderer_factory\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_conflicts\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_config_and_view_defaults_doesnt_conflict\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_kwarg\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_xhr_false\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_xhr_true\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_wrapped_view_is_decorated\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_views_with_accept_multiview_replaces_existing\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_function\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_no_explicit_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_derive_view_with_default_renderer_with_explicit_renderer\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_set_view_mapper\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_set_view_mapper_dottedname\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate\nPASSED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_view_with_most_specific_predicate_with_mismatch\nPASSED r2e_tests/test_config/test_views.py::Test_requestonly::test_defaults\nPASSED r2e_tests/test_config/test_views.py::Test_requestonly::test_otherattr\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_IException\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_IException_subinterface\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_exception_class\nPASSED r2e_tests/test_config/test_views.py::Test_isexception::test_is_exception_instance\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__intermediate_not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call__raise_not_found_isnt_interpreted_as_pred_mismatch\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call_permissive_has_call_permissive\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test___call_permissive_has_no_call_permissive\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__with_accept_match\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call__with_accept_miss\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test__call_permissive__not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash_override_accept\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_add_with_phash_override_accept2\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_class_implements_ISecuredView\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_best_match_returns_None\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_no_self_accepts\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_get_views_request_has_no_accept\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_instance_implements_ISecuredView\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_not_found\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_predicate_fails\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_match_predicate_succeeds\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_multiple_with_functions_as_views\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted_no_match_with__permitted__\nPASSED r2e_tests/test_config/test_views.py::TestMultiView::test_permitted_no_views\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test__view_as_function_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_function_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_context_and_request_and_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_instance_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_newstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_context_and_request_with_attr\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly\nPASSED r2e_tests/test_config/test_views.py::TestDefaultViewMapper::test_view_as_oldstyle_class_requestonly_with_attr\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_different\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_different_with_existing_original_view\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_same\nPASSED r2e_tests/test_config/test_views.py::Test_preserve_view_attrs::test_it_view_is_None\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_already_exists\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebust_prevented\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_abspath\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_for_more_specific_path\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_overwrite\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_cachebuster_overwrite_explicit\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_package_root\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_noendslash\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_noscheme\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_url_withendslash\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_context\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_for_\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_permission\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_renderer\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_add_viewname_with_route_prefix\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_missing\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_quoting\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_registration_miss\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_route_url\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_slash_in_name1\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_slash_in_name2\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_abspath\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_nomatch\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_quoted_remote\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_unquoted_local\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_with_custom_anchor\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_with_custom_query\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_verifyClass\nPASSED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_verifyObject\nPASSED r2e_tests/test_config/test_views.py::Test_view_description::test_with_text\nPASSED r2e_tests/test_scripts/test_common.py::Test_logging_file_config::test_it\nPASSED r2e_tests/test_scripts/test_common.py::TestParseVars::test_parse_vars_bad\nPASSED r2e_tests/test_scripts/test_common.py::TestParseVars::test_parse_vars_good\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_confirm_override_conflicting_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_force_override_conflicting_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_force_override_site_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_absolute_path\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_multiple_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_single_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_known_scaffold_with_path_as_project_target_rendered\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_no_project_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_no_scaffold_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_no_scaffold_no_args\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_show_scaffolds_exist\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_run_show_scaffolds_none_exist\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_dev_pyramid_long_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_dev_pyramid_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_hyphen_in_project_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_long_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_unparsable_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_scaffold_with_prod_pyramid_version\nPASSED r2e_tests/test_scripts/test_pcreate.py::TestPCreateCommand::test_unknown_scaffold_name\nPASSED r2e_tests/test_scripts/test_pcreate.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pdistreport.py::TestPDistReportCommand::test_no_dists\nPASSED r2e_tests/test_scripts/test_pdistreport.py::TestPDistReportCommand::test_with_dists\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_bad_config_header\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_configures_logging\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_not_enough_args\nPASSED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_response_has_no_charset\nPASSED r2e_tests/test_scripts/test_prequest.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test__get_mapper\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_bad_args\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_bad_format\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_good_args\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_good_format\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_no_mapper\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_no_routes\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_as_wsgiapp\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_no_view\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_with_no_slash_prefix\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_multiview_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_no_route_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_no_views_registered\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_one_view_registered_with_factory\nPASSED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_static_routes_included_in_list\nPASSED r2e_tests/test_scripts/test_proutes.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_get_options_no_command\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_get_options_with_command\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_parse_vars_bad\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_parse_vars_good\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_record_pid_not_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_record_pid_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_current_pid_is_not_pid_in_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_current_pid_is_not_written_pid\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_not_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_stale_pid_write_exception\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_unlink_exception\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_file_verbose\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_no_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_remove_pid_not_a_number\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_no_args\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_bad_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_invalid_pid_in_file\nPASSED r2e_tests/test_scripts/test_pserve.py::TestPServeCommand::test_run_stop_daemon_no_such_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile_no_pid_file\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_read_pidfile::test_read_pidfile_not_a_number\nPASSED r2e_tests/test_scripts/test_pserve.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_flush\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_open\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_write\nPASSED r2e_tests/test_scripts/test_pserve.py::TestLazyWriter::test_writeline\nPASSED r2e_tests/test_scripts/test_pserve.py::Test__methodwrapper::test___call__fail\nPASSED r2e_tests/test_scripts/test_pserve.py::Test__methodwrapper::test___call__succeed\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_custom_section_override\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_default_shell_option\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_errors_with_unknown_shell\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_check_variable_override_order\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_custom_items\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_default_shell\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_ipython\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_pythonstartup\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_loads_setup_from_options\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_command_setup\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_list_shells\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_entry_points\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_ordering\nPASSED r2e_tests/test_scripts/test_pshell.py::TestPShellCommand::test_shell_override\nPASSED r2e_tests/test_scripts/test_pshell.py::Test_python_shell_runner::test_it\nPASSED r2e_tests/test_scripts/test_pshell.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test__get_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_implicit_and_explicit_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_implicit_tweens_only\nPASSED r2e_tests/test_scripts/test_ptweens.py::TestPTweensCommand::test_command_no_tweens\nPASSED r2e_tests/test_scripts/test_ptweens.py::Test_main::test_it\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_all_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_none_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_multi_routes_some_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_no_match\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_no_match_multiview_registered\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_multiview_no_view_registered\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_route_no_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_traversal\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test__find_view_traversal_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multi_view_nested\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview_with_permission\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_multiview_with_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_not_found\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_not_found_url_starts_without_slash\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_route\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_route_with_route_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal_with_permission\nPASSED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_traversal_with_predicates\nPASSED r2e_tests/test_scripts/test_pviews.py::Test_main::test_it\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_here_no_utility_registered\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_static_view_package_here_relative\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_exception_only_no_regular_view\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer\nFAILED r2e_tests/test_1.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer_no_callable\nFAILED r2e_tests/test_1.py::TestStaticURLInfo::test_generate_url_cachebust_with_overrides\nFAILED r2e_tests/test_1.py::Test_view_description::test_without_text - Assert...\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_adapter_dotted_names\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_resource_url_adapter_introspectables\nFAILED r2e_tests/test_config/test_adapters.py::AdaptersConfiguratorMixinTests::test_add_traverser_dotted_names\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_directory\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_directory_with_package\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_file_with_file\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_directory\nFAILED r2e_tests/test_config/test_assets.py::TestAssetsConfiguratorMixin::test_override_asset_package_with_package\nFAILED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_no_overrides\nFAILED r2e_tests/test_config/test_assets.py::TestOverrideProvider::test_get_resource_filename_override_returns_None\nFAILED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename\nFAILED r2e_tests/test_config/test_assets.py::TestPackageAssetSource::test_get_filename_with_prefix\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_abspath\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_asset_spec\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_asset_spec_existing_translation_dirs\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_multiple_specs\nFAILED r2e_tests/test_config/test_i18n.py::TestI18NConfiguratorMixin::test_add_translation_dirs_multiple_specs_multiple_calls\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_no_registry\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_ctor_noreg_debug_logger_None_default\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_include_constant_root_package\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_scan_integration_conflict\nFAILED r2e_tests/test_config/test_init.py::ConfiguratorTests::test_setup_registry_debug_logger_None_default\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_add_directive_with_custom_callable\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_add_directive_with_partial\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_with_dotted_name\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator_add_directive::test_extend_with_python_callable\nFAILED r2e_tests/test_config/test_init.py::TestConfigurator__add_predicate::test_factory_as_dotted_name\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_static_view_package_here_relative\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_exception_only_no_regular_view\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer\nFAILED r2e_tests/test_config/test_views.py::TestViewsConfigurationMixin::test_add_view_with_template_renderer_no_callable\nFAILED r2e_tests/test_config/test_views.py::TestStaticURLInfo::test_generate_url_cachebust_with_overrides\nFAILED r2e_tests/test_config/test_views.py::Test_view_description::test_without_text\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_display_headers\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_content_type_header_var\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_good_header_var\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_has_multiple_header_vars\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_get\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_options\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_patch\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_post\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_propfind\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_method_put\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_path_doesnt_start_with_slash\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_two_args\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_w_basic_auth\nFAILED r2e_tests/test_scripts/test_prequest.py::TestPRequestCommand::test_command_with_query_string\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_commas\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_newlines\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_config_format_ini_spaces\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_all_methods_view_only_post\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_only_post_view_all_methods\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_only_post_view_post_and_get\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_one_route_with_long_name_one_view_registered\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_is_get_view_request_method_not_post\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_request_method_mismatch\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_route_static_views\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_single_route_one_view_registered\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_view_glob\nFAILED r2e_tests/test_scripts/test_proutes.py::TestPRoutesCommand::test_view_request_method_not_post\nFAILED r2e_tests/test_scripts/test_pviews.py::TestPViewsCommand::test_views_command_single_view_function_traversal\n======================= 70 failed, 1057 passed in 5.73s ========================\n",
    "old_commit_res_stderr": ""
}
pyramid/config/views.py pyramid/tests/test_config/test_views.py
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Unable to Register Exception-Only Views Using `exception_only` Argument

**Description:**
When attempting to register a view with the `exception_only` parameter set to `True`, a `ConfigurationError` is raised indicating that `exception_only` is an unknown view option. This prevents the registration of views that are intended to handle only exceptions.

**Example Code:**
```python
from pyramid.config import Configurator
from pyramid.exceptions import ConfigurationError

def exception_view(exc, request):
    return {'message': 'An exception occurred'}

config = Configurator()
config.add_view(view=exception_view, context=Exception, exception_only=True)
app = config.make_wsgi_app()
```

**Expected Behavior:**
The view should be successfully registered as an exception-only view, allowing it to handle exceptions without being registered as a regular view.

**Actual Behavior:**
A `ConfigurationError` is raised with the message:
```
Unknown view options: {'exception_only': True}
```
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### pyramid/config/views.py
import inspect
import posixpath
import operator
import os
import warnings

from zope.interface import (
    Interface,
    implementedBy,
    implementer,
    )

from zope.interface.interfaces import IInterface

from pyramid.interfaces import (
    IException,
    IExceptionViewClassifier,
    IMultiView,
    IPackageOverrides,
    IRendererFactory,
    IRequest,
    IResponse,
    IRouteRequest,
    ISecuredView,
    IStaticURLInfo,
    IView,
    IViewClassifier,
    IViewDerivers,
    IViewDeriverInfo,
    IViewMapperFactory,
    PHASE1_CONFIG,
    )

from pyramid import renderers

from pyramid.asset import resolve_asset_spec
from pyramid.compat import (
    string_types,
    urlparse,
    url_quote,
    WIN,
    is_nonstr_iter,
    )

from pyramid.decorator import reify

from pyramid.exceptions import (
    ConfigurationError,
    PredicateMismatch,
    )

from pyramid.httpexceptions import (
    HTTPForbidden,
    HTTPNotFound,
    default_exceptionresponse_view,
    )

from pyramid.registry import (
    predvalseq,
    Deferred,
    )

from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.static import static_view

from pyramid.url import parse_url_overrides

from pyramid.view import AppendSlashNotFoundViewFactory

import pyramid.util
from pyramid.util import (
    viewdefaults,
    action_method,
    TopologicalSorter,
    )

import pyramid.config.predicates
import pyramid.viewderivers

from pyramid.viewderivers import (
    INGRESS,
    VIEW,
    preserve_view_attrs,
    view_description,
    requestonly,
    DefaultViewMapper,
    wraps_view,
)

from pyramid.config.util import (
    DEFAULT_PHASH,
    MAX_ORDER,
    as_sorted_tuple,
    )

urljoin = urlparse.urljoin
url_parse = urlparse.urlparse

DefaultViewMapper = DefaultViewMapper # bw-compat
preserve_view_attrs = preserve_view_attrs # bw-compat
requestonly = requestonly # bw-compat
view_description = view_description # bw-compat

@implementer(IMultiView)
class MultiView(object):

    def __init__(self, name):
        self.name = name
        self.media_views = {}
        self.views = []
        self.accepts = []

    def __discriminator__(self, context, request):
        # used by introspection systems like so:
        # view = adapters.lookup(....)
        # view.__discriminator__(context, request) -> view's discriminator
        # so that superdynamic systems can feed the discriminator to
        # the introspection system to get info about it
        view = self.match(context, request)
        return view.__discriminator__(context, request)

    def add(self, view, order, accept=None, phash=None):
        if phash is not None:
            for i, (s, v, h) in enumerate(list(self.views)):
                if phash == h:
                    self.views[i] = (order, view, phash)
                    return

        if accept is None or '*' in accept:
            self.views.append((order, view, phash))
            self.views.sort(key=operator.itemgetter(0))
        else:
            subset = self.media_views.setdefault(accept, [])
            for i, (s, v, h) in enumerate(list(subset)):
                if phash == h:
                    subset[i] = (order, view, phash)
                    return
            else:
                subset.append((order, view, phash))
                subset.sort(key=operator.itemgetter(0))
            accepts = set(self.accepts)
            accepts.add(accept)
            self.accepts = list(accepts) # dedupe

    def get_views(self, request):
        if self.accepts and hasattr(request, 'accept'):
            accepts = self.accepts[:]
            views = []
            while accepts:
                match = request.accept.best_match(accepts)
                if match is None:
                    break
                subset = self.media_views[match]
                views.extend(subset)
                accepts.remove(match)
            views.extend(self.views)
            return views
        return self.views

    def match(self, context, request):
        for order, view, phash in self.get_views(request):
            if not hasattr(view, '__predicated__'):
                return view
            if view.__predicated__(context, request):
                return view
        raise PredicateMismatch(self.name)

    def __permitted__(self, context, request):
        view = self.match(context, request)
        if hasattr(view, '__permitted__'):
            return view.__permitted__(context, request)
        return True

    def __call_permissive__(self, context, request):
        view = self.match(context, request)
        view = getattr(view, '__call_permissive__', view)
        return view(context, request)

    def __call__(self, context, request):
        for order, view, phash in self.get_views(request):
            try:
                return view(context, request)
            except PredicateMismatch:
                continue
        raise PredicateMismatch(self.name)

class ViewsConfiguratorMixin(object):
    @viewdefaults
    @action_method
    def add_view(
        self,
        view=None,
        name="",
        for_=None,
        permission=None,
        request_type=None,
        route_name=None,
        request_method=None,
        request_param=None,
        containment=None,
        attr=None,
        renderer=None,
        wrapper=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        context=None,
        decorator=None,
        mapper=None,
        http_cache=None,
        match_param=None,
        check_csrf=None,
        require_csrf=None,
        **view_options):
        """ Add a :term:`view configuration` to the current
        configuration state.  Arguments to ``add_view`` are broken
        down below into *predicate* arguments and *non-predicate*
        arguments.  Predicate arguments narrow the circumstances in
        which the view callable will be invoked when a request is
        presented to :app:`Pyramid`; non-predicate arguments are
        informational.

        Non-Predicate Arguments

        view

          A :term:`view callable` or a :term:`dotted Python name`
          which refers to a view callable.  This argument is required
          unless a ``renderer`` argument also exists.  If a
          ``renderer`` argument is passed, and a ``view`` argument is
          not provided, the view callable defaults to a callable that
          returns an empty dictionary (see
          :ref:`views_which_use_a_renderer`).

        permission

          A :term:`permission` that the user must possess in order to invoke
          the :term:`view callable`.  See :ref:`view_security_section` for
          more information about view security and permissions.  This is
          often a string like ``view`` or ``edit``.

          If ``permission`` is omitted, a *default* permission may be used
          for this view registration if one was named as the
          :class:`pyramid.config.Configurator` constructor's
          ``default_permission`` argument, or if
          :meth:`pyramid.config.Configurator.set_default_permission` was used
          prior to this view registration.  Pass the value
          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission
          argument to explicitly indicate that the view should always be
          executable by entirely anonymous users, regardless of the default
          permission, bypassing any :term:`authorization policy` that may be
          in effect.

        attr

          This knob is most useful when the view definition is a class.

          The view machinery defaults to using the ``__call__`` method
          of the :term:`view callable` (or the function itself, if the
          view callable is a function) to obtain a response.  The
          ``attr`` value allows you to vary the method attribute used
          to obtain the response.  For example, if your view was a
          class, and the class has a method named ``index`` and you
          wanted to use this method instead of the class' ``__call__``
          method to return the response, you'd say ``attr="index"`` in the
          view configuration for the view.

        renderer

          This is either a single string term (e.g. ``json``) or a
          string implying a path or :term:`asset specification`
          (e.g. ``templates/views.pt``) naming a :term:`renderer`
          implementation.  If the ``renderer`` value does not contain
          a dot ``.``, the specified string will be used to look up a
          renderer implementation, and that renderer implementation
          will be used to construct a response from the view return
          value.  If the ``renderer`` value contains a dot (``.``),
          the specified term will be treated as a path, and the
          filename extension of the last element in the path will be
          used to look up the renderer implementation, which will be
          passed the full path.  The renderer implementation will be
          used to construct a :term:`response` from the view return
          value.

          Note that if the view itself returns a :term:`response` (see
          :ref:`the_response`), the specified renderer implementation
          is never called.

          When the renderer is a path, although a path is usually just
          a simple relative pathname (e.g. ``templates/foo.pt``,
          implying that a template named "foo.pt" is in the
          "templates" directory relative to the directory of the
          current :term:`package` of the Configurator), a path can be
          absolute, starting with a slash on UNIX or a drive letter
          prefix on Windows.  The path can alternately be a
          :term:`asset specification` in the form
          ``some.dotted.package_name:relative/path``, making it
          possible to address template assets which live in a
          separate package.

          The ``renderer`` attribute is optional.  If it is not
          defined, the "null" renderer is assumed (no rendering is
          performed and the value is passed back to the upstream
          :app:`Pyramid` machinery unmodified).

        http_cache

          .. versionadded:: 1.1

          When you supply an ``http_cache`` value to a view configuration,
          the ``Expires`` and ``Cache-Control`` headers of a response
          generated by the associated view callable are modified.  The value
          for ``http_cache`` may be one of the following:

          - A nonzero integer.  If it's a nonzero integer, it's treated as a
            number of seconds.  This number of seconds will be used to
            compute the ``Expires`` header and the ``Cache-Control:
            max-age`` parameter of responses to requests which call this view.
            For example: ``http_cache=3600`` instructs the requesting browser
            to 'cache this response for an hour, please'.

          - A ``datetime.timedelta`` instance.  If it's a
            ``datetime.timedelta`` instance, it will be converted into a
            number of seconds, and that number of seconds will be used to
            compute the ``Expires`` header and the ``Cache-Control:
            max-age`` parameter of responses to requests which call this view.
            For example: ``http_cache=datetime.timedelta(days=1)`` instructs
            the requesting browser to 'cache this response for a day, please'.

          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and
            ``Expires`` headers present in all responses from this view will
            be composed such that client browser cache (and any intermediate
            caches) are instructed to never cache the response.

          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,
            {'public':True})``), the first value in the tuple may be a
            nonzero integer or a ``datetime.timedelta`` instance; in either
            case this value will be used as the number of seconds to cache
            the response.  The second value in the tuple must be a
            dictionary.  The values present in the dictionary will be used as
            input to the ``Cache-Control`` response header.  For example:
            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,
            and add ``public`` to the Cache-Control header of the response'.
            All keys and values supported by the
            ``webob.cachecontrol.CacheControl`` interface may be added to the
            dictionary.  Supplying ``{'public':True}`` is equivalent to
            calling ``response.cache_control.public = True``.

          Providing a non-tuple value as ``http_cache`` is equivalent to
          calling ``response.cache_expires(value)`` within your view's body.

          Providing a two-tuple value as ``http_cache`` is equivalent to
          calling ``response.cache_expires(value[0], **value[1])`` within your
          view's body.

          If you wish to avoid influencing, the ``Expires`` header, and
          instead wish to only influence ``Cache-Control`` headers, pass a
          tuple as ``http_cache`` with the first element of ``None``, e.g.:
          ``(None, {'public':True})``.

          If you wish to prevent a view that uses ``http_cache`` in its
          configuration from having its caching response headers changed by
          this machinery, set ``response.cache_control.prevent_auto = True``
          before returning the response from the view.  This effectively
          disables any HTTP caching done by ``http_cache`` for that response.

        require_csrf

          .. versionadded:: 1.7

          A boolean option or ``None``. Default: ``None``.

          If this option is set to ``True`` then CSRF checks will be enabled
          for requests to this view. The required token or header default to
          ``csrf_token`` and ``X-CSRF-Token``, respectively.

          CSRF checks only affect "unsafe" methods as defined by RFC2616. By
          default, these methods are anything except
          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.

          The defaults here may be overridden by
          :meth:`pyramid.config.Configurator.set_default_csrf_options`.

          This feature requires a configured :term:`session factory`.

          If this option is set to ``False`` then CSRF checks will be disabled
          regardless of the default ``require_csrf`` setting passed
          to ``set_default_csrf_options``.

          See :ref:`auto_csrf_checking` for more information.

        wrapper

          The :term:`view name` of a different :term:`view
          configuration` which will receive the response body of this
          view as the ``request.wrapped_body`` attribute of its own
          :term:`request`, and the :term:`response` returned by this
          view as the ``request.wrapped_response`` attribute of its
          own request.  Using a wrapper makes it possible to "chain"
          views together to form a composite response.  The response
          of the outermost wrapper view will be returned to the user.
          The wrapper view will be found as any view is found: see
          :ref:`view_lookup`.  The "best" wrapper view will be found
          based on the lookup ordering: "under the hood" this wrapper
          view is looked up via
          ``pyramid.view.render_view_to_response(context, request,
          'wrapper_viewname')``. The context and request of a wrapper
          view is the same context and request of the inner view.  If
          this attribute is unspecified, no view wrapping is done.

        decorator

          A :term:`dotted Python name` to function (or the function itself,
          or an iterable of the aforementioned) which will be used to
          decorate the registered :term:`view callable`.  The decorator
          function(s) will be called with the view callable as a single
          argument.  The view callable it is passed will accept
          ``(context, request)``.  The decorator(s) must return a
          replacement view callable which also accepts ``(context,
          request)``.

          If decorator is an iterable, the callables will be combined and
          used in the order provided as a decorator.
          For example::

            @view_config(...,
                decorator=(decorator2,
                           decorator1))
            def myview(request):
                ....

          Is similar to doing::

            @view_config(...)
            @decorator2
            @decorator1
            def myview(request):
                ...

          Except with the existing benefits of ``decorator=`` (having a common
          decorator syntax for all view calling conventions and not having to
          think about preserving function attributes such as ``__name__`` and
          ``__module__`` within decorator logic).

          All view callables in the decorator chain must return a response
          object implementing :class:`pyramid.interfaces.IResponse` or raise
          an exception:

          .. code-block:: python

             def log_timer(wrapped):
                 def wrapper(context, request):
                     start = time.time()
                     response = wrapped(context, request)
                     duration = time.time() - start
                     response.headers['X-View-Time'] = '%.3f' % (duration,)
                     log.info('view took %.3f seconds', duration)
                     return response
                 return wrapper

          .. versionchanged:: 1.4a4
             Passing an iterable.

        mapper

          A Python object or :term:`dotted Python name` which refers to a
          :term:`view mapper`, or ``None``.  By default it is ``None``, which
          indicates that the view should use the default view mapper.  This
          plug-point is useful for Pyramid extension developers, but it's not
          very useful for 'civilians' who are just developing stock Pyramid
          applications. Pay no attention to the man behind the curtain.

        accept

          This value represents a match query for one or more mimetypes in the
          ``Accept`` HTTP request header.  If this value is specified, it must
          be in one of the following forms: a mimetype match token in the form
          ``text/plain``, a wildcard mimetype match token in the form
          ``text/*`` or a match-all wildcard mimetype match token in the form
          ``*/*``.  If any of the forms matches the ``Accept`` header of the
          request, or if the ``Accept`` header isn't set at all in the request,
          this will match the current view. If this does not match the
          ``Accept`` header of the request, view matching continues.

        Predicate Arguments

        name

          The :term:`view name`.  Read :ref:`traversal_chapter` to
          understand the concept of a view name.

        context

          An object or a :term:`dotted Python name` referring to an
          interface or class object that the :term:`context` must be
          an instance of, *or* the :term:`interface` that the
          :term:`context` must provide in order for this view to be
          found and called.  This predicate is true when the
          :term:`context` is an instance of the represented class or
          if the :term:`context` provides the represented interface;
          it is otherwise false.  This argument may also be provided
          to ``add_view`` as ``for_`` (an older, still-supported
          spelling).

        route_name

          This value must match the ``name`` of a :term:`route
          configuration` declaration (see :ref:`urldispatch_chapter`)
          that must match before this view will be called.

        request_type

          This value should be an :term:`interface` that the
          :term:`request` must provide in order for this view to be
          found and called.  This value exists only for backwards
          compatibility purposes.

        request_method

          This value can be either a string (such as ``"GET"``, ``"POST"``,
          ``"PUT"``, ``"DELETE"``, ``"HEAD"`` or ``"OPTIONS"``) representing
          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of
          these strings.  A view declaration with this argument ensures that
          the view will only be called when the ``method`` attribute of the
          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches
          a supplied value.  Note that use of ``GET`` also implies that the
          view will respond to ``HEAD`` as of Pyramid 1.4.

          .. versionchanged:: 1.2
             The ability to pass a tuple of items as ``request_method``.
             Previous versions allowed only a string.

        request_param

          This value can be any string or any sequence of strings.  A view
          declaration with this argument ensures that the view will only be
          called when the :term:`request` has a key in the ``request.params``
          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a
          name which matches the supplied value (if the value is a string)
          or values (if the value is a tuple).  If any value
          supplied has a ``=`` sign in it,
          e.g. ``request_param="foo=123"``, then the key (``foo``)
          must both exist in the ``request.params`` dictionary, *and*
          the value must match the right hand side of the expression
          (``123``) for the view to "match" the current request.

        match_param

          .. versionadded:: 1.2

          This value can be a string of the format "key=value" or a tuple
          containing one or more of these strings.

          A view declaration with this argument ensures that the view will
          only be called when the :term:`request` has key/value pairs in its
          :term:`matchdict` that equal those supplied in the predicate.
          e.g. ``match_param="action=edit"`` would require the ``action``
          parameter in the :term:`matchdict` match the right hand side of
          the expression (``edit``) for the view to "match" the current
          request.

          If the ``match_param`` is a tuple, every key/value pair must match
          for the predicate to pass.

        containment

          This value should be a Python class or :term:`interface` (or a
          :term:`dotted Python name`) that an object in the
          :term:`lineage` of the context must provide in order for this view
          to be found and called.  The nodes in your object graph must be
          "location-aware" to use this feature.  See
          :ref:`location_aware` for more information about
          location-awareness.

        xhr

          This value should be either ``True`` or ``False``.  If this
          value is specified and is ``True``, the :term:`request`
          must possess an ``HTTP_X_REQUESTED_WITH`` (aka
          ``X-Requested-With``) header that has the value
          ``XMLHttpRequest`` for this view to be found and called.
          This is useful for detecting AJAX requests issued from
          jQuery, Prototype and other Javascript libraries.

        header

          This value represents an HTTP header name or a header
          name/value pair.  If the value contains a ``:`` (colon), it
          will be considered a name/value pair
          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The
          value portion should be a regular expression.  If the value
          does not contain a colon, the entire value will be
          considered to be the header name
          (e.g. ``If-Modified-Since``).  If the value evaluates to a
          header name only without a value, the header specified by
          the name must be present in the request for this predicate
          to be true.  If the value evaluates to a header name/value
          pair, the header specified by the name must be present in
          the request *and* the regular expression specified as the
          value must match the header value.  Whether or not the value
          represents a header name or a header name/value pair, the
          case of the header name is not significant.

        path_info

          This value represents a regular expression pattern that will
          be tested against the ``PATH_INFO`` WSGI environment
          variable.  If the regex matches, this predicate will be
          ``True``.

        check_csrf

          .. deprecated:: 1.7
             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`
             instead to have :class:`pyramid.exceptions.BadCSRFToken`
             exceptions raised.

          If specified, this value should be one of ``None``, ``True``,
          ``False``, or a string representing the 'check name'.  If the value
          is ``True`` or a string, CSRF checking will be performed.  If the
          value is ``False`` or ``None``, CSRF checking will not be performed.

          If the value provided is a string, that string will be used as the
          'check name'.  If the value provided is ``True``, ``csrf_token`` will
          be used as the check name.

          If CSRF checking is performed, the checked value will be the value
          of ``request.params[check_name]``.  This value will be compared
          against the value of ``request.session.get_csrf_token()``, and the
          check will pass if these two values are the same.  If the check
          passes, the associated view will be permitted to execute.  If the
          check fails, the associated view will not be permitted to execute.

          Note that using this feature requires a :term:`session factory` to
          have been configured.

          .. versionadded:: 1.4a2

        physical_path

          If specified, this value should be a string or a tuple representing
          the :term:`physical path` of the context found via traversal for this
          predicate to match as true.  For example: ``physical_path='/'`` or
          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.
          This is not a path prefix match or a regex, it's a whole-path match.
          It's useful when you want to always potentially show a view when some
          object is traversed to, but you can't be sure about what kind of
          object it will be, so you can't use the ``context`` predicate.  The
          individual path elements inbetween slash characters or in tuple
          elements should be the Unicode representation of the name of the
          resource and should not be encoded in any way.

          .. versionadded:: 1.4a3

        effective_principals

          If specified, this value should be a :term:`principal` identifier or
          a sequence of principal identifiers.  If the
          :attr:`pyramid.request.Request.effective_principals` property
          indicates that every principal named in the argument list is present
          in the current request, this predicate will return True; otherwise it
          will return False.  For example:
          ``effective_principals=pyramid.security.Authenticated`` or
          ``effective_principals=('fred', 'group:admins')``.

          .. versionadded:: 1.4a4

        custom_predicates

            .. deprecated:: 1.5
                This value should be a sequence of references to custom
                predicate callables.  Use custom predicates when no set of
                predefined predicates do what you need.  Custom predicates
                can be combined with predefined predicates as necessary.
                Each custom predicate callable should accept two arguments:
                ``context`` and ``request`` and should return either
                ``True`` or ``False`` after doing arbitrary evaluation of
                the context and/or the request.  The ``predicates`` argument
                to this method and the ability to register third-party view
                predicates via
                :meth:`pyramid.config.Configurator.add_view_predicate`
                obsoletes this argument, but it is kept around for backwards
                compatibility.

        view_options:

          Pass a key/value pair here to use a third-party predicate or set a
          value for a view deriver. See
          :meth:`pyramid.config.Configurator.add_view_predicate` and
          :meth:`pyramid.config.Configurator.add_view_deriver`. See
          :ref:`view_and_route_predicates` for more information about
          third-party predicates and :ref:`view_derivers` for information
          about view derivers.

          .. versionadded: 1.4a1

          .. versionchanged: 1.7

             Support setting view deriver options. Previously, only custom
             view predicate values could be supplied.

        """
        if custom_predicates:
            warnings.warn(
                ('The "custom_predicates" argument to Configurator.add_view '
                 'is deprecated as of Pyramid 1.5.  Use '
                 '"config.add_view_predicate" and use the registered '
                 'view predicate as a predicate argument to add_view instead. '
                 'See "Adding A Third Party View, Route, or Subscriber '
                 'Predicate" in the "Hooks" chapter of the documentation '
                 'for more information.'),
                DeprecationWarning,
                stacklevel=4,
                )

        if check_csrf is not None:
            warnings.warn(
                ('The "check_csrf" argument to Configurator.add_view is '
                 'deprecated as of Pyramid 1.7. Use the "require_csrf" option '
                 'instead or see "Checking CSRF Tokens Automatically" in the '
                 '"Sessions" chapter of the documentation for more '
                 'information.'),
                DeprecationWarning,
                stacklevel=4,
                )

        view = self.maybe_dotted(view)
        context = self.maybe_dotted(context)
        for_ = self.maybe_dotted(for_)
        containment = self.maybe_dotted(containment)
        mapper = self.maybe_dotted(mapper)

        def combine(*decorators):
            def decorated(view_callable):
                # reversed() allows a more natural ordering in the api
                for decorator in reversed(decorators):
                    view_callable = decorator(view_callable)
                return view_callable
            return decorated

        if is_nonstr_iter(decorator):
            decorator = combine(*map(self.maybe_dotted, decorator))
        else:
            decorator = self.maybe_dotted(decorator)

        if not view:
            if renderer:
                def view(context, request):
                    return {}
            else:
                raise ConfigurationError('"view" was not specified and '
                                         'no "renderer" specified')

        if request_type is not None:
            request_type = self.maybe_dotted(request_type)
            if not IInterface.providedBy(request_type):
                raise ConfigurationError(
                    'request_type must be an interface, not %s' % request_type)

        if context is None:
            context = for_

        r_context = context
        if r_context is None:
            r_context = Interface
        if not IInterface.providedBy(r_context):
            r_context = implementedBy(r_context)

        if isinstance(renderer, string_types):
            renderer = renderers.RendererHelper(
                name=renderer, package=self.package,
                registry=self.registry)

        if accept is not None:
            accept = accept.lower()

        introspectables = []
        ovals = view_options.copy()
        ovals.update(dict(
            xhr=xhr,
            request_method=request_method,
            path_info=path_info,
            request_param=request_param,
            header=header,
            accept=accept,
            containment=containment,
            request_type=request_type,
            match_param=match_param,
            check_csrf=check_csrf,
            custom=predvalseq(custom_predicates),
        ))

        def discrim_func():
            # We need to defer the discriminator until we know what the phash
            # is.  It can't be computed any sooner because thirdparty
            # predicates/view derivers may not yet exist when add_view is
            # called.
            valid_predicates = predlist.names()
            pvals = {}
            dvals = {}

            for (k, v) in ovals.items():
                if k in valid_predicates:
                    pvals[k] = v
                else:
                    dvals[k] = v

            self._check_view_options(**dvals)

            order, preds, phash = predlist.make(self, **pvals)

            view_intr.update({
                'phash': phash,
                'order': order,
                'predicates': preds,
                })
            return ('view', context, name, route_name, phash)

        discriminator = Deferred(discrim_func)

        if inspect.isclass(view) and attr:
            view_desc = 'method %r of %s' % (
                attr, self.object_description(view))
        else:
            view_desc = self.object_description(view)

        tmpl_intr = None

        view_intr = self.introspectable('views',
                                        discriminator,
                                        view_desc,
                                        'view')
        view_intr.update(dict(
            name=name,
            context=context,
            containment=containment,
            request_param=request_param,
            request_methods=request_method,
            route_name=route_name,
            attr=attr,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            match_param=match_param,
            check_csrf=check_csrf,
            http_cache=http_cache,
            require_csrf=require_csrf,
            callable=view,
            mapper=mapper,
            decorator=decorator,
        ))
        view_intr.update(view_options)
        introspectables.append(view_intr)
        predlist = self.get_predlist('view')

        def register(permission=permission, renderer=renderer):
            request_iface = IRequest
            if route_name is not None:
                request_iface = self.registry.queryUtility(IRouteRequest,
                                                           name=route_name)
                if request_iface is None:
                    # route configuration should have already happened in
                    # phase 2
                    raise ConfigurationError(
                        'No route named %s found for view registration' %
                        route_name)

            if renderer is None:
                # use default renderer if one exists (reg'd in phase 1)
                if self.registry.queryUtility(IRendererFactory) is not None:
                    renderer = renderers.RendererHelper(
                        name=None,
                        package=self.package,
                        registry=self.registry
                        )

            # added by discrim_func above during conflict resolving
            preds = view_intr['predicates']
            order = view_intr['order']
            phash = view_intr['phash']

            # __no_permission_required__ handled by _secure_view
            derived_view = self._derive_view(
                view,
                permission=permission,
                predicates=preds,
                attr=attr,
                context=context,
                renderer=renderer,
                wrapper_viewname=wrapper,
                viewname=name,
                accept=accept,
                order=order,
                phash=phash,
                decorator=decorator,
                mapper=mapper,
                http_cache=http_cache,
                require_csrf=require_csrf,
                extra_options=ovals,
            )
            derived_view.__discriminator__ = lambda *arg: discriminator
            # __discriminator__ is used by superdynamic systems
            # that require it for introspection after manual view lookup;
            # see also MultiView.__discriminator__
            view_intr['derived_callable'] = derived_view

            registered = self.registry.adapters.registered

            # A multiviews is a set of views which are registered for
            # exactly the same context type/request type/name triad.  Each
            # consituent view in a multiview differs only by the
            # predicates which it possesses.

            # To find a previously registered view for a context
            # type/request type/name triad, we need to use the
            # ``registered`` method of the adapter registry rather than
            # ``lookup``.  ``registered`` ignores interface inheritance
            # for the required and provided arguments, returning only a
            # view registered previously with the *exact* triad we pass
            # in.

            # We need to do this three times, because we use three
            # different interfaces as the ``provided`` interface while
            # doing registrations, and ``registered`` performs exact
            # matches on all the arguments it receives.

            old_view = None

            for view_type in (IView, ISecuredView, IMultiView):
                old_view = registered((IViewClassifier, request_iface,
                                       r_context), view_type, name)
                if old_view is not None:
                    break

            isexc = isexception(context)

            def regclosure():
                if hasattr(derived_view, '__call_permissive__'):
                    view_iface = ISecuredView
                else:
                    view_iface = IView
                self.registry.registerAdapter(
                    derived_view,
                    (IViewClassifier, request_iface, context), view_iface, name
                    )
                if isexc:
                    self.registry.registerAdapter(
                        derived_view,
                        (IExceptionViewClassifier, request_iface, context),
                        view_iface, name)

            is_multiview = IMultiView.providedBy(old_view)
            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)

            if old_view is None:
                # - No component was yet registered for any of our I*View
                #   interfaces exactly; this is the first view for this
                #   triad.
                regclosure()

            elif (not is_multiview) and (old_phash == phash):
                # - A single view component was previously registered with
                #   the same predicate hash as this view; this registration
                #   is therefore an override.
                regclosure()

            else:
                # - A view or multiview was already registered for this
                #   triad, and the new view is not an override.

                # XXX we could try to be more efficient here and register
                # a non-secured view for a multiview if none of the
                # multiview's consituent views have a permission
                # associated with them, but this code is getting pretty
                # rough already
                if is_multiview:
                    multiview = old_view
                else:
                    multiview = MultiView(name)
                    old_accept = getattr(old_view, '__accept__', None)
                    old_order = getattr(old_view, '__order__', MAX_ORDER)
                    multiview.add(old_view, old_order, old_accept, old_phash)
                multiview.add(derived_view, order, accept, phash)
                for view_type in (IView, ISecuredView):
                    # unregister any existing views
                    self.registry.adapters.unregister(
                        (IViewClassifier, request_iface, r_context),
                        view_type, name=name)
                    if isexc:
                        self.registry.adapters.unregister(
                            (IExceptionViewClassifier, request_iface,
                             r_context), view_type, name=name)
                self.registry.registerAdapter(
                    multiview,
                    (IViewClassifier, request_iface, context),
                    IMultiView, name=name)
                if isexc:
                    self.registry.registerAdapter(
                        multiview,
                        (IExceptionViewClassifier, request_iface, context),
                        IMultiView, name=name)

            self.registry._clear_view_lookup_cache()
            renderer_type = getattr(renderer, 'type', None) # gard against None
            intrspc = self.introspector
            if (
                renderer_type is not None and
                tmpl_intr is not None and
                intrspc is not None and
                intrspc.get('renderer factories', renderer_type) is not None
                ):
                # allow failure of registered template factories to be deferred
                # until view execution, like other bad renderer factories; if
                # we tried to relate this to an existing renderer factory
                # without checking if it the factory actually existed, we'd end
                # up with a KeyError at startup time, which is inconsistent
                # with how other bad renderer registrations behave (they throw
                # a ValueError at view execution time)
                tmpl_intr.relate('renderer factories', renderer.type)

        if mapper:
            mapper_intr = self.introspectable(
                'view mappers',
                discriminator,
                'view mapper for %s' % view_desc,
                'view mapper'
                )
            mapper_intr['mapper'] = mapper
            mapper_intr.relate('views', discriminator)
            introspectables.append(mapper_intr)
        if route_name:
            view_intr.relate('routes', route_name) # see add_route
        if renderer is not None and renderer.name and '.' in renderer.name:
            # the renderer is a template
            tmpl_intr = self.introspectable(
                'templates',
                discriminator,
                renderer.name,
                'template'
                )
            tmpl_intr.relate('views', discriminator)
            tmpl_intr['name'] = renderer.name
            tmpl_intr['type'] = renderer.type
            tmpl_intr['renderer'] = renderer
            introspectables.append(tmpl_intr)
        if permission is not None:
            # if a permission exists, register a permission introspectable
            perm_intr = self.introspectable(
                'permissions',
                permission,
                permission,
                'permission'
                )
            perm_intr['value'] = permission
            perm_intr.relate('views', discriminator)
            introspectables.append(perm_intr)
        self.action(discriminator, register, introspectables=introspectables)

    def _check_view_options(self, **kw):
        # we only need to validate deriver options because the predicates
        # were checked by the predlist
        derivers = self.registry.getUtility(IViewDerivers)
        for deriver in derivers.values():
            for opt in getattr(deriver, 'options', []):
                kw.pop(opt, None)
        if kw:
            raise ConfigurationError('Unknown view options: %s' % (kw,))

    def _apply_view_derivers(self, info):
        d = pyramid.viewderivers

        # These derivers are not really derivers and so have fixed order
        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),
                          ('predicated_view', d.predicated_view)]

        view = info.original_view
        derivers = self.registry.getUtility(IViewDerivers)
        for name, deriver in reversed(outer_derivers + derivers.sorted()):
            view = wraps_view(deriver)(view, info)
        return view

    @action_method
    def add_view_predicate(self, name, factory, weighs_more_than=None,
                           weighs_less_than=None):
        """
        .. versionadded:: 1.4

        Adds a view predicate factory.  The associated view predicate can
        later be named as a keyword argument to
        :meth:`pyramid.config.Configurator.add_view` in the
        ``predicates`` anonyous keyword argument dictionary.

        ``name`` should be the name of the predicate.  It must be a valid
        Python identifier (it will be used as a keyword argument to
        ``add_view`` by others).

        ``factory`` should be a :term:`predicate factory` or :term:`dotted
        Python name` which refers to a predicate factory.

        See :ref:`view_and_route_predicates` for more information.
        """
        self._add_predicate(
            'view',
            name,
            factory,
            weighs_more_than=weighs_more_than,
            weighs_less_than=weighs_less_than
            )

    def add_default_view_predicates(self):
        p = pyramid.config.predicates
        for (name, factory) in (
            ('xhr', p.XHRPredicate),
            ('request_method', p.RequestMethodPredicate),
            ('path_info', p.PathInfoPredicate),
            ('request_param', p.RequestParamPredicate),
            ('header', p.HeaderPredicate),
            ('accept', p.AcceptPredicate),
            ('containment', p.ContainmentPredicate),
            ('request_type', p.RequestTypePredicate),
            ('match_param', p.MatchParamPredicate),
            ('check_csrf', p.CheckCSRFTokenPredicate),
            ('physical_path', p.PhysicalPathPredicate),
            ('effective_principals', p.EffectivePrincipalsPredicate),
            ('custom', p.CustomPredicate),
            ):
            self.add_view_predicate(name, factory)

    @action_method
    def add_view_deriver(self, deriver, name=None, under=None, over=None):
        """
        .. versionadded:: 1.7

        Add a :term:`view deriver` to the view pipeline. View derivers are
        a feature used by extension authors to wrap views in custom code
        controllable by view-specific options.

        ``deriver`` should be a callable conforming to the
        :class:`pyramid.interfaces.IViewDeriver` interface.

        ``name`` should be the name of the view deriver.  There are no
        restrictions on the name of a view deriver. If left unspecified, the
        name will be constructed from the name of the ``deriver``.

        The ``under`` and ``over`` options can be used to control the ordering
        of view derivers by providing hints about where in the view pipeline
        the deriver is used. Each option may be a string or a list of strings.
        At least one view deriver in each, the over and under directions, must
        exist to fully satisfy the constraints.

        ``under`` means closer to the user-defined :term:`view callable`,
        and ``over`` means closer to view pipeline ingress.

        The default value for ``over`` is ``rendered_view`` and ``under`` is
        ``decorated_view``. This places the deriver somewhere between the two
        in the view pipeline. If the deriver should be placed elsewhere in the
        pipeline, such as above ``decorated_view``, then you MUST also specify
        ``under`` to something earlier in the order, or a
        ``CyclicDependencyError`` will be raised when trying to sort the
        derivers.

        See :ref:`view_derivers` for more information.

        """
        deriver = self.maybe_dotted(deriver)

        if name is None:
            name = deriver.__name__

        if name in (INGRESS, VIEW):
            raise ConfigurationError('%s is a reserved view deriver name'
                                     % name)

        if under is None:
            under = 'decorated_view'

        if over is None:
            over = 'rendered_view'

        over = as_sorted_tuple(over)
        under = as_sorted_tuple(under)

        if INGRESS in over:
            raise ConfigurationError('%s cannot be over INGRESS' % name)

        # ensure everything is always over mapped_view
        if VIEW in over and name != 'mapped_view':
            over = as_sorted_tuple(over + ('mapped_view',))

        if VIEW in under:
            raise ConfigurationError('%s cannot be under VIEW' % name)
        if 'mapped_view' in under:
            raise ConfigurationError('%s cannot be under "mapped_view"' % name)

        discriminator = ('view deriver', name)
        intr = self.introspectable(
            'view derivers',
            name,
            name,
            'view deriver')
        intr['name'] = name
        intr['deriver'] = deriver
        intr['under'] = under
        intr['over'] = over
        def register():
            derivers = self.registry.queryUtility(IViewDerivers)
            if derivers is None:
                derivers = TopologicalSorter(
                    default_before=None,
                    default_after=INGRESS,
                    first=INGRESS,
                    last=VIEW,
                )
                self.registry.registerUtility(derivers, IViewDerivers)
            derivers.add(name, deriver, before=over, after=under)
        self.action(discriminator, register, introspectables=(intr,),
                    order=PHASE1_CONFIG) # must be registered before add_view

    def add_default_view_derivers(self):
        d = pyramid.viewderivers
        derivers = [
            ('secured_view', d.secured_view),
            ('owrapped_view', d.owrapped_view),
            ('http_cached_view', d.http_cached_view),
            ('decorated_view', d.decorated_view),
            ('rendered_view', d.rendered_view),
            ('mapped_view', d.mapped_view),
        ]
        last = INGRESS
        for name, deriver in derivers:
            self.add_view_deriver(
                deriver,
                name=name,
                under=last,
                over=VIEW,
            )
            last = name

        # leave the csrf_view loosely coupled to the rest of the pipeline
        # by ensuring nothing in the default pipeline depends on the order
        # of the csrf_view
        self.add_view_deriver(
            d.csrf_view,
            'csrf_view',
            under='secured_view',
            over='owrapped_view',
        )

    def derive_view(self, view, attr=None, renderer=None):
        """
        Create a :term:`view callable` using the function, instance,
        or class (or :term:`dotted Python name` referring to the same)
        provided as ``view`` object.

        .. warning::

           This method is typically only used by :app:`Pyramid` framework
           extension authors, not by :app:`Pyramid` application developers.

        This is API is useful to framework extenders who create
        pluggable systems which need to register 'proxy' view
        callables for functions, instances, or classes which meet the
        requirements of being a :app:`Pyramid` view callable.  For
        example, a ``some_other_framework`` function in another
        framework may want to allow a user to supply a view callable,
        but he may want to wrap the view callable in his own before
        registering the wrapper as a :app:`Pyramid` view callable.
        Because a :app:`Pyramid` view callable can be any of a
        number of valid objects, the framework extender will not know
        how to call the user-supplied object.  Running it through
        ``derive_view`` normalizes it to a callable which accepts two
        arguments: ``context`` and ``request``.

        For example:

        .. code-block:: python

           def some_other_framework(user_supplied_view):
               config = Configurator(reg)
               proxy_view = config.derive_view(user_supplied_view)
               def my_wrapper(context, request):
                   do_something_that_mutates(request)
                   return proxy_view(context, request)
               config.add_view(my_wrapper)

        The ``view`` object provided should be one of the following:

        - A function or another non-class callable object that accepts
          a :term:`request` as a single positional argument and which
          returns a :term:`response` object.

        - A function or other non-class callable object that accepts
          two positional arguments, ``context, request`` and which
          returns a :term:`response` object.

        - A class which accepts a single positional argument in its
          constructor named ``request``, and which has a ``__call__``
          method that accepts no arguments that returns a
          :term:`response` object.

        - A class which accepts two positional arguments named
          ``context, request``, and which has a ``__call__`` method
          that accepts no arguments that returns a :term:`response`
          object.

        - A :term:`dotted Python name` which refers to any of the
          kinds of objects above.

        This API returns a callable which accepts the arguments
        ``context, request`` and which returns the result of calling
        the provided ``view`` object.

        The ``attr`` keyword argument is most useful when the view
        object is a class.  It names the method that should be used as
        the callable.  If ``attr`` is not provided, the attribute
        effectively defaults to ``__call__``.  See
        :ref:`class_as_view` for more information.

        The ``renderer`` keyword argument should be a renderer
        name. If supplied, it will cause the returned callable to use
        a :term:`renderer` to convert the user-supplied view result to
        a :term:`response` object.  If a ``renderer`` argument is not
        supplied, the user-supplied view must itself return a
        :term:`response` object.  """
        return self._derive_view(view, attr=attr, renderer=renderer)

    # b/w compat
    def _derive_view(self, view, permission=None, predicates=(),
                     attr=None, renderer=None, wrapper_viewname=None,
                     viewname=None, accept=None, order=MAX_ORDER,
                     phash=DEFAULT_PHASH, decorator=None,
                     mapper=None, http_cache=None, context=None,
                     require_csrf=None, extra_options=None):
        view = self.maybe_dotted(view)
        mapper = self.maybe_dotted(mapper)
        if isinstance(renderer, string_types):
            renderer = renderers.RendererHelper(
                name=renderer, package=self.package,
                registry=self.registry)
        if renderer is None:
            # use default renderer if one exists
            if self.registry.queryUtility(IRendererFactory) is not None:
                renderer = renderers.RendererHelper(
                    name=None,
                    package=self.package,
                    registry=self.registry)

        options = dict(
            view=view,
            context=context,
            permission=permission,
            attr=attr,
            renderer=renderer,
            wrapper=wrapper_viewname,
            name=viewname,
            accept=accept,
            mapper=mapper,
            decorator=decorator,
            http_cache=http_cache,
            require_csrf=require_csrf,
        )
        if extra_options:
            options.update(extra_options)

        info = ViewDeriverInfo(
            view=view,
            registry=self.registry,
            package=self.package,
            predicates=predicates,
            options=options,
        )

        # order and phash are only necessary for the predicated view and
        # are not really view deriver options
        info.order = order
        info.phash = phash

        return self._apply_view_derivers(info)

    @viewdefaults
    @action_method
    def add_forbidden_view(
        self,
        view=None,
        attr=None,
        renderer=None,
        wrapper=None,
        route_name=None,
        request_type=None,
        request_method=None,
        request_param=None,
        containment=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        decorator=None,
        mapper=None,
        match_param=None,
        **view_options
        ):
        """ Add a forbidden view to the current configuration state.  The
        view will be called when Pyramid or application code raises a
        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of
        circumstances implied by the predicates provided are matched.  The
        simplest example is:

          .. code-block:: python

            def forbidden(request):
                return Response('Forbidden', status='403 Forbidden')

            config.add_forbidden_view(forbidden)

        If ``view`` argument is not provided, the view callable defaults to
        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.

        All arguments have the same meaning as
        :meth:`pyramid.config.Configurator.add_view` and each predicate
        argument restricts the set of circumstances under which this forbidden
        view will be invoked.  Unlike
        :meth:`pyramid.config.Configurator.add_view`, this method will raise
        an exception if passed ``name``, ``permission``, ``context``,
        ``for_``, or ``http_cache`` keyword arguments.  These argument values
        make no sense in the context of a forbidden view.

        .. versionadded:: 1.3
        """
        for arg in (
            'name', 'permission', 'context', 'for_', 'http_cache',
            'require_csrf',
        ):
            if arg in view_options:
                raise ConfigurationError(
                    '%s may not be used as an argument to add_forbidden_view'
                    % arg
                    )

        if view is None:
            view = default_exceptionresponse_view

        settings = dict(
            view=view,
            context=HTTPForbidden,
            wrapper=wrapper,
            request_type=request_type,
            request_method=request_method,
            request_param=request_param,
            containment=containment,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            custom_predicates=custom_predicates,
            decorator=decorator,
            mapper=mapper,
            match_param=match_param,
            route_name=route_name,
            permission=NO_PERMISSION_REQUIRED,
            require_csrf=False,
            attr=attr,
            renderer=renderer,
            )
        settings.update(view_options)
        return self.add_view(**settings)

    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias

    @viewdefaults
    @action_method
    def add_notfound_view(
        self,
        view=None,
        attr=None,
        renderer=None,
        wrapper=None,
        route_name=None,
        request_type=None,
        request_method=None,
        request_param=None,
        containment=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        decorator=None,
        mapper=None,
        match_param=None,
        append_slash=False,
        **view_options
        ):
        """ Add a default Not Found View to the current configuration state.
        The view will be called when Pyramid or application code raises an
        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a
        view cannot be found for the request).  The simplest example is:

          .. code-block:: python

            def notfound(request):
                return Response('Not Found', status='404 Not Found')

            config.add_notfound_view(notfound)

        If ``view`` argument is not provided, the view callable defaults to
        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.

        All arguments except ``append_slash`` have the same meaning as
        :meth:`pyramid.config.Configurator.add_view` and each predicate
        argument restricts the set of circumstances under which this notfound
        view will be invoked.  Unlike
        :meth:`pyramid.config.Configurator.add_view`, this method will raise
        an exception if passed ``name``, ``permission``, ``context``,
        ``for_``, or ``http_cache`` keyword arguments.  These argument values
        make no sense in the context of a Not Found View.

        If ``append_slash`` is ``True``, when this Not Found View is invoked,
        and the current path info does not end in a slash, the notfound logic
        will attempt to find a :term:`route` that matches the request's path
        info suffixed with a slash.  If such a route exists, Pyramid will
        issue a redirect to the URL implied by the route; if it does not,
        Pyramid will return the result of the view callable provided as
        ``view``, as normal.

        If the argument provided as ``append_slash`` is not a boolean but
        instead implements :class:`~pyramid.interfaces.IResponse`, the
        append_slash logic will behave as if ``append_slash=True`` was passed,
        but the provided class will be used as the response class instead of
        the default :class:`~pyramid.httpexceptions.HTTPFound` response class
        when a redirect is performed.  For example:

          .. code-block:: python

            from pyramid.httpexceptions import HTTPMovedPermanently
            config.add_notfound_view(append_slash=HTTPMovedPermanently)

        The above means that a redirect to a slash-appended route will be
        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`
        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will
        be used` for the redirect response if a slash-appended route is found.

        .. versionchanged:: 1.6
        .. versionadded:: 1.3
        """
        for arg in (
            'name', 'permission', 'context', 'for_', 'http_cache',
            'require_csrf',
        ):
            if arg in view_options:
                raise ConfigurationError(
                    '%s may not be used as an argument to add_notfound_view'
                    % arg
                    )

        if view is None:
            view = default_exceptionresponse_view

        settings = dict(
            view=view,
            context=HTTPNotFound,
            wrapper=wrapper,
            request_type=request_type,
            request_method=request_method,
            request_param=request_param,
            containment=containment,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            custom_predicates=custom_predicates,
            decorator=decorator,
            mapper=mapper,
            match_param=match_param,
            route_name=route_name,
            permission=NO_PERMISSION_REQUIRED,
            require_csrf=False,
            )
        settings.update(view_options)
        if append_slash:
            view = self._derive_view(view, attr=attr, renderer=renderer)
            if IResponse.implementedBy(append_slash):
                view = AppendSlashNotFoundViewFactory(
                    view, redirect_class=append_slash,
                )
            else:
                view = AppendSlashNotFoundViewFactory(view)
            settings['view'] = view
        else:
            settings['attr'] = attr
            settings['renderer'] = renderer
        return self.add_view(**settings)

    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias

    @action_method
    def set_view_mapper(self, mapper):
        """
        Setting a :term:`view mapper` makes it possible to make use of
        :term:`view callable` objects which implement different call
        signatures than the ones supported by :app:`Pyramid` as described in
        its narrative documentation.

        The ``mapper`` argument should be an object implementing
        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted
        Python name` to such an object.  The provided ``mapper`` will become
        the default view mapper to be used by all subsequent :term:`view
        configuration` registrations.

        .. seealso::

            See also :ref:`using_a_view_mapper`.

        .. note::

           Using the ``default_view_mapper`` argument to the
           :class:`pyramid.config.Configurator` constructor
           can be used to achieve the same purpose.
        """
        mapper = self.maybe_dotted(mapper)
        def register():
            self.registry.registerUtility(mapper, IViewMapperFactory)
        # IViewMapperFactory is looked up as the result of view config
        # in phase 3
        intr = self.introspectable('view mappers',
                                   IViewMapperFactory,
                                   self.object_description(mapper),
                                   'default view mapper')
        intr['mapper'] = mapper
        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,
                    introspectables=(intr,))

    @action_method
    def add_static_view(self, name, path, **kw):
        """ Add a view used to render static assets such as images
        and CSS files.

        The ``name`` argument is a string representing an
        application-relative local URL prefix.  It may alternately be a full
        URL.

        The ``path`` argument is the path on disk where the static files
        reside.  This can be an absolute path, a package-relative path, or a
        :term:`asset specification`.

        The ``cache_max_age`` keyword argument is input to set the
        ``Expires`` and ``Cache-Control`` headers for static assets served.
        Note that this argument has no effect when the ``name`` is a *url
        prefix*.  By default, this argument is ``None``, meaning that no
        particular Expires or Cache-Control headers are set in the response.

        The ``permission`` keyword argument is used to specify the
        :term:`permission` required by a user to execute the static view.  By
        default, it is the string
        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel
        which indicates that, even if a :term:`default permission` exists for
        the current application, the static view should be renderered to
        completely anonymous users.  This default value is permissive
        because, in most web apps, static assets seldom need protection from
        viewing.  If ``permission`` is specified, the security checking will
        be performed against the default root factory ACL.

        Any other keyword arguments sent to ``add_static_view`` are passed on
        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,
        perhaps to define a custom factory with a custom ACL for this static
        view).

        *Usage*

        The ``add_static_view`` function is typically used in conjunction
        with the :meth:`pyramid.request.Request.static_url` method.
        ``add_static_view`` adds a view which renders a static asset when
        some URL is visited; :meth:`pyramid.request.Request.static_url`
        generates a URL to that asset.

        The ``name`` argument to ``add_static_view`` is usually a simple URL
        prefix (e.g. ``'images'``).  When this is the case, the
        :meth:`pyramid.request.Request.static_url` API will generate a URL
        which points to a Pyramid view, which will serve up a set of assets
        that live in the package itself. For example:

        .. code-block:: python

           add_static_view('images', 'mypackage:images/')

        Code that registers such a view can generate URLs to the view via
        :meth:`pyramid.request.Request.static_url`:

        .. code-block:: python

           request.static_url('mypackage:images/logo.png')

        When ``add_static_view`` is called with a ``name`` argument that
        represents a URL prefix, as it is above, subsequent calls to
        :meth:`pyramid.request.Request.static_url` with paths that start with
        the ``path`` argument passed to ``add_static_view`` will generate a
        URL something like ``http://<Pyramid app URL>/images/logo.png``,
        which will cause the ``logo.png`` file in the ``images`` subdirectory
        of the ``mypackage`` package to be served.

        ``add_static_view`` can alternately be used with a ``name`` argument
        which is a *URL*, causing static assets to be served from an external
        webserver.  This happens when the ``name`` argument is a fully
        qualified URL (e.g. starts with ``http://`` or similar).  In this
        mode, the ``name`` is used as the prefix of the full URL when
        generating a URL using :meth:`pyramid.request.Request.static_url`.
        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)
        is used as the ``name`` argument, the generated URL will use the
        protocol of the request (http or https, respectively).

        For example, if ``add_static_view`` is called like so:

        .. code-block:: python

           add_static_view('http://example.com/images', 'mypackage:images/')

        Subsequently, the URLs generated by
        :meth:`pyramid.request.Request.static_url` for that static view will
        be prefixed with ``http://example.com/images`` (the external webserver
        listening on ``example.com`` must be itself configured to respond
        properly to such a request.):

        .. code-block:: python

           static_url('mypackage:images/logo.png', request)

        See :ref:`static_assets_section` for more information.
        """
        spec = self._make_spec(path)
        info = self._get_static_info()
        info.add(self, name, spec, **kw)

    def add_cache_buster(self, path, cachebust, explicit=False):
        """
        Add a cache buster to a set of files on disk.

        The ``path`` should be the path on disk where the static files
        reside.  This can be an absolute path, a package-relative path, or a
        :term:`asset specification`.

        The ``cachebust`` argument may be set to cause
        :meth:`~pyramid.request.Request.static_url` to use cache busting when
        generating URLs. See :ref:`cache_busting` for general information
        about cache busting. The value of the ``cachebust`` argument must
        be an object which implements
        :class:`~pyramid.interfaces.ICacheBuster`.

        If ``explicit`` is set to ``True`` then the ``path`` for the cache
        buster will be matched based on the ``rawspec`` instead of the
        ``pathspec`` as defined in the
        :class:`~pyramid.interfaces.ICacheBuster` interface.
        Default: ``False``.

        """
        spec = self._make_spec(path)
        info = self._get_static_info()
        info.add_cache_buster(self, spec, cachebust, explicit=explicit)

    def _get_static_info(self):
        info = self.registry.queryUtility(IStaticURLInfo)
        if info is None:
            info = StaticURLInfo()
            self.registry.registerUtility(info, IStaticURLInfo)
        return info

def isexception(o):
    if IInterface.providedBy(o):
        if IException.isEqualOrExtendedBy(o):
            return True
    return (
        isinstance(o, Exception) or
        (inspect.isclass(o) and (issubclass(o, Exception)))
        )

@implementer(IViewDeriverInfo)
class ViewDeriverInfo(object):
    def __init__(self, view, registry, package, predicates, options):
        self.original_view = view
        self.registry = registry
        self.package = package
        self.predicates = predicates or []
        self.options = options or {}

    @reify
    def settings(self):
        return self.registry.settings

@implementer(IStaticURLInfo)
class StaticURLInfo(object):
    def __init__(self):
        self.registrations = []
        self.cache_busters = []

    def generate(self, path, request, **kw):
        for (url, spec, route_name) in self.registrations:
            if path.startswith(spec):
                subpath = path[len(spec):]
                if WIN: # pragma: no cover
                    subpath = subpath.replace('\\', '/') # windows
                if self.cache_busters:
                    subpath, kw = self._bust_asset_path(
                        request, spec, subpath, kw)
                if url is None:
                    kw['subpath'] = subpath
                    return request.route_url(route_name, **kw)
                else:
                    app_url, scheme, host, port, qs, anchor = \
                        parse_url_overrides(kw)
                    parsed = url_parse(url)
                    if not parsed.scheme:
                        url = urlparse.urlunparse(parsed._replace(
                            scheme=request.environ['wsgi.url_scheme']))
                    subpath = url_quote(subpath)
                    result = urljoin(url, subpath)
                    return result + qs + anchor

        raise ValueError('No static URL definition matching %s' % path)

    def add(self, config, name, spec, **extra):
        # This feature only allows for the serving of a directory and
        # the files contained within, not of a single asset;
        # appending a slash here if the spec doesn't have one is
        # required for proper prefix matching done in ``generate``
        # (``subpath = path[len(spec):]``).
        if os.path.isabs(spec): # FBO windows
            sep = os.sep
        else:
            sep = '/'
        if not spec.endswith(sep) and not spec.endswith(':'):
            spec = spec + sep

        # we also make sure the name ends with a slash, purely as a
        # convenience: a name that is a url is required to end in a
        # slash, so that ``urljoin(name, subpath))`` will work above
        # when the name is a URL, and it doesn't hurt things for it to
        # have a name that ends in a slash if it's used as a route
        # name instead of a URL.
        if not name.endswith('/'):
            # make sure it ends with a slash
            name = name + '/'

        if url_parse(name).netloc:
            # it's a URL
            # url, spec, route_name
            url = name
            route_name = None
        else:
            # it's a view name
            url = None
            cache_max_age = extra.pop('cache_max_age', None)

            # create a view
            view = static_view(spec, cache_max_age=cache_max_age,
                               use_subpath=True)

            # Mutate extra to allow factory, etc to be passed through here.
            # Treat permission specially because we'd like to default to
            # permissiveness (see docs of config.add_static_view).
            permission = extra.pop('permission', None)
            if permission is None:
                permission = NO_PERMISSION_REQUIRED

            context = extra.pop('context', None)
            if context is None:
                context = extra.pop('for_', None)

            renderer = extra.pop('renderer', None)

            # register a route using the computed view, permission, and
            # pattern, plus any extras passed to us via add_static_view
            pattern = "%s*subpath" % name # name already ends with slash
            if config.route_prefix:
                route_name = '__%s/%s' % (config.route_prefix, name)
            else:
                route_name = '__%s' % name
            config.add_route(route_name, pattern, **extra)
            config.add_view(
                route_name=route_name,
                view=view,
                permission=permission,
                context=context,
                renderer=renderer,
            )

        def register():
            registrations = self.registrations

            names = [t[0] for t in registrations]

            if name in names:
                idx = names.index(name)
                registrations.pop(idx)

            # url, spec, route_name
            registrations.append((url, spec, route_name))

        intr = config.introspectable('static views',
                                     name,
                                     'static view for %r' % name,
                                     'static view')
        intr['name'] = name
        intr['spec'] = spec

        config.action(None, callable=register, introspectables=(intr,))

    def add_cache_buster(self, config, spec, cachebust, explicit=False):
        # ensure the spec always has a trailing slash as we only support
        # adding cache busters to folders, not files
        if os.path.isabs(spec): # FBO windows
            sep = os.sep
        else:
            sep = '/'
        if not spec.endswith(sep) and not spec.endswith(':'):
            spec = spec + sep

        def register():
            if config.registry.settings.get('pyramid.prevent_cachebust'):
                return

            cache_busters = self.cache_busters

            # find duplicate cache buster (old_idx)
            # and insertion location (new_idx)
            new_idx, old_idx = len(cache_busters), None
            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):
                # if we find an identical (spec, explicit) then use it
                if spec == spec_ and explicit == explicit_:
                    old_idx = new_idx = idx
                    break

                # past all explicit==False specs then add to the end
                elif not explicit and explicit_:
                    new_idx = idx
                    break

                # explicit matches and spec is shorter
                elif explicit == explicit_ and len(spec) < len(spec_):
                    new_idx = idx
                    break

            if old_idx is not None:
                cache_busters.pop(old_idx)

            cache_busters.insert(new_idx, (spec, cachebust, explicit))

        intr = config.introspectable('cache busters',
                                     spec,
                                     'cache buster for %r' % spec,
                                     'cache buster')
        intr['cachebust'] = cachebust
        intr['path'] = spec
        intr['explicit'] = explicit

        config.action(None, callable=register, introspectables=(intr,))

    def _bust_asset_path(self, request, spec, subpath, kw):
        registry = request.registry
        pkg_name, pkg_subpath = resolve_asset_spec(spec)
        rawspec = None

        if pkg_name is not None:
            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)
            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)
            if overrides is not None:
                resource_name = posixpath.join(pkg_subpath, subpath)
                sources = overrides.filtered_sources(resource_name)
                for source, filtered_path in sources:
                    rawspec = source.get_path(filtered_path)
                    if hasattr(source, 'pkg_name'):
                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)
                    break

        else:
            pathspec = pkg_subpath + subpath

        if rawspec is None:
            rawspec = pathspec

        kw['pathspec'] = pathspec
        kw['rawspec'] = rawspec
        for spec_, cachebust, explicit in reversed(self.cache_busters):
            if (
                (explicit and rawspec.startswith(spec_)) or
                (not explicit and pathspec.startswith(spec_))
            ):
                subpath, kw = cachebust(request, subpath, kw)
                break
        return subpath, kw

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
[ISSUE]
**Title:** Unable to Register Exception-Only Views Using `exception_only` Argument

**Description:**
When attempting to register a view with the `exception_only` parameter set to `True`, a `ConfigurationError` is raised indicating that `exception_only` is an unknown view option. This prevents the registration of views that are intended to handle only exceptions.

**Example Code:**
```python
from pyramid.config import Configurator
from pyramid.exceptions import ConfigurationError

def exception_view(exc, request):
    return {'message': 'An exception occurred'}

config = Configurator()
config.add_view(view=exception_view, context=Exception, exception_only=True)
app = config.make_wsgi_app()
```

**Expected Behavior:**
The view should be successfully registered as an exception-only view, allowing it to handle exceptions without being registered as a regular view.

**Actual Behavior:**
A `ConfigurationError` is raised with the message:
```
Unknown view options: {'exception_only': True}
```
[/ISSUE]
{
    "TestViewsConfigurationMixin.test_add_forbidden_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_allows_other_predicates": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_disallows_context": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_disallows_for_": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_disallows_http_cache": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_disallows_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_disallows_permission": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_no_view_argument": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_with_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_add_forbidden_view_with_view_defaults": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_allows_other_predicates": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_append_slash": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_append_slash_custom_response": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_disallows_context": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_disallows_for_": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_disallows_http_cache": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_disallows_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_disallows_permission": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_no_view_argument": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_with_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_add_notfound_view_with_view_defaults": "PASSED",
    "TestViewsConfigurationMixin.test_add_static_view_absolute": "PASSED",
    "TestViewsConfigurationMixin.test_add_static_view_package_relative": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_instance": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_instance_requestonly": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_instancemethod": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_instancemethod_requestonly": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_oldstyle_class": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_as_oldstyle_class_requestonly": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_class_method_no_attr": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_context_as_class": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_context_as_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_context_as_iface": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_context_trumps_for": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_custom_more_preds_first_bests_fewer_preds_last": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_custom_predicate_bests_standard_predicate": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_default_phash_overrides_default_phash": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_default_phash_overrides_no_phash": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_default_phash_overrides_default_phash": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_default_phash_overrides_no_phash": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_multiview_replaces_existing_securedview": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_multiview_replaces_existing_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_multiview_replaces_multiview": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_mulview_replaces_existing_view_with___accept__": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_same_phash_overrides_existing_single_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exc_with_accept_multiview_replaces_existing_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exception_only": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exception_only_misconfiguration": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exception_only_no_regular_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_exception_register_secured_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_for__as_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_for_as_class": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_for_as_iface": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_mixed_case_replaces_existing_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview___discriminator__": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_call_ordering": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_context_superclass_then_subclass": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_exception_superclass_then_subclass": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_replaces_existing_securedview": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_replaces_existing_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_replaces_existing_view_with___accept__": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_multiview_replaces_multiview": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_register_secured_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_same_phash_overrides_existing_single_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_same_predicates": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_view_callable_None_no_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_view_callable_None_with_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_view_callable_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_accept_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_accept_multiview_replaces_existing_view": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_accept_nomatch": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_check_csrf_predicates_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_containment_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_containment_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_containment_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_csrf_header": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_csrf_param": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_custom_predicates_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_custom_predicates_nomatch": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_decorator": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_decorator_tuple": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_default_permission_no_explicit_permission": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_default_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_function_callable": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_function_callable_requestonly": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_badregex": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_noval_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_noval_nomatch": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_val_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_val_missing": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_header_val_nomatch": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_http_cache": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_mapper": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_missing_csrf_header": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_name_unicode": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_no_default_permission_no_explicit_permission": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_nonexistant_route_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_path_info_badregex": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_path_info_match": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_path_info_nomatch": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_permission": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_get_implies_head": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_sequence_conflict": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_sequence_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_sequence_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_method_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_param_noval_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_param_noval_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_param_val_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_param_val_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_type": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_type_and_route_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_type_as_iface": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_request_type_as_noniface": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_route_name": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_route_name_exception": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_tmpl_renderer_factory_introspector_missing": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_tmpl_renderer_factory_no_renderer_factory": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_tmpl_renderer_factory_with_renderer_factory": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_view_config_and_view_defaults_conflicts": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_view_config_and_view_defaults_doesnt_conflict": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_view_defaults": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_view_defaults_viewname_is_dottedname_kwarg": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_view_defaults_viewname_is_dottedname_nonkwarg": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_xhr_false": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_with_xhr_true": "PASSED",
    "TestViewsConfigurationMixin.test_add_view_wrapped_view_is_decorated": "PASSED",
    "TestViewsConfigurationMixin.test_add_views_with_accept_multiview_replaces_existing": "PASSED",
    "TestViewsConfigurationMixin.test_derive_view_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_derive_view_function": "PASSED",
    "TestViewsConfigurationMixin.test_derive_view_with_default_renderer_no_explicit_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_derive_view_with_default_renderer_with_explicit_renderer": "PASSED",
    "TestViewsConfigurationMixin.test_set_view_mapper": "PASSED",
    "TestViewsConfigurationMixin.test_set_view_mapper_dottedname": "PASSED",
    "TestViewsConfigurationMixin.test_view_with_most_specific_predicate": "PASSED",
    "TestViewsConfigurationMixin.test_view_with_most_specific_predicate_with_mismatch": "PASSED",
    "Test_requestonly.test_defaults": "PASSED",
    "Test_requestonly.test_otherattr": "PASSED",
    "Test_isexception.test_is_IException": "PASSED",
    "Test_isexception.test_is_IException_subinterface": "PASSED",
    "Test_isexception.test_is_exception_class": "PASSED",
    "Test_isexception.test_is_exception_instance": "PASSED",
    "TestMultiView.test___call__": "PASSED",
    "TestMultiView.test___call__intermediate_not_found": "PASSED",
    "TestMultiView.test___call__raise_not_found_isnt_interpreted_as_pred_mismatch": "PASSED",
    "TestMultiView.test___call_permissive_has_call_permissive": "PASSED",
    "TestMultiView.test___call_permissive_has_no_call_permissive": "PASSED",
    "TestMultiView.test__call__not_found": "PASSED",
    "TestMultiView.test__call__with_accept_match": "PASSED",
    "TestMultiView.test__call__with_accept_miss": "PASSED",
    "TestMultiView.test__call_permissive__not_found": "PASSED",
    "TestMultiView.test_add": "PASSED",
    "TestMultiView.test_add_with_phash": "PASSED",
    "TestMultiView.test_add_with_phash_override_accept": "PASSED",
    "TestMultiView.test_add_with_phash_override_accept2": "PASSED",
    "TestMultiView.test_class_implements_ISecuredView": "PASSED",
    "TestMultiView.test_get_views": "PASSED",
    "TestMultiView.test_get_views_best_match_returns_None": "PASSED",
    "TestMultiView.test_get_views_no_self_accepts": "PASSED",
    "TestMultiView.test_get_views_request_has_no_accept": "PASSED",
    "TestMultiView.test_instance_implements_ISecuredView": "PASSED",
    "TestMultiView.test_match_not_found": "PASSED",
    "TestMultiView.test_match_predicate_fails": "PASSED",
    "TestMultiView.test_match_predicate_succeeds": "PASSED",
    "TestMultiView.test_multiple_with_functions_as_views": "PASSED",
    "TestMultiView.test_permitted": "PASSED",
    "TestMultiView.test_permitted_no_match_with__permitted__": "PASSED",
    "TestMultiView.test_permitted_no_views": "PASSED",
    "TestDefaultViewMapper.test__view_as_function_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_function_context_and_request": "PASSED",
    "TestDefaultViewMapper.test_view_as_function_requestonly": "PASSED",
    "TestDefaultViewMapper.test_view_as_function_requestonly_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_instance_context_and_request": "PASSED",
    "TestDefaultViewMapper.test_view_as_instance_context_and_request_and_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_instance_requestonly": "PASSED",
    "TestDefaultViewMapper.test_view_as_instance_requestonly_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_newstyle_class_context_and_request": "PASSED",
    "TestDefaultViewMapper.test_view_as_newstyle_class_context_and_request_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_newstyle_class_requestonly": "PASSED",
    "TestDefaultViewMapper.test_view_as_newstyle_class_requestonly_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_oldstyle_class_context_and_request": "PASSED",
    "TestDefaultViewMapper.test_view_as_oldstyle_class_context_and_request_with_attr": "PASSED",
    "TestDefaultViewMapper.test_view_as_oldstyle_class_requestonly": "PASSED",
    "TestDefaultViewMapper.test_view_as_oldstyle_class_requestonly_with_attr": "PASSED",
    "Test_preserve_view_attrs.test_it_different": "PASSED",
    "Test_preserve_view_attrs.test_it_different_with_existing_original_view": "PASSED",
    "Test_preserve_view_attrs.test_it_same": "PASSED",
    "Test_preserve_view_attrs.test_it_view_is_None": "PASSED",
    "TestStaticURLInfo.test_add_already_exists": "PASSED",
    "TestStaticURLInfo.test_add_cachebust_prevented": "PASSED",
    "TestStaticURLInfo.test_add_cachebuster": "PASSED",
    "TestStaticURLInfo.test_add_cachebuster_abspath": "PASSED",
    "TestStaticURLInfo.test_add_cachebuster_for_more_specific_path": "PASSED",
    "TestStaticURLInfo.test_add_cachebuster_overwrite": "PASSED",
    "TestStaticURLInfo.test_add_cachebuster_overwrite_explicit": "PASSED",
    "TestStaticURLInfo.test_add_package_root": "PASSED",
    "TestStaticURLInfo.test_add_url_noendslash": "PASSED",
    "TestStaticURLInfo.test_add_url_noscheme": "PASSED",
    "TestStaticURLInfo.test_add_url_withendslash": "PASSED",
    "TestStaticURLInfo.test_add_viewname": "PASSED",
    "TestStaticURLInfo.test_add_viewname_with_context": "PASSED",
    "TestStaticURLInfo.test_add_viewname_with_for_": "PASSED",
    "TestStaticURLInfo.test_add_viewname_with_permission": "PASSED",
    "TestStaticURLInfo.test_add_viewname_with_renderer": "PASSED",
    "TestStaticURLInfo.test_add_viewname_with_route_prefix": "PASSED",
    "TestStaticURLInfo.test_generate_missing": "PASSED",
    "TestStaticURLInfo.test_generate_quoting": "PASSED",
    "TestStaticURLInfo.test_generate_registration_miss": "PASSED",
    "TestStaticURLInfo.test_generate_route_url": "PASSED",
    "TestStaticURLInfo.test_generate_slash_in_name1": "PASSED",
    "TestStaticURLInfo.test_generate_slash_in_name2": "PASSED",
    "TestStaticURLInfo.test_generate_url_cachebust": "PASSED",
    "TestStaticURLInfo.test_generate_url_cachebust_abspath": "PASSED",
    "TestStaticURLInfo.test_generate_url_cachebust_nomatch": "PASSED",
    "TestStaticURLInfo.test_generate_url_quoted_remote": "PASSED",
    "TestStaticURLInfo.test_generate_url_unquoted_local": "PASSED",
    "TestStaticURLInfo.test_generate_url_with_custom_anchor": "PASSED",
    "TestStaticURLInfo.test_generate_url_with_custom_query": "PASSED",
    "TestStaticURLInfo.test_verifyClass": "PASSED",
    "TestStaticURLInfo.test_verifyObject": "PASSED",
    "Test_view_description.test_with_text": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_object_event_subscriber": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_resource_url_default_resource_iface_means_Interface": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_resource_url_nodefault_resource_iface": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_response_adapter": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_response_adapter_dottednames": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_response_adapter_self": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_defaults": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_dottednames": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_iface_specified": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_predicate": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_with_default_type_predicates_False": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_with_default_type_predicates_True": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_with_specific_type_and_predicates_False": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_subscriber_with_specific_type_and_predicates_True": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_traverser_default_iface_means_Interface": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_traverser_introspectables": "PASSED",
    "AdaptersConfiguratorMixinTests.test_add_traverser_nondefault_iface": "PASSED",
    "Test_eventonly.test_defaults": "PASSED",
    "TestAssetsConfiguratorMixin.test__override_already_registered": "PASSED",
    "TestAssetsConfiguratorMixin.test__override_not_yet_registered": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_directory_with_absdirectory": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_directory_with_absfile": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_directory_with_file": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_absdirectory": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_absfile": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_directory": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_missing_abspath": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_package": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_package_with_absdirectory": "PASSED",
    "TestAssetsConfiguratorMixin.test_override_asset_samename": "PASSED",
    "TestOverrideProvider.test_get_resource_filename_override_returns_value": "PASSED",
    "TestOverrideProvider.test_get_resource_stream_no_overrides": "PASSED",
    "TestOverrideProvider.test_get_resource_stream_override_returns_None": "PASSED",
    "TestOverrideProvider.test_get_resource_stream_override_returns_value": "PASSED",
    "TestOverrideProvider.test_get_resource_string_no_overrides": "PASSED",
    "TestOverrideProvider.test_get_resource_string_override_returns_None": "PASSED",
    "TestOverrideProvider.test_get_resource_string_override_returns_value": "PASSED",
    "TestOverrideProvider.test_has_resource_no_overrides": "PASSED",
    "TestOverrideProvider.test_has_resource_override_returns_None": "PASSED",
    "TestOverrideProvider.test_has_resource_override_returns_True": "PASSED",
    "TestOverrideProvider.test_resource_isdir_no_overrides": "PASSED",
    "TestOverrideProvider.test_resource_isdir_override_returns_False": "PASSED",
    "TestOverrideProvider.test_resource_isdir_override_returns_None": "PASSED",
    "TestOverrideProvider.test_resource_listdir_no_overrides": "PASSED",
    "TestOverrideProvider.test_resource_listdir_override_returns_None": "PASSED",
    "TestOverrideProvider.test_resource_listdir_override_returns_values": "PASSED",
    "TestPackageOverrides.test_class_conforms_to_IPEP302Loader": "PASSED",
    "TestPackageOverrides.test_class_conforms_to_IPackageOverrides": "PASSED",
    "TestPackageOverrides.test_ctor_package_already_has_loader_of_different_type": "PASSED",
    "TestPackageOverrides.test_ctor_package_already_has_loader_of_same_type": "PASSED",
    "TestPackageOverrides.test_ctor_registers_loader_type": "PASSED",
    "TestPackageOverrides.test_ctor_sets_loader": "PASSED",
    "TestPackageOverrides.test_ctor_sets_local_state": "PASSED",
    "TestPackageOverrides.test_filtered_sources": "PASSED",
    "TestPackageOverrides.test_get_code_pkg_has___loader__": "PASSED",
    "TestPackageOverrides.test_get_code_pkg_has_no___loader__": "PASSED",
    "TestPackageOverrides.test_get_data_pkg_has___loader__": "PASSED",
    "TestPackageOverrides.test_get_data_pkg_has_no___loader__": "PASSED",
    "TestPackageOverrides.test_get_filename": "PASSED",
    "TestPackageOverrides.test_get_filename_file_doesnt_exist": "PASSED",
    "TestPackageOverrides.test_get_source_pkg_has___loader__": "PASSED",
    "TestPackageOverrides.test_get_source_pkg_has_no___loader__": "PASSED",
    "TestPackageOverrides.test_get_stream": "PASSED",
    "TestPackageOverrides.test_get_stream_file_doesnt_exist": "PASSED",
    "TestPackageOverrides.test_get_string": "PASSED",
    "TestPackageOverrides.test_get_string_file_doesnt_exist": "PASSED",
    "TestPackageOverrides.test_has_resource": "PASSED",
    "TestPackageOverrides.test_has_resource_file_doesnt_exist": "PASSED",
    "TestPackageOverrides.test_insert_directory": "PASSED",
    "TestPackageOverrides.test_insert_emptystring": "PASSED",
    "TestPackageOverrides.test_insert_file": "PASSED",
    "TestPackageOverrides.test_instance_conforms_to_IPEP302Loader": "PASSED",
    "TestPackageOverrides.test_instance_conforms_to_IPackageOverrides": "PASSED",
    "TestPackageOverrides.test_is_package_pkg_has___loader__": "PASSED",
    "TestPackageOverrides.test_is_package_pkg_has_no___loader__": "PASSED",
    "TestPackageOverrides.test_isdir_doesnt_exist": "PASSED",
    "TestPackageOverrides.test_isdir_false": "PASSED",
    "TestPackageOverrides.test_isdir_true": "PASSED",
    "TestPackageOverrides.test_listdir": "PASSED",
    "TestPackageOverrides.test_listdir_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_exists": "PASSED",
    "TestPackageAssetSource.test_exists_file_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_exists_with_prefix": "PASSED",
    "TestPackageAssetSource.test_get_filename_file_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_get_stream": "PASSED",
    "TestPackageAssetSource.test_get_stream_file_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_get_stream_with_prefix": "PASSED",
    "TestPackageAssetSource.test_get_string": "PASSED",
    "TestPackageAssetSource.test_get_string_file_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_get_string_with_prefix": "PASSED",
    "TestPackageAssetSource.test_isdir_doesnt_exist": "PASSED",
    "TestPackageAssetSource.test_isdir_false": "PASSED",
    "TestPackageAssetSource.test_isdir_true": "PASSED",
    "TestPackageAssetSource.test_listdir": "PASSED",
    "TestPackageAssetSource.test_listdir_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_exists": "PASSED",
    "TestFSAssetSource.test_exists_file_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_exists_with_prefix": "PASSED",
    "TestFSAssetSource.test_get_filename": "PASSED",
    "TestFSAssetSource.test_get_filename_file_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_get_filename_with_prefix": "PASSED",
    "TestFSAssetSource.test_get_stream": "PASSED",
    "TestFSAssetSource.test_get_stream_file_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_get_stream_with_prefix": "PASSED",
    "TestFSAssetSource.test_get_string": "PASSED",
    "TestFSAssetSource.test_get_string_file_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_get_string_with_prefix": "PASSED",
    "TestFSAssetSource.test_isdir_doesnt_exist": "PASSED",
    "TestFSAssetSource.test_isdir_false": "PASSED",
    "TestFSAssetSource.test_isdir_true": "PASSED",
    "TestFSAssetSource.test_listdir": "PASSED",
    "TestFSAssetSource.test_listdir_doesnt_exist": "PASSED",
    "TestDirectoryOverride.test_it_match": "PASSED",
    "TestDirectoryOverride.test_it_no_match": "PASSED",
    "TestFileOverride.test_it_match": "PASSED",
    "TestFileOverride.test_it_no_match": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_None_callable": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_None_callable_and_no_name": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_None_callable_conflict": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_callable": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_text_type_name": "PASSED",
    "TestFactoriesMixin.test_add_request_method_with_unnamed_callable": "PASSED",
    "TestFactoriesMixin.test_set_multiple_request_methods_conflict": "PASSED",
    "TestFactoriesMixin.test_set_request_factory": "PASSED",
    "TestFactoriesMixin.test_set_request_factory_dottedname": "PASSED",
    "TestFactoriesMixin.test_set_response_factory": "PASSED",
    "TestFactoriesMixin.test_set_response_factory_dottedname": "PASSED",
    "TestFactoriesMixin.test_set_root_factory": "PASSED",
    "TestFactoriesMixin.test_set_root_factory_as_None": "PASSED",
    "TestFactoriesMixin.test_set_root_factory_dottedname": "PASSED",
    "TestFactoriesMixin.test_set_session_factory": "PASSED",
    "TestFactoriesMixin.test_set_session_factory_dottedname": "PASSED",
    "TestDeprecatedFactoriesMixinMethods.test_set_multiple_request_properties": "PASSED",
    "TestDeprecatedFactoriesMixinMethods.test_set_multiple_request_properties_conflict": "PASSED",
    "TestDeprecatedFactoriesMixinMethods.test_set_request_property_with_callable": "PASSED",
    "TestDeprecatedFactoriesMixinMethods.test_set_request_property_with_property": "PASSED",
    "TestDeprecatedFactoriesMixinMethods.test_set_request_property_with_unnamed_callable": "PASSED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_missing_dir": "PASSED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_no_specs": "PASSED",
    "TestI18NConfiguratorMixin.test_set_locale_negotiator": "PASSED",
    "TestI18NConfiguratorMixin.test_set_locale_negotiator_dottedname": "PASSED",
    "ConfiguratorTests.test___getattr__matches": "PASSED",
    "ConfiguratorTests.test___getattr__matches_no_action_wrap": "PASSED",
    "ConfiguratorTests.test___getattr__missing_when_directives_dont_exist": "PASSED",
    "ConfiguratorTests.test___getattr__missing_when_directives_exist": "PASSED",
    "ConfiguratorTests.test__fix_registry_adds__lock": "PASSED",
    "ConfiguratorTests.test__fix_registry_adds_clear_view_lookup_cache": "PASSED",
    "ConfiguratorTests.test__fix_registry_has_listeners": "PASSED",
    "ConfiguratorTests.test__fix_registry_notify": "PASSED",
    "ConfiguratorTests.test__fix_registry_queryAdapterOrSelf": "PASSED",
    "ConfiguratorTests.test__fix_registry_registerSelfAdapter": "PASSED",
    "ConfiguratorTests.test_absolute_asset_spec_already_absolute": "PASSED",
    "ConfiguratorTests.test_absolute_asset_spec_notastring": "PASSED",
    "ConfiguratorTests.test_absolute_asset_spec_relative": "PASSED",
    "ConfiguratorTests.test_action_autocommit_with_introspectables": "PASSED",
    "ConfiguratorTests.test_action_autocommit_with_introspectables_introspection_off": "PASSED",
    "ConfiguratorTests.test_action_branching_kw_is_None": "PASSED",
    "ConfiguratorTests.test_action_branching_kw_is_not_None": "PASSED",
    "ConfiguratorTests.test_action_branching_nonautocommit_with_config_info": "PASSED",
    "ConfiguratorTests.test_action_branching_nonautocommit_with_introspectables": "PASSED",
    "ConfiguratorTests.test_action_branching_nonautocommit_without_config_info": "PASSED",
    "ConfiguratorTests.test_action_nonautocommit_with_introspectables_introspection_off": "PASSED",
    "ConfiguratorTests.test_autocommit_no_conflicts": "PASSED",
    "ConfiguratorTests.test_begin": "PASSED",
    "ConfiguratorTests.test_begin_with_request": "PASSED",
    "ConfiguratorTests.test_commit_conflict_resolved_with_include": "PASSED",
    "ConfiguratorTests.test_commit_conflict_resolved_with_two_includes_and_local": "PASSED",
    "ConfiguratorTests.test_commit_conflict_simple": "PASSED",
    "ConfiguratorTests.test_commit_conflict_with_two_includes": "PASSED",
    "ConfiguratorTests.test_conflict_set_forbidden_view": "PASSED",
    "ConfiguratorTests.test_conflict_set_notfound_view": "PASSED",
    "ConfiguratorTests.test_ctor_alternate_renderers": "PASSED",
    "ConfiguratorTests.test_ctor_authentication_policy": "PASSED",
    "ConfiguratorTests.test_ctor_authorization_policy_only": "PASSED",
    "ConfiguratorTests.test_ctor_default_permission": "PASSED",
    "ConfiguratorTests.test_ctor_default_renderers": "PASSED",
    "ConfiguratorTests.test_ctor_default_view_mapper": "PASSED",
    "ConfiguratorTests.test_ctor_default_webob_response_adapter_registered": "PASSED",
    "ConfiguratorTests.test_ctor_exceptionresponse_view_None": "PASSED",
    "ConfiguratorTests.test_ctor_exceptionresponse_view_custom": "PASSED",
    "ConfiguratorTests.test_ctor_httpexception_view_default": "PASSED",
    "ConfiguratorTests.test_ctor_no_root_factory": "PASSED",
    "ConfiguratorTests.test_ctor_noreg_custom_settings": "PASSED",
    "ConfiguratorTests.test_ctor_noreg_debug_logger_non_None": "PASSED",
    "ConfiguratorTests.test_ctor_session_factory": "PASSED",
    "ConfiguratorTests.test_ctor_with_introspection": "PASSED",
    "ConfiguratorTests.test_ctor_with_package_registry": "PASSED",
    "ConfiguratorTests.test_ctor_with_root_factory": "PASSED",
    "ConfiguratorTests.test_end": "PASSED",
    "ConfiguratorTests.test_hook_zca": "PASSED",
    "ConfiguratorTests.test_include_with_dotted_name": "PASSED",
    "ConfiguratorTests.test_include_with_missing_source_file": "PASSED",
    "ConfiguratorTests.test_include_with_module_defaults_to_includeme": "PASSED",
    "ConfiguratorTests.test_include_with_module_defaults_to_includeme_missing": "PASSED",
    "ConfiguratorTests.test_include_with_nested_route_prefix": "PASSED",
    "ConfiguratorTests.test_include_with_python_callable": "PASSED",
    "ConfiguratorTests.test_include_with_route_prefix": "PASSED",
    "ConfiguratorTests.test_introspector_decorator": "PASSED",
    "ConfiguratorTests.test_make_wsgi_app": "PASSED",
    "ConfiguratorTests.test_maybe_dotted_notstring_success": "PASSED",
    "ConfiguratorTests.test_maybe_dotted_string_fail": "PASSED",
    "ConfiguratorTests.test_maybe_dotted_string_success": "PASSED",
    "ConfiguratorTests.test_scan_integration": "PASSED",
    "ConfiguratorTests.test_scan_integration_dottedname_package": "PASSED",
    "ConfiguratorTests.test_scan_integration_with_extra_kw": "PASSED",
    "ConfiguratorTests.test_scan_integration_with_ignore": "PASSED",
    "ConfiguratorTests.test_scan_integration_with_onerror": "PASSED",
    "ConfiguratorTests.test_setup_registry_alternate_renderers": "PASSED",
    "ConfiguratorTests.test_setup_registry_authentication_policy": "PASSED",
    "ConfiguratorTests.test_setup_registry_authentication_policy_dottedname": "PASSED",
    "ConfiguratorTests.test_setup_registry_authorization_policy_dottedname": "PASSED",
    "ConfiguratorTests.test_setup_registry_authorization_policy_only": "PASSED",
    "ConfiguratorTests.test_setup_registry_calls_fix_registry": "PASSED",
    "ConfiguratorTests.test_setup_registry_custom_settings": "PASSED",
    "ConfiguratorTests.test_setup_registry_debug_logger_name": "PASSED",
    "ConfiguratorTests.test_setup_registry_debug_logger_non_None": "PASSED",
    "ConfiguratorTests.test_setup_registry_default_permission": "PASSED",
    "ConfiguratorTests.test_setup_registry_dottedname_root_factory": "PASSED",
    "ConfiguratorTests.test_setup_registry_explicit_notfound_trumps_iexceptionresponse": "PASSED",
    "ConfiguratorTests.test_setup_registry_includes": "PASSED",
    "ConfiguratorTests.test_setup_registry_includes_spaces": "PASSED",
    "ConfiguratorTests.test_setup_registry_locale_negotiator": "PASSED",
    "ConfiguratorTests.test_setup_registry_locale_negotiator_dottedname": "PASSED",
    "ConfiguratorTests.test_setup_registry_no_default_root_factory": "PASSED",
    "ConfiguratorTests.test_setup_registry_registers_default_exceptionresponse_views": "PASSED",
    "ConfiguratorTests.test_setup_registry_registers_default_view_predicates": "PASSED",
    "ConfiguratorTests.test_setup_registry_registers_default_webob_iresponse_adapter": "PASSED",
    "ConfiguratorTests.test_setup_registry_request_factory": "PASSED",
    "ConfiguratorTests.test_setup_registry_request_factory_dottedname": "PASSED",
    "ConfiguratorTests.test_setup_registry_response_factory": "PASSED",
    "ConfiguratorTests.test_setup_registry_tweens": "PASSED",
    "ConfiguratorTests.test_unhook_zca": "PASSED",
    "ConfiguratorTests.test_with_package": "PASSED",
    "ConfiguratorTests.test_with_package_module": "PASSED",
    "ConfiguratorTests.test_with_package_package": "PASSED",
    "TestConfigurator_add_directive.test_directive_persists_across_configurator_creations": "PASSED",
    "TestConfigurator_add_directive.test_extend_action_method_successful": "PASSED",
    "TestConfigurator_add_directive.test_extend_same_name_doesnt_conflict": "PASSED",
    "TestConfigurator__add_predicate.test_factory_as_object": "PASSED",
    "TestActionState.test_action_simple": "PASSED",
    "TestActionState.test_action_with_includepath": "PASSED",
    "TestActionState.test_action_with_includepath_and_info": "PASSED",
    "TestActionState.test_action_with_info": "PASSED",
    "TestActionState.test_action_with_introspectables": "PASSED",
    "TestActionState.test_action_with_order": "PASSED",
    "TestActionState.test_execute_actions_dicts": "PASSED",
    "TestActionState.test_execute_actions_error": "PASSED",
    "TestActionState.test_execute_actions_tuples": "PASSED",
    "TestActionState.test_execute_actions_with_introspectable_no_callable": "PASSED",
    "TestActionState.test_execute_actions_with_introspectables": "PASSED",
    "TestActionState.test_it": "PASSED",
    "TestActionState.test_processSpec": "PASSED",
    "TestActionState.test_reentrant_action": "PASSED",
    "TestActionState.test_reentrant_action_error": "PASSED",
    "TestActionState.test_reentrant_action_without_clear": "PASSED",
    "Test_reentrant_action_functional.test_functional": "PASSED",
    "Test_resolveConflicts.test_it_conflict": "PASSED",
    "Test_resolveConflicts.test_it_success_dicts": "PASSED",
    "Test_resolveConflicts.test_it_success_tuples": "PASSED",
    "Test_resolveConflicts.test_it_with_actions_grouped_by_order": "PASSED",
    "TestGlobalRegistriesIntegration.test_global_registries": "PASSED",
    "TestGlobalRegistriesIntegration.test_global_registries_empty": "PASSED",
    "TestXHRPredicate.test___call___false": "PASSED",
    "TestXHRPredicate.test___call___true": "PASSED",
    "TestXHRPredicate.test_phash": "PASSED",
    "TestXHRPredicate.test_text": "PASSED",
    "TestRequestMethodPredicate.test___call___false": "PASSED",
    "TestRequestMethodPredicate.test___call___true_multi": "PASSED",
    "TestRequestMethodPredicate.test___call___true_single": "PASSED",
    "TestRequestMethodPredicate.test_ctor_get_but_no_head": "PASSED",
    "TestRequestMethodPredicate.test_phash": "PASSED",
    "TestRequestMethodPredicate.test_text": "PASSED",
    "TestPathInfoPredicate.test___call___false": "PASSED",
    "TestPathInfoPredicate.test___call___true": "PASSED",
    "TestPathInfoPredicate.test_ctor_compilefail": "PASSED",
    "TestPathInfoPredicate.test_phash": "PASSED",
    "TestPathInfoPredicate.test_text": "PASSED",
    "TestRequestParamPredicate.test___call___false": "PASSED",
    "TestRequestParamPredicate.test___call___false_multi": "PASSED",
    "TestRequestParamPredicate.test___call___true_exists": "PASSED",
    "TestRequestParamPredicate.test___call___true_multi": "PASSED",
    "TestRequestParamPredicate.test___call___true_withval": "PASSED",
    "TestRequestParamPredicate.test_phash_exists": "PASSED",
    "TestRequestParamPredicate.test_phash_exists_equal_sign": "PASSED",
    "TestRequestParamPredicate.test_phash_withval": "PASSED",
    "TestRequestParamPredicate.test_text_exists": "PASSED",
    "TestRequestParamPredicate.test_text_exists_equal_sign": "PASSED",
    "TestRequestParamPredicate.test_text_multi": "PASSED",
    "TestRequestParamPredicate.test_text_multi_equal_sign": "PASSED",
    "TestRequestParamPredicate.test_text_withval": "PASSED",
    "TestMatchParamPredicate.test___call___false": "PASSED",
    "TestMatchParamPredicate.test___call___matchdict_is_None": "PASSED",
    "TestMatchParamPredicate.test___call___true_multi": "PASSED",
    "TestMatchParamPredicate.test___call___true_single": "PASSED",
    "TestMatchParamPredicate.test_phash": "PASSED",
    "TestMatchParamPredicate.test_text": "PASSED",
    "TestCustomPredicate.test___call___false": "PASSED",
    "TestCustomPredicate.test___call___true": "PASSED",
    "TestCustomPredicate.test_phash": "PASSED",
    "TestCustomPredicate.test_text_func_has___text__": "PASSED",
    "TestCustomPredicate.test_text_func_repr": "PASSED",
    "TestTraversePredicate.test___call__traverse_has_remainder_already": "PASSED",
    "TestTraversePredicate.test___call__traverse_matches": "PASSED",
    "TestTraversePredicate.test___call__traverse_matches_with_highorder_chars": "PASSED",
    "TestTraversePredicate.test_phash": "PASSED",
    "TestTraversePredicate.test_text": "PASSED",
    "Test_CheckCSRFTokenPredicate.test_it_call_val_False": "PASSED",
    "Test_CheckCSRFTokenPredicate.test_it_call_val_True": "PASSED",
    "Test_CheckCSRFTokenPredicate.test_it_call_val_str": "PASSED",
    "Test_CheckCSRFTokenPredicate.test_phash": "PASSED",
    "Test_CheckCSRFTokenPredicate.test_text": "PASSED",
    "TestHeaderPredicate.test___call___false": "PASSED",
    "TestHeaderPredicate.test___call___false_withregex": "PASSED",
    "TestHeaderPredicate.test___call___true_exists": "PASSED",
    "TestHeaderPredicate.test___call___true_withregex": "PASSED",
    "TestHeaderPredicate.test___call___true_withval": "PASSED",
    "TestHeaderPredicate.test_phash_exists": "PASSED",
    "TestHeaderPredicate.test_phash_withregex": "PASSED",
    "TestHeaderPredicate.test_phash_withval": "PASSED",
    "TestHeaderPredicate.test_text_exists": "PASSED",
    "TestHeaderPredicate.test_text_withregex": "PASSED",
    "TestHeaderPredicate.test_text_withval": "PASSED",
    "Test_PhysicalPathPredicate.test_it_call_False": "PASSED",
    "Test_PhysicalPathPredicate.test_it_call_context_has_no_name": "PASSED",
    "Test_PhysicalPathPredicate.test_it_call_val_list_True": "PASSED",
    "Test_PhysicalPathPredicate.test_it_call_val_str_True": "PASSED",
    "Test_PhysicalPathPredicate.test_it_call_val_tuple_True": "PASSED",
    "Test_PhysicalPathPredicate.test_phash": "PASSED",
    "Test_PhysicalPathPredicate.test_text": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_it_call_authentication_policy_doesnt_provide_superset": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_it_call_authentication_policy_provides_superset": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_it_call_authentication_policy_provides_superset_implicit": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_it_call_no_authentication_policy": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_phash": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_text": "PASSED",
    "Test_EffectivePrincipalsPredicate.test_text_noniter": "PASSED",
    "TestRenderingConfiguratorMixin.test_add_default_renderers": "PASSED",
    "TestRenderingConfiguratorMixin.test_add_renderer": "PASSED",
    "TestRenderingConfiguratorMixin.test_add_renderer_dottedname_factory": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_defaults": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_discriminator": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_path_no_pattern": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_pattern_with_path": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_view_with_view_attr": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_view_with_view_context": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_view_with_view_permission": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_no_view_with_view_renderer": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_accept": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_custom_predicates": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_factory": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_factory_dottedname": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_header": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_path_info": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_path_info_highorder": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_path_info_regex": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_pregenerator": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_request_method": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_request_param": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_route_prefix": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_static": "PASSED",
    "RoutesConfiguratorMixinTests.test_add_route_with_xhr": "PASSED",
    "RoutesConfiguratorMixinTests.test_get_routes_mapper_already_registered": "PASSED",
    "RoutesConfiguratorMixinTests.test_get_routes_mapper_not_yet_registered": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_add_permission": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_changing_set_default_csrf_options": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authentication_policy_no_authz_policy": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authentication_policy_no_authz_policy_autocommit": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authentication_policy_with_authz_policy": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authentication_policy_with_authz_policy_autocommit": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authorization_policy_no_authn_policy": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authorization_policy_no_authn_policy_autocommit": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authorization_policy_with_authn_policy": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_authorization_policy_with_authn_policy_autocommit": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_default_csrf_options": "PASSED",
    "ConfiguratorSecurityMethodsTests.test_set_default_permission": "PASSED",
    "TestSettingsConfiguratorMixin.test__set_settings_as_None": "PASSED",
    "TestSettingsConfiguratorMixin.test__set_settings_as_dictwithvalues": "PASSED",
    "TestSettingsConfiguratorMixin.test_add_settings_settings_None": "PASSED",
    "TestSettingsConfiguratorMixin.test_add_settings_settings_already_registered": "PASSED",
    "TestSettingsConfiguratorMixin.test_add_settings_settings_not_yet_registered": "PASSED",
    "TestSettingsConfiguratorMixin.test_get_settings_nosettings": "PASSED",
    "TestSettingsConfiguratorMixin.test_get_settings_withsettings": "PASSED",
    "TestSettings.test_debug_all": "PASSED",
    "TestSettings.test_debug_authorization": "PASSED",
    "TestSettings.test_debug_notfound": "PASSED",
    "TestSettings.test_debug_routematch": "PASSED",
    "TestSettings.test_debug_templates": "PASSED",
    "TestSettings.test_default_locale_name": "PASSED",
    "TestSettings.test_getattr_fail": "PASSED",
    "TestSettings.test_getattr_raises_attribute_error": "PASSED",
    "TestSettings.test_getattr_success": "PASSED",
    "TestSettings.test_noargs": "PASSED",
    "TestSettings.test_originals_kept": "PASSED",
    "TestSettings.test_prevent_cachebust": "PASSED",
    "TestSettings.test_prevent_http_cache": "PASSED",
    "TestSettings.test_reload_all": "PASSED",
    "TestSettings.test_reload_assets": "PASSED",
    "TestSettings.test_reload_resources": "PASSED",
    "TestSettings.test_reload_templates": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_renderer": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_renderer_explicitrenderer": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_renderer_twice": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_subscriber_defaults": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_subscriber_dottedname": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_subscriber_multiple": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_subscriber_single": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_add_template": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_resources": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_securitypolicy": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_securitypolicy_forget_result": "PASSED",
    "TestingConfiguratorMixinTests.test_testing_securitypolicy_remember_result": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_dottedname": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_instance": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_name_ingress": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_name_main": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_over_ingress": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_over_ingress_iterable": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_under_main": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_under_main_iterable": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tween_unsuitable": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tweens_conflict": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tweens_names_distinct": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tweens_names_with_over_nonstringoriter": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tweens_names_with_under_nonstringoriter": "PASSED",
    "TestTweensConfiguratorMixin.test_add_tweens_names_with_underover": "PASSED",
    "TestTweens.test___call___explicit": "PASSED",
    "TestTweens.test___call___implicit": "PASSED",
    "TestTweens.test_add_explicit": "PASSED",
    "TestTweens.test_add_implicit": "PASSED",
    "TestTweens.test_implicit_ordering_1": "PASSED",
    "TestTweens.test_implicit_ordering_2": "PASSED",
    "TestTweens.test_implicit_ordering_3": "PASSED",
    "TestTweens.test_implicit_ordering_4": "PASSED",
    "TestTweens.test_implicit_ordering_5": "PASSED",
    "TestTweens.test_implicit_ordering_conflict_direct": "PASSED",
    "TestTweens.test_implicit_ordering_conflict_indirect": "PASSED",
    "TestTweens.test_implicit_ordering_missing_over_and_under_partials": "PASSED",
    "TestTweens.test_implicit_ordering_missing_over_partial": "PASSED",
    "TestTweens.test_implicit_ordering_missing_over_partial_with_fallback": "PASSED",
    "TestTweens.test_implicit_ordering_missing_under_partial": "PASSED",
    "TestTweens.test_implicit_ordering_missing_under_partial_with_fallback": "PASSED",
    "TestTweens.test_implicit_ordering_with_missing_fallbacks": "PASSED",
    "TestTweens.test_implicit_ordering_with_multiple_matching_fallbacks": "PASSED",
    "TestTweens.test_implicit_ordering_with_partial_fallbacks": "PASSED",
    "TestPredicateList.test_custom_predicates_can_affect_traversal": "PASSED",
    "TestPredicateList.test_different_custom_predicates_with_same_hash": "PASSED",
    "TestPredicateList.test_match_param_from_dict": "PASSED",
    "TestPredicateList.test_match_param_from_dict_fails": "PASSED",
    "TestPredicateList.test_match_param_from_string": "PASSED",
    "TestPredicateList.test_match_param_from_string_fails": "PASSED",
    "TestPredicateList.test_notted": "PASSED",
    "TestPredicateList.test_ordering_importance_and_number": "PASSED",
    "TestPredicateList.test_ordering_importance_of_predicates": "PASSED",
    "TestPredicateList.test_ordering_number_of_predicates": "PASSED",
    "TestPredicateList.test_ordering_xhr_and_request_method_trump_only_containment": "PASSED",
    "TestPredicateList.test_predicate_text_is_correct": "PASSED",
    "TestPredicateList.test_request_method_ordering_hashes_same": "PASSED",
    "TestPredicateList.test_request_method_sequence": "PASSED",
    "TestPredicateList.test_traverse_has_remainder_already": "PASSED",
    "TestPredicateList.test_traverse_matches": "PASSED",
    "TestPredicateList.test_traverse_matches_with_highorder_chars": "PASSED",
    "TestPredicateList.test_unknown_predicate": "PASSED",
    "Test_takes_one_arg.test_function_annotations": "PASSED",
    "Test_takes_one_arg.test_function_defaultargs_firstname_not_request": "PASSED",
    "Test_takes_one_arg.test_function_defaultargs_firstname_request": "PASSED",
    "Test_takes_one_arg.test_function_noargs": "PASSED",
    "Test_takes_one_arg.test_function_onearg_named_request": "PASSED",
    "Test_takes_one_arg.test_function_onearg_named_somethingelse": "PASSED",
    "Test_takes_one_arg.test_function_toomanyargs": "PASSED",
    "Test_takes_one_arg.test_function_with_attr_false": "PASSED",
    "Test_takes_one_arg.test_function_with_attr_true": "PASSED",
    "Test_takes_one_arg.test_instance_defaultargs_firstname_not_request": "PASSED",
    "Test_takes_one_arg.test_instance_defaultargs_firstname_request": "PASSED",
    "Test_takes_one_arg.test_instance_defaultargs_onearg_named_request": "PASSED",
    "Test_takes_one_arg.test_instance_defaultargs_onearg_named_somethingelse": "PASSED",
    "Test_takes_one_arg.test_instance_nocall": "PASSED",
    "Test_takes_one_arg.test_instance_toomanyargs": "PASSED",
    "Test_takes_one_arg.test_method_onearg_named_request": "PASSED",
    "Test_takes_one_arg.test_newstyle_class_init_defaultargs_firstname_not_request": "PASSED",
    "Test_takes_one_arg.test_newstyle_class_init_defaultargs_firstname_request": "PASSED",
    "Test_takes_one_arg.test_newstyle_class_init_firstname_request_with_secondname": "PASSED",
    "Test_takes_one_arg.test_newstyle_class_init_noargs": "PASSED",
    "Test_takes_one_arg.test_newstyle_class_init_onearg_named_somethingelse": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_defaultargs_firstname_not_request": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_defaultargs_firstname_request": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_noargs": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_onearg_named_request": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_onearg_named_somethingelse": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_init_toomanyargs": "PASSED",
    "Test_takes_one_arg.test_oldstyle_class_no_init": "PASSED",
    "Test_takes_one_arg.test_requestonly_newstyle_class_init_onearg_named_request": "PASSED",
    "Test_takes_one_arg.test_requestonly_newstyle_class_init_toomanyargs": "PASSED",
    "Test_takes_one_arg.test_requestonly_newstyle_class_no_init": "PASSED",
    "TestNotted.test_it_with_phash_val": "PASSED",
    "TestNotted.test_it_without_phash_val": "PASSED",
    "TestViewsConfigurationMixin.test_add_static_view_here_no_utility_registered": "FAILED",
    "Test_logging_file_config.test_it": "PASSED",
    "TestParseVars.test_parse_vars_bad": "PASSED",
    "TestParseVars.test_parse_vars_good": "PASSED",
    "TestPCreateCommand.test_confirm_override_conflicting_name": "PASSED",
    "TestPCreateCommand.test_force_override_conflicting_name": "PASSED",
    "TestPCreateCommand.test_force_override_site_name": "PASSED",
    "TestPCreateCommand.test_known_scaffold_absolute_path": "PASSED",
    "TestPCreateCommand.test_known_scaffold_multiple_rendered": "PASSED",
    "TestPCreateCommand.test_known_scaffold_single_rendered": "PASSED",
    "TestPCreateCommand.test_known_scaffold_with_path_as_project_target_rendered": "PASSED",
    "TestPCreateCommand.test_no_project_name": "PASSED",
    "TestPCreateCommand.test_run_no_scaffold_name": "PASSED",
    "TestPCreateCommand.test_run_no_scaffold_no_args": "PASSED",
    "TestPCreateCommand.test_run_show_scaffolds_exist": "PASSED",
    "TestPCreateCommand.test_run_show_scaffolds_none_exist": "PASSED",
    "TestPCreateCommand.test_scaffold_with_dev_pyramid_long_version": "PASSED",
    "TestPCreateCommand.test_scaffold_with_dev_pyramid_version": "PASSED",
    "TestPCreateCommand.test_scaffold_with_hyphen_in_project_name": "PASSED",
    "TestPCreateCommand.test_scaffold_with_prod_pyramid_long_version": "PASSED",
    "TestPCreateCommand.test_scaffold_with_prod_pyramid_unparsable_version": "PASSED",
    "TestPCreateCommand.test_scaffold_with_prod_pyramid_version": "PASSED",
    "TestPCreateCommand.test_unknown_scaffold_name": "PASSED",
    "Test_main.test_it": "PASSED",
    "TestPDistReportCommand.test_no_dists": "PASSED",
    "TestPDistReportCommand.test_with_dists": "PASSED",
    "TestPRequestCommand.test_command_has_bad_config_header": "PASSED",
    "TestPRequestCommand.test_command_method_configures_logging": "PASSED",
    "TestPRequestCommand.test_command_not_enough_args": "PASSED",
    "TestPRequestCommand.test_command_response_has_no_charset": "PASSED",
    "TestPRoutesCommand.test__get_mapper": "PASSED",
    "TestPRoutesCommand.test_bad_args": "PASSED",
    "TestPRoutesCommand.test_bad_format": "PASSED",
    "TestPRoutesCommand.test_good_args": "PASSED",
    "TestPRoutesCommand.test_good_format": "PASSED",
    "TestPRoutesCommand.test_no_mapper": "PASSED",
    "TestPRoutesCommand.test_no_routes": "PASSED",
    "TestPRoutesCommand.test_route_as_wsgiapp": "PASSED",
    "TestPRoutesCommand.test_route_no_view": "PASSED",
    "TestPRoutesCommand.test_route_with_no_slash_prefix": "PASSED",
    "TestPRoutesCommand.test_single_route_multiview_registered": "PASSED",
    "TestPRoutesCommand.test_single_route_no_route_registered": "PASSED",
    "TestPRoutesCommand.test_single_route_no_views_registered": "PASSED",
    "TestPRoutesCommand.test_single_route_one_view_registered_with_factory": "PASSED",
    "TestPRoutesCommand.test_static_routes_included_in_list": "PASSED",
    "TestPServeCommand.test_get_options_no_command": "PASSED",
    "TestPServeCommand.test_get_options_with_command": "PASSED",
    "TestPServeCommand.test_parse_vars_bad": "PASSED",
    "TestPServeCommand.test_parse_vars_good": "PASSED",
    "TestPServeCommand.test_record_pid_not_verbose": "PASSED",
    "TestPServeCommand.test_record_pid_verbose": "PASSED",
    "TestPServeCommand.test_remove_pid_current_pid_is_not_pid_in_file": "PASSED",
    "TestPServeCommand.test_remove_pid_current_pid_is_not_written_pid": "PASSED",
    "TestPServeCommand.test_remove_pid_file_not_verbose": "PASSED",
    "TestPServeCommand.test_remove_pid_file_stale_pid_write_exception": "PASSED",
    "TestPServeCommand.test_remove_pid_file_unlink_exception": "PASSED",
    "TestPServeCommand.test_remove_pid_file_verbose": "PASSED",
    "TestPServeCommand.test_remove_pid_no_pid_file": "PASSED",
    "TestPServeCommand.test_remove_pid_not_a_number": "PASSED",
    "TestPServeCommand.test_run_no_args": "PASSED",
    "TestPServeCommand.test_run_stop_daemon_bad_pid_file": "PASSED",
    "TestPServeCommand.test_run_stop_daemon_invalid_pid_in_file": "PASSED",
    "TestPServeCommand.test_run_stop_daemon_no_such_pid_file": "PASSED",
    "Test_read_pidfile.test_read_pidfile": "PASSED",
    "Test_read_pidfile.test_read_pidfile_no_pid_file": "PASSED",
    "Test_read_pidfile.test_read_pidfile_not_a_number": "PASSED",
    "TestLazyWriter.test_flush": "PASSED",
    "TestLazyWriter.test_open": "PASSED",
    "TestLazyWriter.test_write": "PASSED",
    "TestLazyWriter.test_writeline": "PASSED",
    "Test__methodwrapper.test___call__fail": "PASSED",
    "Test__methodwrapper.test___call__succeed": "PASSED",
    "TestPShellCommand.test_command_custom_section_override": "PASSED",
    "TestPShellCommand.test_command_default_shell_option": "PASSED",
    "TestPShellCommand.test_command_errors_with_unknown_shell": "PASSED",
    "TestPShellCommand.test_command_loads_check_variable_override_order": "PASSED",
    "TestPShellCommand.test_command_loads_custom_items": "PASSED",
    "TestPShellCommand.test_command_loads_default_shell": "PASSED",
    "TestPShellCommand.test_command_loads_ipython": "PASSED",
    "TestPShellCommand.test_command_loads_pythonstartup": "PASSED",
    "TestPShellCommand.test_command_loads_setup_from_options": "PASSED",
    "TestPShellCommand.test_command_setup": "PASSED",
    "TestPShellCommand.test_list_shells": "PASSED",
    "TestPShellCommand.test_shell_entry_points": "PASSED",
    "TestPShellCommand.test_shell_ordering": "PASSED",
    "TestPShellCommand.test_shell_override": "PASSED",
    "Test_python_shell_runner.test_it": "PASSED",
    "TestPTweensCommand.test__get_tweens": "PASSED",
    "TestPTweensCommand.test_command_implicit_and_explicit_tweens": "PASSED",
    "TestPTweensCommand.test_command_implicit_tweens_only": "PASSED",
    "TestPTweensCommand.test_command_no_tweens": "PASSED",
    "TestPViewsCommand.test__find_multi_routes_all_match": "PASSED",
    "TestPViewsCommand.test__find_multi_routes_none_match": "PASSED",
    "TestPViewsCommand.test__find_multi_routes_some_match": "PASSED",
    "TestPViewsCommand.test__find_view_no_match": "PASSED",
    "TestPViewsCommand.test__find_view_no_match_multiview_registered": "PASSED",
    "TestPViewsCommand.test__find_view_route_multiview": "PASSED",
    "TestPViewsCommand.test__find_view_route_multiview_no_view_registered": "PASSED",
    "TestPViewsCommand.test__find_view_route_no_multiview": "PASSED",
    "TestPViewsCommand.test__find_view_traversal": "PASSED",
    "TestPViewsCommand.test__find_view_traversal_multiview": "PASSED",
    "TestPViewsCommand.test_views_command_multi_view_nested": "PASSED",
    "TestPViewsCommand.test_views_command_multiview": "PASSED",
    "TestPViewsCommand.test_views_command_multiview_with_permission": "PASSED",
    "TestPViewsCommand.test_views_command_multiview_with_predicates": "PASSED",
    "TestPViewsCommand.test_views_command_not_found": "PASSED",
    "TestPViewsCommand.test_views_command_not_found_url_starts_without_slash": "PASSED",
    "TestPViewsCommand.test_views_command_single_view_route": "PASSED",
    "TestPViewsCommand.test_views_command_single_view_route_with_route_predicates": "PASSED",
    "TestPViewsCommand.test_views_command_single_view_traversal": "PASSED",
    "TestPViewsCommand.test_views_command_single_view_traversal_with_permission": "PASSED",
    "TestPViewsCommand.test_views_command_single_view_traversal_with_predicates": "PASSED",
    "TestViewsConfigurationMixin.test_add_static_view_package_here_relative": "FAILED",
    "TestViewsConfigurationMixin.test_add_view_with_template_renderer": "FAILED",
    "TestViewsConfigurationMixin.test_add_view_with_template_renderer_no_callable": "FAILED",
    "TestStaticURLInfo.test_generate_url_cachebust_with_overrides": "FAILED",
    "Test_view_description.test_without_text": "FAILED",
    "AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_dotted_names": "FAILED",
    "AdaptersConfiguratorMixinTests.test_add_resource_url_adapter_introspectables": "FAILED",
    "AdaptersConfiguratorMixinTests.test_add_traverser_dotted_names": "FAILED",
    "TestAssetsConfiguratorMixin.test_override_asset_directory_with_directory": "FAILED",
    "TestAssetsConfiguratorMixin.test_override_asset_directory_with_package": "FAILED",
    "TestAssetsConfiguratorMixin.test_override_asset_file_with_file": "FAILED",
    "TestAssetsConfiguratorMixin.test_override_asset_package_with_directory": "FAILED",
    "TestAssetsConfiguratorMixin.test_override_asset_package_with_package": "FAILED",
    "TestOverrideProvider.test_get_resource_filename_no_overrides": "FAILED",
    "TestOverrideProvider.test_get_resource_filename_override_returns_None": "FAILED",
    "TestPackageAssetSource.test_get_filename": "FAILED",
    "TestPackageAssetSource.test_get_filename_with_prefix": "FAILED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_abspath": "FAILED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec": "FAILED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_asset_spec_existing_translation_dirs": "FAILED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs": "FAILED",
    "TestI18NConfiguratorMixin.test_add_translation_dirs_multiple_specs_multiple_calls": "FAILED",
    "ConfiguratorTests.test_ctor_no_registry": "FAILED",
    "ConfiguratorTests.test_ctor_noreg_debug_logger_None_default": "FAILED",
    "ConfiguratorTests.test_include_constant_root_package": "FAILED",
    "ConfiguratorTests.test_scan_integration_conflict": "FAILED",
    "ConfiguratorTests.test_setup_registry_debug_logger_None_default": "FAILED",
    "TestConfigurator_add_directive.test_add_directive_with_custom_callable": "FAILED",
    "TestConfigurator_add_directive.test_add_directive_with_partial": "FAILED",
    "TestConfigurator_add_directive.test_extend_with_dotted_name": "FAILED",
    "TestConfigurator_add_directive.test_extend_with_python_callable": "FAILED",
    "TestConfigurator__add_predicate.test_factory_as_dotted_name": "FAILED",
    "TestPRequestCommand.test_command_display_headers": "FAILED",
    "TestPRequestCommand.test_command_has_content_type_header_var": "FAILED",
    "TestPRequestCommand.test_command_has_good_header_var": "FAILED",
    "TestPRequestCommand.test_command_has_multiple_header_vars": "FAILED",
    "TestPRequestCommand.test_command_method_get": "FAILED",
    "TestPRequestCommand.test_command_method_options": "FAILED",
    "TestPRequestCommand.test_command_method_patch": "FAILED",
    "TestPRequestCommand.test_command_method_post": "FAILED",
    "TestPRequestCommand.test_command_method_propfind": "FAILED",
    "TestPRequestCommand.test_command_method_put": "FAILED",
    "TestPRequestCommand.test_command_path_doesnt_start_with_slash": "FAILED",
    "TestPRequestCommand.test_command_two_args": "FAILED",
    "TestPRequestCommand.test_command_w_basic_auth": "FAILED",
    "TestPRequestCommand.test_command_with_query_string": "FAILED",
    "TestPRoutesCommand.test_config_format_ini_commas": "FAILED",
    "TestPRoutesCommand.test_config_format_ini_newlines": "FAILED",
    "TestPRoutesCommand.test_config_format_ini_spaces": "FAILED",
    "TestPRoutesCommand.test_one_route_all_methods_view_only_post": "FAILED",
    "TestPRoutesCommand.test_one_route_only_post_view_all_methods": "FAILED",
    "TestPRoutesCommand.test_one_route_only_post_view_post_and_get": "FAILED",
    "TestPRoutesCommand.test_one_route_with_long_name_one_view_registered": "FAILED",
    "TestPRoutesCommand.test_route_is_get_view_request_method_not_post": "FAILED",
    "TestPRoutesCommand.test_route_request_method_mismatch": "FAILED",
    "TestPRoutesCommand.test_route_static_views": "FAILED",
    "TestPRoutesCommand.test_single_route_one_view_registered": "FAILED",
    "TestPRoutesCommand.test_view_glob": "FAILED",
    "TestPRoutesCommand.test_view_request_method_not_post": "FAILED",
    "TestPViewsCommand.test_views_command_single_view_function_traversal": "FAILED"
}
diff --git a/pyramid/config/views.py b/pyramid/config/views.py
index 9e46ba155..198fde5e8 100644
--- a/pyramid/config/views.py
+++ b/pyramid/config/views.py
@@ -213,6 +213,7 @@ class ViewsConfiguratorMixin(object):
         match_param=None,
         check_csrf=None,
         require_csrf=None,
+        exception_only=False,
         **view_options):
         """ Add a :term:`view configuration` to the current
         configuration state.  Arguments to ``add_view`` are broken
@@ -701,6 +702,14 @@ class ViewsConfiguratorMixin(object):
              Support setting view deriver options. Previously, only custom
              view predicate values could be supplied.
 
+        exception_only
+
+          .. versionadded:: 1.8
+
+          A boolean indicating whether the view is registered only as an
+          exception view. When this argument is true, the view context must
+          be an exception.
+
         """
         if custom_predicates:
             warnings.warn(
@@ -759,6 +768,11 @@ class ViewsConfiguratorMixin(object):
                 raise ConfigurationError(
                     'request_type must be an interface, not %s' % request_type)
 
+        if exception_only and not isexception(context):
+            raise ConfigurationError(
+                'context must be an exception when exception_only is true'
+                )
+
         if context is None:
             context = for_
 
@@ -942,10 +956,13 @@ class ViewsConfiguratorMixin(object):
                     view_iface = ISecuredView
                 else:
                     view_iface = IView
-                self.registry.registerAdapter(
-                    derived_view,
-                    (IViewClassifier, request_iface, context), view_iface, name
-                    )
+                if not exception_only:
+                    self.registry.registerAdapter(
+                        derived_view,
+                        (IViewClassifier, request_iface, context),
+                        view_iface,
+                        name
+                        )
                 if isexc:
                     self.registry.registerAdapter(
                         derived_view,

{"pyramid/config/views.py": "import inspect\nimport posixpath\nimport operator\nimport os\nimport warnings\n\nfrom zope.interface import (\n    Interface,\n    implementedBy,\n    implementer,\n    )\n\nfrom zope.interface.interfaces import IInterface\n\nfrom pyramid.interfaces import (\n    IException,\n    IExceptionViewClassifier,\n    IMultiView,\n    IPackageOverrides,\n    IRendererFactory,\n    IRequest,\n    IResponse,\n    IRouteRequest,\n    ISecuredView,\n    IStaticURLInfo,\n    IView,\n    IViewClassifier,\n    IViewDerivers,\n    IViewDeriverInfo,\n    IViewMapperFactory,\n    PHASE1_CONFIG,\n    )\n\nfrom pyramid import renderers\n\nfrom pyramid.asset import resolve_asset_spec\nfrom pyramid.compat import (\n    string_types,\n    urlparse,\n    url_quote,\n    WIN,\n    is_nonstr_iter,\n    )\n\nfrom pyramid.decorator import reify\n\nfrom pyramid.exceptions import (\n    ConfigurationError,\n    PredicateMismatch,\n    )\n\nfrom pyramid.httpexceptions import (\n    HTTPForbidden,\n    HTTPNotFound,\n    default_exceptionresponse_view,\n    )\n\nfrom pyramid.registry import (\n    predvalseq,\n    Deferred,\n    )\n\nfrom pyramid.security import NO_PERMISSION_REQUIRED\nfrom pyramid.static import static_view\n\nfrom pyramid.url import parse_url_overrides\n\nfrom pyramid.view import AppendSlashNotFoundViewFactory\n\nimport pyramid.util\nfrom pyramid.util import (\n    viewdefaults,\n    action_method,\n    TopologicalSorter,\n    )\n\nimport pyramid.config.predicates\nimport pyramid.viewderivers\n\nfrom pyramid.viewderivers import (\n    INGRESS,\n    VIEW,\n    preserve_view_attrs,\n    view_description,\n    requestonly,\n    DefaultViewMapper,\n    wraps_view,\n)\n\nfrom pyramid.config.util import (\n    DEFAULT_PHASH,\n    MAX_ORDER,\n    as_sorted_tuple,\n    )\n\nurljoin = urlparse.urljoin\nurl_parse = urlparse.urlparse\n\nDefaultViewMapper = DefaultViewMapper # bw-compat\npreserve_view_attrs = preserve_view_attrs # bw-compat\nrequestonly = requestonly # bw-compat\nview_description = view_description # bw-compat\n\n@implementer(IMultiView)\nclass MultiView(object):\n\n    def __init__(self, name):\n        self.name = name\n        self.media_views = {}\n        self.views = []\n        self.accepts = []\n\n    def __discriminator__(self, context, request):\n        # used by introspection systems like so:\n        # view = adapters.lookup(....)\n        # view.__discriminator__(context, request) -> view's discriminator\n        # so that superdynamic systems can feed the discriminator to\n        # the introspection system to get info about it\n        view = self.match(context, request)\n        return view.__discriminator__(context, request)\n\n    def add(self, view, order, accept=None, phash=None):\n        if phash is not None:\n            for i, (s, v, h) in enumerate(list(self.views)):\n                if phash == h:\n                    self.views[i] = (order, view, phash)\n                    return\n\n        if accept is None or '*' in accept:\n            self.views.append((order, view, phash))\n            self.views.sort(key=operator.itemgetter(0))\n        else:\n            subset = self.media_views.setdefault(accept, [])\n            for i, (s, v, h) in enumerate(list(subset)):\n                if phash == h:\n                    subset[i] = (order, view, phash)\n                    return\n            else:\n                subset.append((order, view, phash))\n                subset.sort(key=operator.itemgetter(0))\n            accepts = set(self.accepts)\n            accepts.add(accept)\n            self.accepts = list(accepts) # dedupe\n\n    def get_views(self, request):\n        if self.accepts and hasattr(request, 'accept'):\n            accepts = self.accepts[:]\n            views = []\n            while accepts:\n                match = request.accept.best_match(accepts)\n                if match is None:\n                    break\n                subset = self.media_views[match]\n                views.extend(subset)\n                accepts.remove(match)\n            views.extend(self.views)\n            return views\n        return self.views\n\n    def match(self, context, request):\n        for order, view, phash in self.get_views(request):\n            if not hasattr(view, '__predicated__'):\n                return view\n            if view.__predicated__(context, request):\n                return view\n        raise PredicateMismatch(self.name)\n\n    def __permitted__(self, context, request):\n        view = self.match(context, request)\n        if hasattr(view, '__permitted__'):\n            return view.__permitted__(context, request)\n        return True\n\n    def __call_permissive__(self, context, request):\n        view = self.match(context, request)\n        view = getattr(view, '__call_permissive__', view)\n        return view(context, request)\n\n    def __call__(self, context, request):\n        for order, view, phash in self.get_views(request):\n            try:\n                return view(context, request)\n            except PredicateMismatch:\n                continue\n        raise PredicateMismatch(self.name)\n\nclass ViewsConfiguratorMixin(object):\n    @viewdefaults\n    @action_method\n    def add_view(\n        self,\n        view=None,\n        name=\"\",\n        for_=None,\n        permission=None,\n        request_type=None,\n        route_name=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        context=None,\n        decorator=None,\n        mapper=None,\n        http_cache=None,\n        match_param=None,\n        check_csrf=None,\n        require_csrf=None,\n        **view_options):\n        \"\"\" Add a :term:`view configuration` to the current\n        configuration state.  Arguments to ``add_view`` are broken\n        down below into *predicate* arguments and *non-predicate*\n        arguments.  Predicate arguments narrow the circumstances in\n        which the view callable will be invoked when a request is\n        presented to :app:`Pyramid`; non-predicate arguments are\n        informational.\n\n        Non-Predicate Arguments\n\n        view\n\n          A :term:`view callable` or a :term:`dotted Python name`\n          which refers to a view callable.  This argument is required\n          unless a ``renderer`` argument also exists.  If a\n          ``renderer`` argument is passed, and a ``view`` argument is\n          not provided, the view callable defaults to a callable that\n          returns an empty dictionary (see\n          :ref:`views_which_use_a_renderer`).\n\n        permission\n\n          A :term:`permission` that the user must possess in order to invoke\n          the :term:`view callable`.  See :ref:`view_security_section` for\n          more information about view security and permissions.  This is\n          often a string like ``view`` or ``edit``.\n\n          If ``permission`` is omitted, a *default* permission may be used\n          for this view registration if one was named as the\n          :class:`pyramid.config.Configurator` constructor's\n          ``default_permission`` argument, or if\n          :meth:`pyramid.config.Configurator.set_default_permission` was used\n          prior to this view registration.  Pass the value\n          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission\n          argument to explicitly indicate that the view should always be\n          executable by entirely anonymous users, regardless of the default\n          permission, bypassing any :term:`authorization policy` that may be\n          in effect.\n\n        attr\n\n          This knob is most useful when the view definition is a class.\n\n          The view machinery defaults to using the ``__call__`` method\n          of the :term:`view callable` (or the function itself, if the\n          view callable is a function) to obtain a response.  The\n          ``attr`` value allows you to vary the method attribute used\n          to obtain the response.  For example, if your view was a\n          class, and the class has a method named ``index`` and you\n          wanted to use this method instead of the class' ``__call__``\n          method to return the response, you'd say ``attr=\"index\"`` in the\n          view configuration for the view.\n\n        renderer\n\n          This is either a single string term (e.g. ``json``) or a\n          string implying a path or :term:`asset specification`\n          (e.g. ``templates/views.pt``) naming a :term:`renderer`\n          implementation.  If the ``renderer`` value does not contain\n          a dot ``.``, the specified string will be used to look up a\n          renderer implementation, and that renderer implementation\n          will be used to construct a response from the view return\n          value.  If the ``renderer`` value contains a dot (``.``),\n          the specified term will be treated as a path, and the\n          filename extension of the last element in the path will be\n          used to look up the renderer implementation, which will be\n          passed the full path.  The renderer implementation will be\n          used to construct a :term:`response` from the view return\n          value.\n\n          Note that if the view itself returns a :term:`response` (see\n          :ref:`the_response`), the specified renderer implementation\n          is never called.\n\n          When the renderer is a path, although a path is usually just\n          a simple relative pathname (e.g. ``templates/foo.pt``,\n          implying that a template named \"foo.pt\" is in the\n          \"templates\" directory relative to the directory of the\n          current :term:`package` of the Configurator), a path can be\n          absolute, starting with a slash on UNIX or a drive letter\n          prefix on Windows.  The path can alternately be a\n          :term:`asset specification` in the form\n          ``some.dotted.package_name:relative/path``, making it\n          possible to address template assets which live in a\n          separate package.\n\n          The ``renderer`` attribute is optional.  If it is not\n          defined, the \"null\" renderer is assumed (no rendering is\n          performed and the value is passed back to the upstream\n          :app:`Pyramid` machinery unmodified).\n\n        http_cache\n\n          .. versionadded:: 1.1\n\n          When you supply an ``http_cache`` value to a view configuration,\n          the ``Expires`` and ``Cache-Control`` headers of a response\n          generated by the associated view callable are modified.  The value\n          for ``http_cache`` may be one of the following:\n\n          - A nonzero integer.  If it's a nonzero integer, it's treated as a\n            number of seconds.  This number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=3600`` instructs the requesting browser\n            to 'cache this response for an hour, please'.\n\n          - A ``datetime.timedelta`` instance.  If it's a\n            ``datetime.timedelta`` instance, it will be converted into a\n            number of seconds, and that number of seconds will be used to\n            compute the ``Expires`` header and the ``Cache-Control:\n            max-age`` parameter of responses to requests which call this view.\n            For example: ``http_cache=datetime.timedelta(days=1)`` instructs\n            the requesting browser to 'cache this response for a day, please'.\n\n          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and\n            ``Expires`` headers present in all responses from this view will\n            be composed such that client browser cache (and any intermediate\n            caches) are instructed to never cache the response.\n\n          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,\n            {'public':True})``), the first value in the tuple may be a\n            nonzero integer or a ``datetime.timedelta`` instance; in either\n            case this value will be used as the number of seconds to cache\n            the response.  The second value in the tuple must be a\n            dictionary.  The values present in the dictionary will be used as\n            input to the ``Cache-Control`` response header.  For example:\n            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,\n            and add ``public`` to the Cache-Control header of the response'.\n            All keys and values supported by the\n            ``webob.cachecontrol.CacheControl`` interface may be added to the\n            dictionary.  Supplying ``{'public':True}`` is equivalent to\n            calling ``response.cache_control.public = True``.\n\n          Providing a non-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value)`` within your view's body.\n\n          Providing a two-tuple value as ``http_cache`` is equivalent to\n          calling ``response.cache_expires(value[0], **value[1])`` within your\n          view's body.\n\n          If you wish to avoid influencing, the ``Expires`` header, and\n          instead wish to only influence ``Cache-Control`` headers, pass a\n          tuple as ``http_cache`` with the first element of ``None``, e.g.:\n          ``(None, {'public':True})``.\n\n          If you wish to prevent a view that uses ``http_cache`` in its\n          configuration from having its caching response headers changed by\n          this machinery, set ``response.cache_control.prevent_auto = True``\n          before returning the response from the view.  This effectively\n          disables any HTTP caching done by ``http_cache`` for that response.\n\n        require_csrf\n\n          .. versionadded:: 1.7\n\n          A boolean option or ``None``. Default: ``None``.\n\n          If this option is set to ``True`` then CSRF checks will be enabled\n          for requests to this view. The required token or header default to\n          ``csrf_token`` and ``X-CSRF-Token``, respectively.\n\n          CSRF checks only affect \"unsafe\" methods as defined by RFC2616. By\n          default, these methods are anything except\n          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.\n\n          The defaults here may be overridden by\n          :meth:`pyramid.config.Configurator.set_default_csrf_options`.\n\n          This feature requires a configured :term:`session factory`.\n\n          If this option is set to ``False`` then CSRF checks will be disabled\n          regardless of the default ``require_csrf`` setting passed\n          to ``set_default_csrf_options``.\n\n          See :ref:`auto_csrf_checking` for more information.\n\n        wrapper\n\n          The :term:`view name` of a different :term:`view\n          configuration` which will receive the response body of this\n          view as the ``request.wrapped_body`` attribute of its own\n          :term:`request`, and the :term:`response` returned by this\n          view as the ``request.wrapped_response`` attribute of its\n          own request.  Using a wrapper makes it possible to \"chain\"\n          views together to form a composite response.  The response\n          of the outermost wrapper view will be returned to the user.\n          The wrapper view will be found as any view is found: see\n          :ref:`view_lookup`.  The \"best\" wrapper view will be found\n          based on the lookup ordering: \"under the hood\" this wrapper\n          view is looked up via\n          ``pyramid.view.render_view_to_response(context, request,\n          'wrapper_viewname')``. The context and request of a wrapper\n          view is the same context and request of the inner view.  If\n          this attribute is unspecified, no view wrapping is done.\n\n        decorator\n\n          A :term:`dotted Python name` to function (or the function itself,\n          or an iterable of the aforementioned) which will be used to\n          decorate the registered :term:`view callable`.  The decorator\n          function(s) will be called with the view callable as a single\n          argument.  The view callable it is passed will accept\n          ``(context, request)``.  The decorator(s) must return a\n          replacement view callable which also accepts ``(context,\n          request)``.\n\n          If decorator is an iterable, the callables will be combined and\n          used in the order provided as a decorator.\n          For example::\n\n            @view_config(...,\n                decorator=(decorator2,\n                           decorator1))\n            def myview(request):\n                ....\n\n          Is similar to doing::\n\n            @view_config(...)\n            @decorator2\n            @decorator1\n            def myview(request):\n                ...\n\n          Except with the existing benefits of ``decorator=`` (having a common\n          decorator syntax for all view calling conventions and not having to\n          think about preserving function attributes such as ``__name__`` and\n          ``__module__`` within decorator logic).\n\n          All view callables in the decorator chain must return a response\n          object implementing :class:`pyramid.interfaces.IResponse` or raise\n          an exception:\n\n          .. code-block:: python\n\n             def log_timer(wrapped):\n                 def wrapper(context, request):\n                     start = time.time()\n                     response = wrapped(context, request)\n                     duration = time.time() - start\n                     response.headers['X-View-Time'] = '%.3f' % (duration,)\n                     log.info('view took %.3f seconds', duration)\n                     return response\n                 return wrapper\n\n          .. versionchanged:: 1.4a4\n             Passing an iterable.\n\n        mapper\n\n          A Python object or :term:`dotted Python name` which refers to a\n          :term:`view mapper`, or ``None``.  By default it is ``None``, which\n          indicates that the view should use the default view mapper.  This\n          plug-point is useful for Pyramid extension developers, but it's not\n          very useful for 'civilians' who are just developing stock Pyramid\n          applications. Pay no attention to the man behind the curtain.\n\n        accept\n\n          This value represents a match query for one or more mimetypes in the\n          ``Accept`` HTTP request header.  If this value is specified, it must\n          be in one of the following forms: a mimetype match token in the form\n          ``text/plain``, a wildcard mimetype match token in the form\n          ``text/*`` or a match-all wildcard mimetype match token in the form\n          ``*/*``.  If any of the forms matches the ``Accept`` header of the\n          request, or if the ``Accept`` header isn't set at all in the request,\n          this will match the current view. If this does not match the\n          ``Accept`` header of the request, view matching continues.\n\n        Predicate Arguments\n\n        name\n\n          The :term:`view name`.  Read :ref:`traversal_chapter` to\n          understand the concept of a view name.\n\n        context\n\n          An object or a :term:`dotted Python name` referring to an\n          interface or class object that the :term:`context` must be\n          an instance of, *or* the :term:`interface` that the\n          :term:`context` must provide in order for this view to be\n          found and called.  This predicate is true when the\n          :term:`context` is an instance of the represented class or\n          if the :term:`context` provides the represented interface;\n          it is otherwise false.  This argument may also be provided\n          to ``add_view`` as ``for_`` (an older, still-supported\n          spelling).\n\n        route_name\n\n          This value must match the ``name`` of a :term:`route\n          configuration` declaration (see :ref:`urldispatch_chapter`)\n          that must match before this view will be called.\n\n        request_type\n\n          This value should be an :term:`interface` that the\n          :term:`request` must provide in order for this view to be\n          found and called.  This value exists only for backwards\n          compatibility purposes.\n\n        request_method\n\n          This value can be either a string (such as ``\"GET\"``, ``\"POST\"``,\n          ``\"PUT\"``, ``\"DELETE\"``, ``\"HEAD\"`` or ``\"OPTIONS\"``) representing\n          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of\n          these strings.  A view declaration with this argument ensures that\n          the view will only be called when the ``method`` attribute of the\n          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches\n          a supplied value.  Note that use of ``GET`` also implies that the\n          view will respond to ``HEAD`` as of Pyramid 1.4.\n\n          .. versionchanged:: 1.2\n             The ability to pass a tuple of items as ``request_method``.\n             Previous versions allowed only a string.\n\n        request_param\n\n          This value can be any string or any sequence of strings.  A view\n          declaration with this argument ensures that the view will only be\n          called when the :term:`request` has a key in the ``request.params``\n          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a\n          name which matches the supplied value (if the value is a string)\n          or values (if the value is a tuple).  If any value\n          supplied has a ``=`` sign in it,\n          e.g. ``request_param=\"foo=123\"``, then the key (``foo``)\n          must both exist in the ``request.params`` dictionary, *and*\n          the value must match the right hand side of the expression\n          (``123``) for the view to \"match\" the current request.\n\n        match_param\n\n          .. versionadded:: 1.2\n\n          This value can be a string of the format \"key=value\" or a tuple\n          containing one or more of these strings.\n\n          A view declaration with this argument ensures that the view will\n          only be called when the :term:`request` has key/value pairs in its\n          :term:`matchdict` that equal those supplied in the predicate.\n          e.g. ``match_param=\"action=edit\"`` would require the ``action``\n          parameter in the :term:`matchdict` match the right hand side of\n          the expression (``edit``) for the view to \"match\" the current\n          request.\n\n          If the ``match_param`` is a tuple, every key/value pair must match\n          for the predicate to pass.\n\n        containment\n\n          This value should be a Python class or :term:`interface` (or a\n          :term:`dotted Python name`) that an object in the\n          :term:`lineage` of the context must provide in order for this view\n          to be found and called.  The nodes in your object graph must be\n          \"location-aware\" to use this feature.  See\n          :ref:`location_aware` for more information about\n          location-awareness.\n\n        xhr\n\n          This value should be either ``True`` or ``False``.  If this\n          value is specified and is ``True``, the :term:`request`\n          must possess an ``HTTP_X_REQUESTED_WITH`` (aka\n          ``X-Requested-With``) header that has the value\n          ``XMLHttpRequest`` for this view to be found and called.\n          This is useful for detecting AJAX requests issued from\n          jQuery, Prototype and other Javascript libraries.\n\n        header\n\n          This value represents an HTTP header name or a header\n          name/value pair.  If the value contains a ``:`` (colon), it\n          will be considered a name/value pair\n          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The\n          value portion should be a regular expression.  If the value\n          does not contain a colon, the entire value will be\n          considered to be the header name\n          (e.g. ``If-Modified-Since``).  If the value evaluates to a\n          header name only without a value, the header specified by\n          the name must be present in the request for this predicate\n          to be true.  If the value evaluates to a header name/value\n          pair, the header specified by the name must be present in\n          the request *and* the regular expression specified as the\n          value must match the header value.  Whether or not the value\n          represents a header name or a header name/value pair, the\n          case of the header name is not significant.\n\n        path_info\n\n          This value represents a regular expression pattern that will\n          be tested against the ``PATH_INFO`` WSGI environment\n          variable.  If the regex matches, this predicate will be\n          ``True``.\n\n        check_csrf\n\n          .. deprecated:: 1.7\n             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`\n             instead to have :class:`pyramid.exceptions.BadCSRFToken`\n             exceptions raised.\n\n          If specified, this value should be one of ``None``, ``True``,\n          ``False``, or a string representing the 'check name'.  If the value\n          is ``True`` or a string, CSRF checking will be performed.  If the\n          value is ``False`` or ``None``, CSRF checking will not be performed.\n\n          If the value provided is a string, that string will be used as the\n          'check name'.  If the value provided is ``True``, ``csrf_token`` will\n          be used as the check name.\n\n          If CSRF checking is performed, the checked value will be the value\n          of ``request.params[check_name]``.  This value will be compared\n          against the value of ``request.session.get_csrf_token()``, and the\n          check will pass if these two values are the same.  If the check\n          passes, the associated view will be permitted to execute.  If the\n          check fails, the associated view will not be permitted to execute.\n\n          Note that using this feature requires a :term:`session factory` to\n          have been configured.\n\n          .. versionadded:: 1.4a2\n\n        physical_path\n\n          If specified, this value should be a string or a tuple representing\n          the :term:`physical path` of the context found via traversal for this\n          predicate to match as true.  For example: ``physical_path='/'`` or\n          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.\n          This is not a path prefix match or a regex, it's a whole-path match.\n          It's useful when you want to always potentially show a view when some\n          object is traversed to, but you can't be sure about what kind of\n          object it will be, so you can't use the ``context`` predicate.  The\n          individual path elements inbetween slash characters or in tuple\n          elements should be the Unicode representation of the name of the\n          resource and should not be encoded in any way.\n\n          .. versionadded:: 1.4a3\n\n        effective_principals\n\n          If specified, this value should be a :term:`principal` identifier or\n          a sequence of principal identifiers.  If the\n          :attr:`pyramid.request.Request.effective_principals` property\n          indicates that every principal named in the argument list is present\n          in the current request, this predicate will return True; otherwise it\n          will return False.  For example:\n          ``effective_principals=pyramid.security.Authenticated`` or\n          ``effective_principals=('fred', 'group:admins')``.\n\n          .. versionadded:: 1.4a4\n\n        custom_predicates\n\n            .. deprecated:: 1.5\n                This value should be a sequence of references to custom\n                predicate callables.  Use custom predicates when no set of\n                predefined predicates do what you need.  Custom predicates\n                can be combined with predefined predicates as necessary.\n                Each custom predicate callable should accept two arguments:\n                ``context`` and ``request`` and should return either\n                ``True`` or ``False`` after doing arbitrary evaluation of\n                the context and/or the request.  The ``predicates`` argument\n                to this method and the ability to register third-party view\n                predicates via\n                :meth:`pyramid.config.Configurator.add_view_predicate`\n                obsoletes this argument, but it is kept around for backwards\n                compatibility.\n\n        view_options:\n\n          Pass a key/value pair here to use a third-party predicate or set a\n          value for a view deriver. See\n          :meth:`pyramid.config.Configurator.add_view_predicate` and\n          :meth:`pyramid.config.Configurator.add_view_deriver`. See\n          :ref:`view_and_route_predicates` for more information about\n          third-party predicates and :ref:`view_derivers` for information\n          about view derivers.\n\n          .. versionadded: 1.4a1\n\n          .. versionchanged: 1.7\n\n             Support setting view deriver options. Previously, only custom\n             view predicate values could be supplied.\n\n        \"\"\"\n        if custom_predicates:\n            warnings.warn(\n                ('The \"custom_predicates\" argument to Configurator.add_view '\n                 'is deprecated as of Pyramid 1.5.  Use '\n                 '\"config.add_view_predicate\" and use the registered '\n                 'view predicate as a predicate argument to add_view instead. '\n                 'See \"Adding A Third Party View, Route, or Subscriber '\n                 'Predicate\" in the \"Hooks\" chapter of the documentation '\n                 'for more information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        if check_csrf is not None:\n            warnings.warn(\n                ('The \"check_csrf\" argument to Configurator.add_view is '\n                 'deprecated as of Pyramid 1.7. Use the \"require_csrf\" option '\n                 'instead or see \"Checking CSRF Tokens Automatically\" in the '\n                 '\"Sessions\" chapter of the documentation for more '\n                 'information.'),\n                DeprecationWarning,\n                stacklevel=4,\n                )\n\n        view = self.maybe_dotted(view)\n        context = self.maybe_dotted(context)\n        for_ = self.maybe_dotted(for_)\n        containment = self.maybe_dotted(containment)\n        mapper = self.maybe_dotted(mapper)\n\n        def combine(*decorators):\n            def decorated(view_callable):\n                # reversed() allows a more natural ordering in the api\n                for decorator in reversed(decorators):\n                    view_callable = decorator(view_callable)\n                return view_callable\n            return decorated\n\n        if is_nonstr_iter(decorator):\n            decorator = combine(*map(self.maybe_dotted, decorator))\n        else:\n            decorator = self.maybe_dotted(decorator)\n\n        if not view:\n            if renderer:\n                def view(context, request):\n                    return {}\n            else:\n                raise ConfigurationError('\"view\" was not specified and '\n                                         'no \"renderer\" specified')\n\n        if request_type is not None:\n            request_type = self.maybe_dotted(request_type)\n            if not IInterface.providedBy(request_type):\n                raise ConfigurationError(\n                    'request_type must be an interface, not %s' % request_type)\n\n        if context is None:\n            context = for_\n\n        r_context = context\n        if r_context is None:\n            r_context = Interface\n        if not IInterface.providedBy(r_context):\n            r_context = implementedBy(r_context)\n\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n\n        if accept is not None:\n            accept = accept.lower()\n\n        introspectables = []\n        ovals = view_options.copy()\n        ovals.update(dict(\n            xhr=xhr,\n            request_method=request_method,\n            path_info=path_info,\n            request_param=request_param,\n            header=header,\n            accept=accept,\n            containment=containment,\n            request_type=request_type,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            custom=predvalseq(custom_predicates),\n        ))\n\n        def discrim_func():\n            # We need to defer the discriminator until we know what the phash\n            # is.  It can't be computed any sooner because thirdparty\n            # predicates/view derivers may not yet exist when add_view is\n            # called.\n            valid_predicates = predlist.names()\n            pvals = {}\n            dvals = {}\n\n            for (k, v) in ovals.items():\n                if k in valid_predicates:\n                    pvals[k] = v\n                else:\n                    dvals[k] = v\n\n            self._check_view_options(**dvals)\n\n            order, preds, phash = predlist.make(self, **pvals)\n\n            view_intr.update({\n                'phash': phash,\n                'order': order,\n                'predicates': preds,\n                })\n            return ('view', context, name, route_name, phash)\n\n        discriminator = Deferred(discrim_func)\n\n        if inspect.isclass(view) and attr:\n            view_desc = 'method %r of %s' % (\n                attr, self.object_description(view))\n        else:\n            view_desc = self.object_description(view)\n\n        tmpl_intr = None\n\n        view_intr = self.introspectable('views',\n                                        discriminator,\n                                        view_desc,\n                                        'view')\n        view_intr.update(dict(\n            name=name,\n            context=context,\n            containment=containment,\n            request_param=request_param,\n            request_methods=request_method,\n            route_name=route_name,\n            attr=attr,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            match_param=match_param,\n            check_csrf=check_csrf,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n            callable=view,\n            mapper=mapper,\n            decorator=decorator,\n        ))\n        view_intr.update(view_options)\n        introspectables.append(view_intr)\n        predlist = self.get_predlist('view')\n\n        def register(permission=permission, renderer=renderer):\n            request_iface = IRequest\n            if route_name is not None:\n                request_iface = self.registry.queryUtility(IRouteRequest,\n                                                           name=route_name)\n                if request_iface is None:\n                    # route configuration should have already happened in\n                    # phase 2\n                    raise ConfigurationError(\n                        'No route named %s found for view registration' %\n                        route_name)\n\n            if renderer is None:\n                # use default renderer if one exists (reg'd in phase 1)\n                if self.registry.queryUtility(IRendererFactory) is not None:\n                    renderer = renderers.RendererHelper(\n                        name=None,\n                        package=self.package,\n                        registry=self.registry\n                        )\n\n            # added by discrim_func above during conflict resolving\n            preds = view_intr['predicates']\n            order = view_intr['order']\n            phash = view_intr['phash']\n\n            # __no_permission_required__ handled by _secure_view\n            derived_view = self._derive_view(\n                view,\n                permission=permission,\n                predicates=preds,\n                attr=attr,\n                context=context,\n                renderer=renderer,\n                wrapper_viewname=wrapper,\n                viewname=name,\n                accept=accept,\n                order=order,\n                phash=phash,\n                decorator=decorator,\n                mapper=mapper,\n                http_cache=http_cache,\n                require_csrf=require_csrf,\n                extra_options=ovals,\n            )\n            derived_view.__discriminator__ = lambda *arg: discriminator\n            # __discriminator__ is used by superdynamic systems\n            # that require it for introspection after manual view lookup;\n            # see also MultiView.__discriminator__\n            view_intr['derived_callable'] = derived_view\n\n            registered = self.registry.adapters.registered\n\n            # A multiviews is a set of views which are registered for\n            # exactly the same context type/request type/name triad.  Each\n            # consituent view in a multiview differs only by the\n            # predicates which it possesses.\n\n            # To find a previously registered view for a context\n            # type/request type/name triad, we need to use the\n            # ``registered`` method of the adapter registry rather than\n            # ``lookup``.  ``registered`` ignores interface inheritance\n            # for the required and provided arguments, returning only a\n            # view registered previously with the *exact* triad we pass\n            # in.\n\n            # We need to do this three times, because we use three\n            # different interfaces as the ``provided`` interface while\n            # doing registrations, and ``registered`` performs exact\n            # matches on all the arguments it receives.\n\n            old_view = None\n\n            for view_type in (IView, ISecuredView, IMultiView):\n                old_view = registered((IViewClassifier, request_iface,\n                                       r_context), view_type, name)\n                if old_view is not None:\n                    break\n\n            isexc = isexception(context)\n\n            def regclosure():\n                if hasattr(derived_view, '__call_permissive__'):\n                    view_iface = ISecuredView\n                else:\n                    view_iface = IView\n                self.registry.registerAdapter(\n                    derived_view,\n                    (IViewClassifier, request_iface, context), view_iface, name\n                    )\n                if isexc:\n                    self.registry.registerAdapter(\n                        derived_view,\n                        (IExceptionViewClassifier, request_iface, context),\n                        view_iface, name)\n\n            is_multiview = IMultiView.providedBy(old_view)\n            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)\n\n            if old_view is None:\n                # - No component was yet registered for any of our I*View\n                #   interfaces exactly; this is the first view for this\n                #   triad.\n                regclosure()\n\n            elif (not is_multiview) and (old_phash == phash):\n                # - A single view component was previously registered with\n                #   the same predicate hash as this view; this registration\n                #   is therefore an override.\n                regclosure()\n\n            else:\n                # - A view or multiview was already registered for this\n                #   triad, and the new view is not an override.\n\n                # XXX we could try to be more efficient here and register\n                # a non-secured view for a multiview if none of the\n                # multiview's consituent views have a permission\n                # associated with them, but this code is getting pretty\n                # rough already\n                if is_multiview:\n                    multiview = old_view\n                else:\n                    multiview = MultiView(name)\n                    old_accept = getattr(old_view, '__accept__', None)\n                    old_order = getattr(old_view, '__order__', MAX_ORDER)\n                    multiview.add(old_view, old_order, old_accept, old_phash)\n                multiview.add(derived_view, order, accept, phash)\n                for view_type in (IView, ISecuredView):\n                    # unregister any existing views\n                    self.registry.adapters.unregister(\n                        (IViewClassifier, request_iface, r_context),\n                        view_type, name=name)\n                    if isexc:\n                        self.registry.adapters.unregister(\n                            (IExceptionViewClassifier, request_iface,\n                             r_context), view_type, name=name)\n                self.registry.registerAdapter(\n                    multiview,\n                    (IViewClassifier, request_iface, context),\n                    IMultiView, name=name)\n                if isexc:\n                    self.registry.registerAdapter(\n                        multiview,\n                        (IExceptionViewClassifier, request_iface, context),\n                        IMultiView, name=name)\n\n            self.registry._clear_view_lookup_cache()\n            renderer_type = getattr(renderer, 'type', None) # gard against None\n            intrspc = self.introspector\n            if (\n                renderer_type is not None and\n                tmpl_intr is not None and\n                intrspc is not None and\n                intrspc.get('renderer factories', renderer_type) is not None\n                ):\n                # allow failure of registered template factories to be deferred\n                # until view execution, like other bad renderer factories; if\n                # we tried to relate this to an existing renderer factory\n                # without checking if it the factory actually existed, we'd end\n                # up with a KeyError at startup time, which is inconsistent\n                # with how other bad renderer registrations behave (they throw\n                # a ValueError at view execution time)\n                tmpl_intr.relate('renderer factories', renderer.type)\n\n        if mapper:\n            mapper_intr = self.introspectable(\n                'view mappers',\n                discriminator,\n                'view mapper for %s' % view_desc,\n                'view mapper'\n                )\n            mapper_intr['mapper'] = mapper\n            mapper_intr.relate('views', discriminator)\n            introspectables.append(mapper_intr)\n        if route_name:\n            view_intr.relate('routes', route_name) # see add_route\n        if renderer is not None and renderer.name and '.' in renderer.name:\n            # the renderer is a template\n            tmpl_intr = self.introspectable(\n                'templates',\n                discriminator,\n                renderer.name,\n                'template'\n                )\n            tmpl_intr.relate('views', discriminator)\n            tmpl_intr['name'] = renderer.name\n            tmpl_intr['type'] = renderer.type\n            tmpl_intr['renderer'] = renderer\n            introspectables.append(tmpl_intr)\n        if permission is not None:\n            # if a permission exists, register a permission introspectable\n            perm_intr = self.introspectable(\n                'permissions',\n                permission,\n                permission,\n                'permission'\n                )\n            perm_intr['value'] = permission\n            perm_intr.relate('views', discriminator)\n            introspectables.append(perm_intr)\n        self.action(discriminator, register, introspectables=introspectables)\n\n    def _check_view_options(self, **kw):\n        # we only need to validate deriver options because the predicates\n        # were checked by the predlist\n        derivers = self.registry.getUtility(IViewDerivers)\n        for deriver in derivers.values():\n            for opt in getattr(deriver, 'options', []):\n                kw.pop(opt, None)\n        if kw:\n            raise ConfigurationError('Unknown view options: %s' % (kw,))\n\n    def _apply_view_derivers(self, info):\n        d = pyramid.viewderivers\n\n        # These derivers are not really derivers and so have fixed order\n        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),\n                          ('predicated_view', d.predicated_view)]\n\n        view = info.original_view\n        derivers = self.registry.getUtility(IViewDerivers)\n        for name, deriver in reversed(outer_derivers + derivers.sorted()):\n            view = wraps_view(deriver)(view, info)\n        return view\n\n    @action_method\n    def add_view_predicate(self, name, factory, weighs_more_than=None,\n                           weighs_less_than=None):\n        \"\"\"\n        .. versionadded:: 1.4\n\n        Adds a view predicate factory.  The associated view predicate can\n        later be named as a keyword argument to\n        :meth:`pyramid.config.Configurator.add_view` in the\n        ``predicates`` anonyous keyword argument dictionary.\n\n        ``name`` should be the name of the predicate.  It must be a valid\n        Python identifier (it will be used as a keyword argument to\n        ``add_view`` by others).\n\n        ``factory`` should be a :term:`predicate factory` or :term:`dotted\n        Python name` which refers to a predicate factory.\n\n        See :ref:`view_and_route_predicates` for more information.\n        \"\"\"\n        self._add_predicate(\n            'view',\n            name,\n            factory,\n            weighs_more_than=weighs_more_than,\n            weighs_less_than=weighs_less_than\n            )\n\n    def add_default_view_predicates(self):\n        p = pyramid.config.predicates\n        for (name, factory) in (\n            ('xhr', p.XHRPredicate),\n            ('request_method', p.RequestMethodPredicate),\n            ('path_info', p.PathInfoPredicate),\n            ('request_param', p.RequestParamPredicate),\n            ('header', p.HeaderPredicate),\n            ('accept', p.AcceptPredicate),\n            ('containment', p.ContainmentPredicate),\n            ('request_type', p.RequestTypePredicate),\n            ('match_param', p.MatchParamPredicate),\n            ('check_csrf', p.CheckCSRFTokenPredicate),\n            ('physical_path', p.PhysicalPathPredicate),\n            ('effective_principals', p.EffectivePrincipalsPredicate),\n            ('custom', p.CustomPredicate),\n            ):\n            self.add_view_predicate(name, factory)\n\n    @action_method\n    def add_view_deriver(self, deriver, name=None, under=None, over=None):\n        \"\"\"\n        .. versionadded:: 1.7\n\n        Add a :term:`view deriver` to the view pipeline. View derivers are\n        a feature used by extension authors to wrap views in custom code\n        controllable by view-specific options.\n\n        ``deriver`` should be a callable conforming to the\n        :class:`pyramid.interfaces.IViewDeriver` interface.\n\n        ``name`` should be the name of the view deriver.  There are no\n        restrictions on the name of a view deriver. If left unspecified, the\n        name will be constructed from the name of the ``deriver``.\n\n        The ``under`` and ``over`` options can be used to control the ordering\n        of view derivers by providing hints about where in the view pipeline\n        the deriver is used. Each option may be a string or a list of strings.\n        At least one view deriver in each, the over and under directions, must\n        exist to fully satisfy the constraints.\n\n        ``under`` means closer to the user-defined :term:`view callable`,\n        and ``over`` means closer to view pipeline ingress.\n\n        The default value for ``over`` is ``rendered_view`` and ``under`` is\n        ``decorated_view``. This places the deriver somewhere between the two\n        in the view pipeline. If the deriver should be placed elsewhere in the\n        pipeline, such as above ``decorated_view``, then you MUST also specify\n        ``under`` to something earlier in the order, or a\n        ``CyclicDependencyError`` will be raised when trying to sort the\n        derivers.\n\n        See :ref:`view_derivers` for more information.\n\n        \"\"\"\n        deriver = self.maybe_dotted(deriver)\n\n        if name is None:\n            name = deriver.__name__\n\n        if name in (INGRESS, VIEW):\n            raise ConfigurationError('%s is a reserved view deriver name'\n                                     % name)\n\n        if under is None:\n            under = 'decorated_view'\n\n        if over is None:\n            over = 'rendered_view'\n\n        over = as_sorted_tuple(over)\n        under = as_sorted_tuple(under)\n\n        if INGRESS in over:\n            raise ConfigurationError('%s cannot be over INGRESS' % name)\n\n        # ensure everything is always over mapped_view\n        if VIEW in over and name != 'mapped_view':\n            over = as_sorted_tuple(over + ('mapped_view',))\n\n        if VIEW in under:\n            raise ConfigurationError('%s cannot be under VIEW' % name)\n        if 'mapped_view' in under:\n            raise ConfigurationError('%s cannot be under \"mapped_view\"' % name)\n\n        discriminator = ('view deriver', name)\n        intr = self.introspectable(\n            'view derivers',\n            name,\n            name,\n            'view deriver')\n        intr['name'] = name\n        intr['deriver'] = deriver\n        intr['under'] = under\n        intr['over'] = over\n        def register():\n            derivers = self.registry.queryUtility(IViewDerivers)\n            if derivers is None:\n                derivers = TopologicalSorter(\n                    default_before=None,\n                    default_after=INGRESS,\n                    first=INGRESS,\n                    last=VIEW,\n                )\n                self.registry.registerUtility(derivers, IViewDerivers)\n            derivers.add(name, deriver, before=over, after=under)\n        self.action(discriminator, register, introspectables=(intr,),\n                    order=PHASE1_CONFIG) # must be registered before add_view\n\n    def add_default_view_derivers(self):\n        d = pyramid.viewderivers\n        derivers = [\n            ('secured_view', d.secured_view),\n            ('owrapped_view', d.owrapped_view),\n            ('http_cached_view', d.http_cached_view),\n            ('decorated_view', d.decorated_view),\n            ('rendered_view', d.rendered_view),\n            ('mapped_view', d.mapped_view),\n        ]\n        last = INGRESS\n        for name, deriver in derivers:\n            self.add_view_deriver(\n                deriver,\n                name=name,\n                under=last,\n                over=VIEW,\n            )\n            last = name\n\n        # leave the csrf_view loosely coupled to the rest of the pipeline\n        # by ensuring nothing in the default pipeline depends on the order\n        # of the csrf_view\n        self.add_view_deriver(\n            d.csrf_view,\n            'csrf_view',\n            under='secured_view',\n            over='owrapped_view',\n        )\n\n    def derive_view(self, view, attr=None, renderer=None):\n        \"\"\"\n        Create a :term:`view callable` using the function, instance,\n        or class (or :term:`dotted Python name` referring to the same)\n        provided as ``view`` object.\n\n        .. warning::\n\n           This method is typically only used by :app:`Pyramid` framework\n           extension authors, not by :app:`Pyramid` application developers.\n\n        This is API is useful to framework extenders who create\n        pluggable systems which need to register 'proxy' view\n        callables for functions, instances, or classes which meet the\n        requirements of being a :app:`Pyramid` view callable.  For\n        example, a ``some_other_framework`` function in another\n        framework may want to allow a user to supply a view callable,\n        but he may want to wrap the view callable in his own before\n        registering the wrapper as a :app:`Pyramid` view callable.\n        Because a :app:`Pyramid` view callable can be any of a\n        number of valid objects, the framework extender will not know\n        how to call the user-supplied object.  Running it through\n        ``derive_view`` normalizes it to a callable which accepts two\n        arguments: ``context`` and ``request``.\n\n        For example:\n\n        .. code-block:: python\n\n           def some_other_framework(user_supplied_view):\n               config = Configurator(reg)\n               proxy_view = config.derive_view(user_supplied_view)\n               def my_wrapper(context, request):\n                   do_something_that_mutates(request)\n                   return proxy_view(context, request)\n               config.add_view(my_wrapper)\n\n        The ``view`` object provided should be one of the following:\n\n        - A function or another non-class callable object that accepts\n          a :term:`request` as a single positional argument and which\n          returns a :term:`response` object.\n\n        - A function or other non-class callable object that accepts\n          two positional arguments, ``context, request`` and which\n          returns a :term:`response` object.\n\n        - A class which accepts a single positional argument in its\n          constructor named ``request``, and which has a ``__call__``\n          method that accepts no arguments that returns a\n          :term:`response` object.\n\n        - A class which accepts two positional arguments named\n          ``context, request``, and which has a ``__call__`` method\n          that accepts no arguments that returns a :term:`response`\n          object.\n\n        - A :term:`dotted Python name` which refers to any of the\n          kinds of objects above.\n\n        This API returns a callable which accepts the arguments\n        ``context, request`` and which returns the result of calling\n        the provided ``view`` object.\n\n        The ``attr`` keyword argument is most useful when the view\n        object is a class.  It names the method that should be used as\n        the callable.  If ``attr`` is not provided, the attribute\n        effectively defaults to ``__call__``.  See\n        :ref:`class_as_view` for more information.\n\n        The ``renderer`` keyword argument should be a renderer\n        name. If supplied, it will cause the returned callable to use\n        a :term:`renderer` to convert the user-supplied view result to\n        a :term:`response` object.  If a ``renderer`` argument is not\n        supplied, the user-supplied view must itself return a\n        :term:`response` object.  \"\"\"\n        return self._derive_view(view, attr=attr, renderer=renderer)\n\n    # b/w compat\n    def _derive_view(self, view, permission=None, predicates=(),\n                     attr=None, renderer=None, wrapper_viewname=None,\n                     viewname=None, accept=None, order=MAX_ORDER,\n                     phash=DEFAULT_PHASH, decorator=None,\n                     mapper=None, http_cache=None, context=None,\n                     require_csrf=None, extra_options=None):\n        view = self.maybe_dotted(view)\n        mapper = self.maybe_dotted(mapper)\n        if isinstance(renderer, string_types):\n            renderer = renderers.RendererHelper(\n                name=renderer, package=self.package,\n                registry=self.registry)\n        if renderer is None:\n            # use default renderer if one exists\n            if self.registry.queryUtility(IRendererFactory) is not None:\n                renderer = renderers.RendererHelper(\n                    name=None,\n                    package=self.package,\n                    registry=self.registry)\n\n        options = dict(\n            view=view,\n            context=context,\n            permission=permission,\n            attr=attr,\n            renderer=renderer,\n            wrapper=wrapper_viewname,\n            name=viewname,\n            accept=accept,\n            mapper=mapper,\n            decorator=decorator,\n            http_cache=http_cache,\n            require_csrf=require_csrf,\n        )\n        if extra_options:\n            options.update(extra_options)\n\n        info = ViewDeriverInfo(\n            view=view,\n            registry=self.registry,\n            package=self.package,\n            predicates=predicates,\n            options=options,\n        )\n\n        # order and phash are only necessary for the predicated view and\n        # are not really view deriver options\n        info.order = order\n        info.phash = phash\n\n        return self._apply_view_derivers(info)\n\n    @viewdefaults\n    @action_method\n    def add_forbidden_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        **view_options\n        ):\n        \"\"\" Add a forbidden view to the current configuration state.  The\n        view will be called when Pyramid or application code raises a\n        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of\n        circumstances implied by the predicates provided are matched.  The\n        simplest example is:\n\n          .. code-block:: python\n\n            def forbidden(request):\n                return Response('Forbidden', status='403 Forbidden')\n\n            config.add_forbidden_view(forbidden)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this forbidden\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a forbidden view.\n\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_forbidden_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPForbidden,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            attr=attr,\n            renderer=renderer,\n            )\n        settings.update(view_options)\n        return self.add_view(**settings)\n\n    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias\n\n    @viewdefaults\n    @action_method\n    def add_notfound_view(\n        self,\n        view=None,\n        attr=None,\n        renderer=None,\n        wrapper=None,\n        route_name=None,\n        request_type=None,\n        request_method=None,\n        request_param=None,\n        containment=None,\n        xhr=None,\n        accept=None,\n        header=None,\n        path_info=None,\n        custom_predicates=(),\n        decorator=None,\n        mapper=None,\n        match_param=None,\n        append_slash=False,\n        **view_options\n        ):\n        \"\"\" Add a default Not Found View to the current configuration state.\n        The view will be called when Pyramid or application code raises an\n        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a\n        view cannot be found for the request).  The simplest example is:\n\n          .. code-block:: python\n\n            def notfound(request):\n                return Response('Not Found', status='404 Not Found')\n\n            config.add_notfound_view(notfound)\n\n        If ``view`` argument is not provided, the view callable defaults to\n        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.\n\n        All arguments except ``append_slash`` have the same meaning as\n        :meth:`pyramid.config.Configurator.add_view` and each predicate\n        argument restricts the set of circumstances under which this notfound\n        view will be invoked.  Unlike\n        :meth:`pyramid.config.Configurator.add_view`, this method will raise\n        an exception if passed ``name``, ``permission``, ``context``,\n        ``for_``, or ``http_cache`` keyword arguments.  These argument values\n        make no sense in the context of a Not Found View.\n\n        If ``append_slash`` is ``True``, when this Not Found View is invoked,\n        and the current path info does not end in a slash, the notfound logic\n        will attempt to find a :term:`route` that matches the request's path\n        info suffixed with a slash.  If such a route exists, Pyramid will\n        issue a redirect to the URL implied by the route; if it does not,\n        Pyramid will return the result of the view callable provided as\n        ``view``, as normal.\n\n        If the argument provided as ``append_slash`` is not a boolean but\n        instead implements :class:`~pyramid.interfaces.IResponse`, the\n        append_slash logic will behave as if ``append_slash=True`` was passed,\n        but the provided class will be used as the response class instead of\n        the default :class:`~pyramid.httpexceptions.HTTPFound` response class\n        when a redirect is performed.  For example:\n\n          .. code-block:: python\n\n            from pyramid.httpexceptions import HTTPMovedPermanently\n            config.add_notfound_view(append_slash=HTTPMovedPermanently)\n\n        The above means that a redirect to a slash-appended route will be\n        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`\n        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will\n        be used` for the redirect response if a slash-appended route is found.\n\n        .. versionchanged:: 1.6\n        .. versionadded:: 1.3\n        \"\"\"\n        for arg in (\n            'name', 'permission', 'context', 'for_', 'http_cache',\n            'require_csrf',\n        ):\n            if arg in view_options:\n                raise ConfigurationError(\n                    '%s may not be used as an argument to add_notfound_view'\n                    % arg\n                    )\n\n        if view is None:\n            view = default_exceptionresponse_view\n\n        settings = dict(\n            view=view,\n            context=HTTPNotFound,\n            wrapper=wrapper,\n            request_type=request_type,\n            request_method=request_method,\n            request_param=request_param,\n            containment=containment,\n            xhr=xhr,\n            accept=accept,\n            header=header,\n            path_info=path_info,\n            custom_predicates=custom_predicates,\n            decorator=decorator,\n            mapper=mapper,\n            match_param=match_param,\n            route_name=route_name,\n            permission=NO_PERMISSION_REQUIRED,\n            require_csrf=False,\n            )\n        settings.update(view_options)\n        if append_slash:\n            view = self._derive_view(view, attr=attr, renderer=renderer)\n            if IResponse.implementedBy(append_slash):\n                view = AppendSlashNotFoundViewFactory(\n                    view, redirect_class=append_slash,\n                )\n            else:\n                view = AppendSlashNotFoundViewFactory(view)\n            settings['view'] = view\n        else:\n            settings['attr'] = attr\n            settings['renderer'] = renderer\n        return self.add_view(**settings)\n\n    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias\n\n    @action_method\n    def set_view_mapper(self, mapper):\n        \"\"\"\n        Setting a :term:`view mapper` makes it possible to make use of\n        :term:`view callable` objects which implement different call\n        signatures than the ones supported by :app:`Pyramid` as described in\n        its narrative documentation.\n\n        The ``mapper`` argument should be an object implementing\n        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted\n        Python name` to such an object.  The provided ``mapper`` will become\n        the default view mapper to be used by all subsequent :term:`view\n        configuration` registrations.\n\n        .. seealso::\n\n            See also :ref:`using_a_view_mapper`.\n\n        .. note::\n\n           Using the ``default_view_mapper`` argument to the\n           :class:`pyramid.config.Configurator` constructor\n           can be used to achieve the same purpose.\n        \"\"\"\n        mapper = self.maybe_dotted(mapper)\n        def register():\n            self.registry.registerUtility(mapper, IViewMapperFactory)\n        # IViewMapperFactory is looked up as the result of view config\n        # in phase 3\n        intr = self.introspectable('view mappers',\n                                   IViewMapperFactory,\n                                   self.object_description(mapper),\n                                   'default view mapper')\n        intr['mapper'] = mapper\n        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,\n                    introspectables=(intr,))\n\n    @action_method\n    def add_static_view(self, name, path, **kw):\n        \"\"\" Add a view used to render static assets such as images\n        and CSS files.\n\n        The ``name`` argument is a string representing an\n        application-relative local URL prefix.  It may alternately be a full\n        URL.\n\n        The ``path`` argument is the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cache_max_age`` keyword argument is input to set the\n        ``Expires`` and ``Cache-Control`` headers for static assets served.\n        Note that this argument has no effect when the ``name`` is a *url\n        prefix*.  By default, this argument is ``None``, meaning that no\n        particular Expires or Cache-Control headers are set in the response.\n\n        The ``permission`` keyword argument is used to specify the\n        :term:`permission` required by a user to execute the static view.  By\n        default, it is the string\n        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel\n        which indicates that, even if a :term:`default permission` exists for\n        the current application, the static view should be renderered to\n        completely anonymous users.  This default value is permissive\n        because, in most web apps, static assets seldom need protection from\n        viewing.  If ``permission`` is specified, the security checking will\n        be performed against the default root factory ACL.\n\n        Any other keyword arguments sent to ``add_static_view`` are passed on\n        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,\n        perhaps to define a custom factory with a custom ACL for this static\n        view).\n\n        *Usage*\n\n        The ``add_static_view`` function is typically used in conjunction\n        with the :meth:`pyramid.request.Request.static_url` method.\n        ``add_static_view`` adds a view which renders a static asset when\n        some URL is visited; :meth:`pyramid.request.Request.static_url`\n        generates a URL to that asset.\n\n        The ``name`` argument to ``add_static_view`` is usually a simple URL\n        prefix (e.g. ``'images'``).  When this is the case, the\n        :meth:`pyramid.request.Request.static_url` API will generate a URL\n        which points to a Pyramid view, which will serve up a set of assets\n        that live in the package itself. For example:\n\n        .. code-block:: python\n\n           add_static_view('images', 'mypackage:images/')\n\n        Code that registers such a view can generate URLs to the view via\n        :meth:`pyramid.request.Request.static_url`:\n\n        .. code-block:: python\n\n           request.static_url('mypackage:images/logo.png')\n\n        When ``add_static_view`` is called with a ``name`` argument that\n        represents a URL prefix, as it is above, subsequent calls to\n        :meth:`pyramid.request.Request.static_url` with paths that start with\n        the ``path`` argument passed to ``add_static_view`` will generate a\n        URL something like ``http://<Pyramid app URL>/images/logo.png``,\n        which will cause the ``logo.png`` file in the ``images`` subdirectory\n        of the ``mypackage`` package to be served.\n\n        ``add_static_view`` can alternately be used with a ``name`` argument\n        which is a *URL*, causing static assets to be served from an external\n        webserver.  This happens when the ``name`` argument is a fully\n        qualified URL (e.g. starts with ``http://`` or similar).  In this\n        mode, the ``name`` is used as the prefix of the full URL when\n        generating a URL using :meth:`pyramid.request.Request.static_url`.\n        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)\n        is used as the ``name`` argument, the generated URL will use the\n        protocol of the request (http or https, respectively).\n\n        For example, if ``add_static_view`` is called like so:\n\n        .. code-block:: python\n\n           add_static_view('http://example.com/images', 'mypackage:images/')\n\n        Subsequently, the URLs generated by\n        :meth:`pyramid.request.Request.static_url` for that static view will\n        be prefixed with ``http://example.com/images`` (the external webserver\n        listening on ``example.com`` must be itself configured to respond\n        properly to such a request.):\n\n        .. code-block:: python\n\n           static_url('mypackage:images/logo.png', request)\n\n        See :ref:`static_assets_section` for more information.\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add(self, name, spec, **kw)\n\n    def add_cache_buster(self, path, cachebust, explicit=False):\n        \"\"\"\n        Add a cache buster to a set of files on disk.\n\n        The ``path`` should be the path on disk where the static files\n        reside.  This can be an absolute path, a package-relative path, or a\n        :term:`asset specification`.\n\n        The ``cachebust`` argument may be set to cause\n        :meth:`~pyramid.request.Request.static_url` to use cache busting when\n        generating URLs. See :ref:`cache_busting` for general information\n        about cache busting. The value of the ``cachebust`` argument must\n        be an object which implements\n        :class:`~pyramid.interfaces.ICacheBuster`.\n\n        If ``explicit`` is set to ``True`` then the ``path`` for the cache\n        buster will be matched based on the ``rawspec`` instead of the\n        ``pathspec`` as defined in the\n        :class:`~pyramid.interfaces.ICacheBuster` interface.\n        Default: ``False``.\n\n        \"\"\"\n        spec = self._make_spec(path)\n        info = self._get_static_info()\n        info.add_cache_buster(self, spec, cachebust, explicit=explicit)\n\n    def _get_static_info(self):\n        info = self.registry.queryUtility(IStaticURLInfo)\n        if info is None:\n            info = StaticURLInfo()\n            self.registry.registerUtility(info, IStaticURLInfo)\n        return info\n\ndef isexception(o):\n    if IInterface.providedBy(o):\n        if IException.isEqualOrExtendedBy(o):\n            return True\n    return (\n        isinstance(o, Exception) or\n        (inspect.isclass(o) and (issubclass(o, Exception)))\n        )\n\n@implementer(IViewDeriverInfo)\nclass ViewDeriverInfo(object):\n    def __init__(self, view, registry, package, predicates, options):\n        self.original_view = view\n        self.registry = registry\n        self.package = package\n        self.predicates = predicates or []\n        self.options = options or {}\n\n    @reify\n    def settings(self):\n        return self.registry.settings\n\n@implementer(IStaticURLInfo)\nclass StaticURLInfo(object):\n    def __init__(self):\n        self.registrations = []\n        self.cache_busters = []\n\n    def generate(self, path, request, **kw):\n        for (url, spec, route_name) in self.registrations:\n            if path.startswith(spec):\n                subpath = path[len(spec):]\n                if WIN: # pragma: no cover\n                    subpath = subpath.replace('\\\\', '/') # windows\n                if self.cache_busters:\n                    subpath, kw = self._bust_asset_path(\n                        request, spec, subpath, kw)\n                if url is None:\n                    kw['subpath'] = subpath\n                    return request.route_url(route_name, **kw)\n                else:\n                    app_url, scheme, host, port, qs, anchor = \\\n                        parse_url_overrides(kw)\n                    parsed = url_parse(url)\n                    if not parsed.scheme:\n                        url = urlparse.urlunparse(parsed._replace(\n                            scheme=request.environ['wsgi.url_scheme']))\n                    subpath = url_quote(subpath)\n                    result = urljoin(url, subpath)\n                    return result + qs + anchor\n\n        raise ValueError('No static URL definition matching %s' % path)\n\n    def add(self, config, name, spec, **extra):\n        # This feature only allows for the serving of a directory and\n        # the files contained within, not of a single asset;\n        # appending a slash here if the spec doesn't have one is\n        # required for proper prefix matching done in ``generate``\n        # (``subpath = path[len(spec):]``).\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        # we also make sure the name ends with a slash, purely as a\n        # convenience: a name that is a url is required to end in a\n        # slash, so that ``urljoin(name, subpath))`` will work above\n        # when the name is a URL, and it doesn't hurt things for it to\n        # have a name that ends in a slash if it's used as a route\n        # name instead of a URL.\n        if not name.endswith('/'):\n            # make sure it ends with a slash\n            name = name + '/'\n\n        if url_parse(name).netloc:\n            # it's a URL\n            # url, spec, route_name\n            url = name\n            route_name = None\n        else:\n            # it's a view name\n            url = None\n            cache_max_age = extra.pop('cache_max_age', None)\n\n            # create a view\n            view = static_view(spec, cache_max_age=cache_max_age,\n                               use_subpath=True)\n\n            # Mutate extra to allow factory, etc to be passed through here.\n            # Treat permission specially because we'd like to default to\n            # permissiveness (see docs of config.add_static_view).\n            permission = extra.pop('permission', None)\n            if permission is None:\n                permission = NO_PERMISSION_REQUIRED\n\n            context = extra.pop('context', None)\n            if context is None:\n                context = extra.pop('for_', None)\n\n            renderer = extra.pop('renderer', None)\n\n            # register a route using the computed view, permission, and\n            # pattern, plus any extras passed to us via add_static_view\n            pattern = \"%s*subpath\" % name # name already ends with slash\n            if config.route_prefix:\n                route_name = '__%s/%s' % (config.route_prefix, name)\n            else:\n                route_name = '__%s' % name\n            config.add_route(route_name, pattern, **extra)\n            config.add_view(\n                route_name=route_name,\n                view=view,\n                permission=permission,\n                context=context,\n                renderer=renderer,\n            )\n\n        def register():\n            registrations = self.registrations\n\n            names = [t[0] for t in registrations]\n\n            if name in names:\n                idx = names.index(name)\n                registrations.pop(idx)\n\n            # url, spec, route_name\n            registrations.append((url, spec, route_name))\n\n        intr = config.introspectable('static views',\n                                     name,\n                                     'static view for %r' % name,\n                                     'static view')\n        intr['name'] = name\n        intr['spec'] = spec\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def add_cache_buster(self, config, spec, cachebust, explicit=False):\n        # ensure the spec always has a trailing slash as we only support\n        # adding cache busters to folders, not files\n        if os.path.isabs(spec): # FBO windows\n            sep = os.sep\n        else:\n            sep = '/'\n        if not spec.endswith(sep) and not spec.endswith(':'):\n            spec = spec + sep\n\n        def register():\n            if config.registry.settings.get('pyramid.prevent_cachebust'):\n                return\n\n            cache_busters = self.cache_busters\n\n            # find duplicate cache buster (old_idx)\n            # and insertion location (new_idx)\n            new_idx, old_idx = len(cache_busters), None\n            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):\n                # if we find an identical (spec, explicit) then use it\n                if spec == spec_ and explicit == explicit_:\n                    old_idx = new_idx = idx\n                    break\n\n                # past all explicit==False specs then add to the end\n                elif not explicit and explicit_:\n                    new_idx = idx\n                    break\n\n                # explicit matches and spec is shorter\n                elif explicit == explicit_ and len(spec) < len(spec_):\n                    new_idx = idx\n                    break\n\n            if old_idx is not None:\n                cache_busters.pop(old_idx)\n\n            cache_busters.insert(new_idx, (spec, cachebust, explicit))\n\n        intr = config.introspectable('cache busters',\n                                     spec,\n                                     'cache buster for %r' % spec,\n                                     'cache buster')\n        intr['cachebust'] = cachebust\n        intr['path'] = spec\n        intr['explicit'] = explicit\n\n        config.action(None, callable=register, introspectables=(intr,))\n\n    def _bust_asset_path(self, request, spec, subpath, kw):\n        registry = request.registry\n        pkg_name, pkg_subpath = resolve_asset_spec(spec)\n        rawspec = None\n\n        if pkg_name is not None:\n            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)\n            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)\n            if overrides is not None:\n                resource_name = posixpath.join(pkg_subpath, subpath)\n                sources = overrides.filtered_sources(resource_name)\n                for source, filtered_path in sources:\n                    rawspec = source.get_path(filtered_path)\n                    if hasattr(source, 'pkg_name'):\n                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)\n                    break\n\n        else:\n            pathspec = pkg_subpath + subpath\n\n        if rawspec is None:\n            rawspec = pathspec\n\n        kw['pathspec'] = pathspec\n        kw['rawspec'] = rawspec\n        for spec_, cachebust, explicit in reversed(self.cache_busters):\n            if (\n                (explicit and rawspec.startswith(spec_)) or\n                (not explicit and pathspec.startswith(spec_))\n            ):\n                subpath, kw = cachebust(request, subpath, kw)\n                break\n        return subpath, kw\n"}
A user will ask you to solve a task. You should first draft your thinking process (inner monologue). Then, generate the solution.

Your response format must follow the template below:
<think>
Your thoughts or/and draft, like working through an exercise on scratch paper. Be as casual and as long as you want until you are confident to generate a correct solution.
</think>
<solution>
Final solution presented to the user.
</solution>
system
We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[ISSUE]
**Title:** Unable to Register Exception-Only Views Using `exception_only` Argument

**Description:**
When attempting to register a view with the `exception_only` parameter set to `True`, a `ConfigurationError` is raised indicating that `exception_only` is an unknown view option. This prevents the registration of views that are intended to handle only exceptions.

**Example Code:**
```python
from pyramid.config import Configurator
from pyramid.exceptions import ConfigurationError

def exception_view(exc, request):
    return {'message': 'An exception occurred'}

config = Configurator()
config.add_view(view=exception_view, context=Exception, exception_only=True)
app = config.make_wsgi_app()
```

**Expected Behavior:**
The view should be successfully registered as an exception-only view, allowing it to handle exceptions without being registered as a regular view.

**Actual Behavior:**
A `ConfigurationError` is raised with the message:
```
Unknown view options: {'exception_only': True}
```
[/ISSUE]
--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.

--- BEGIN FILE ---
```
### pyramid/config/views.py
import inspect
import posixpath
import operator
import os
import warnings

from zope.interface import (
    Interface,
    implementedBy,
    implementer,
    )

from zope.interface.interfaces import IInterface

from pyramid.interfaces import (
    IException,
    IExceptionViewClassifier,
    IMultiView,
    IPackageOverrides,
    IRendererFactory,
    IRequest,
    IResponse,
    IRouteRequest,
    ISecuredView,
    IStaticURLInfo,
    IView,
    IViewClassifier,
    IViewDerivers,
    IViewDeriverInfo,
    IViewMapperFactory,
    PHASE1_CONFIG,
    )

from pyramid import renderers

from pyramid.asset import resolve_asset_spec
from pyramid.compat import (
    string_types,
    urlparse,
    url_quote,
    WIN,
    is_nonstr_iter,
    )

from pyramid.decorator import reify

from pyramid.exceptions import (
    ConfigurationError,
    PredicateMismatch,
    )

from pyramid.httpexceptions import (
    HTTPForbidden,
    HTTPNotFound,
    default_exceptionresponse_view,
    )

from pyramid.registry import (
    predvalseq,
    Deferred,
    )

from pyramid.security import NO_PERMISSION_REQUIRED
from pyramid.static import static_view

from pyramid.url import parse_url_overrides

from pyramid.view import AppendSlashNotFoundViewFactory

import pyramid.util
from pyramid.util import (
    viewdefaults,
    action_method,
    TopologicalSorter,
    )

import pyramid.config.predicates
import pyramid.viewderivers

from pyramid.viewderivers import (
    INGRESS,
    VIEW,
    preserve_view_attrs,
    view_description,
    requestonly,
    DefaultViewMapper,
    wraps_view,
)

from pyramid.config.util import (
    DEFAULT_PHASH,
    MAX_ORDER,
    as_sorted_tuple,
    )

urljoin = urlparse.urljoin
url_parse = urlparse.urlparse

DefaultViewMapper = DefaultViewMapper # bw-compat
preserve_view_attrs = preserve_view_attrs # bw-compat
requestonly = requestonly # bw-compat
view_description = view_description # bw-compat

@implementer(IMultiView)
class MultiView(object):

    def __init__(self, name):
        self.name = name
        self.media_views = {}
        self.views = []
        self.accepts = []

    def __discriminator__(self, context, request):
        # used by introspection systems like so:
        # view = adapters.lookup(....)
        # view.__discriminator__(context, request) -> view's discriminator
        # so that superdynamic systems can feed the discriminator to
        # the introspection system to get info about it
        view = self.match(context, request)
        return view.__discriminator__(context, request)

    def add(self, view, order, accept=None, phash=None):
        if phash is not None:
            for i, (s, v, h) in enumerate(list(self.views)):
                if phash == h:
                    self.views[i] = (order, view, phash)
                    return

        if accept is None or '*' in accept:
            self.views.append((order, view, phash))
            self.views.sort(key=operator.itemgetter(0))
        else:
            subset = self.media_views.setdefault(accept, [])
            for i, (s, v, h) in enumerate(list(subset)):
                if phash == h:
                    subset[i] = (order, view, phash)
                    return
            else:
                subset.append((order, view, phash))
                subset.sort(key=operator.itemgetter(0))
            accepts = set(self.accepts)
            accepts.add(accept)
            self.accepts = list(accepts) # dedupe

    def get_views(self, request):
        if self.accepts and hasattr(request, 'accept'):
            accepts = self.accepts[:]
            views = []
            while accepts:
                match = request.accept.best_match(accepts)
                if match is None:
                    break
                subset = self.media_views[match]
                views.extend(subset)
                accepts.remove(match)
            views.extend(self.views)
            return views
        return self.views

    def match(self, context, request):
        for order, view, phash in self.get_views(request):
            if not hasattr(view, '__predicated__'):
                return view
            if view.__predicated__(context, request):
                return view
        raise PredicateMismatch(self.name)

    def __permitted__(self, context, request):
        view = self.match(context, request)
        if hasattr(view, '__permitted__'):
            return view.__permitted__(context, request)
        return True

    def __call_permissive__(self, context, request):
        view = self.match(context, request)
        view = getattr(view, '__call_permissive__', view)
        return view(context, request)

    def __call__(self, context, request):
        for order, view, phash in self.get_views(request):
            try:
                return view(context, request)
            except PredicateMismatch:
                continue
        raise PredicateMismatch(self.name)

class ViewsConfiguratorMixin(object):
    @viewdefaults
    @action_method
    def add_view(
        self,
        view=None,
        name="",
        for_=None,
        permission=None,
        request_type=None,
        route_name=None,
        request_method=None,
        request_param=None,
        containment=None,
        attr=None,
        renderer=None,
        wrapper=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        context=None,
        decorator=None,
        mapper=None,
        http_cache=None,
        match_param=None,
        check_csrf=None,
        require_csrf=None,
        **view_options):
        """ Add a :term:`view configuration` to the current
        configuration state.  Arguments to ``add_view`` are broken
        down below into *predicate* arguments and *non-predicate*
        arguments.  Predicate arguments narrow the circumstances in
        which the view callable will be invoked when a request is
        presented to :app:`Pyramid`; non-predicate arguments are
        informational.

        Non-Predicate Arguments

        view

          A :term:`view callable` or a :term:`dotted Python name`
          which refers to a view callable.  This argument is required
          unless a ``renderer`` argument also exists.  If a
          ``renderer`` argument is passed, and a ``view`` argument is
          not provided, the view callable defaults to a callable that
          returns an empty dictionary (see
          :ref:`views_which_use_a_renderer`).

        permission

          A :term:`permission` that the user must possess in order to invoke
          the :term:`view callable`.  See :ref:`view_security_section` for
          more information about view security and permissions.  This is
          often a string like ``view`` or ``edit``.

          If ``permission`` is omitted, a *default* permission may be used
          for this view registration if one was named as the
          :class:`pyramid.config.Configurator` constructor's
          ``default_permission`` argument, or if
          :meth:`pyramid.config.Configurator.set_default_permission` was used
          prior to this view registration.  Pass the value
          :data:`pyramid.security.NO_PERMISSION_REQUIRED` as the permission
          argument to explicitly indicate that the view should always be
          executable by entirely anonymous users, regardless of the default
          permission, bypassing any :term:`authorization policy` that may be
          in effect.

        attr

          This knob is most useful when the view definition is a class.

          The view machinery defaults to using the ``__call__`` method
          of the :term:`view callable` (or the function itself, if the
          view callable is a function) to obtain a response.  The
          ``attr`` value allows you to vary the method attribute used
          to obtain the response.  For example, if your view was a
          class, and the class has a method named ``index`` and you
          wanted to use this method instead of the class' ``__call__``
          method to return the response, you'd say ``attr="index"`` in the
          view configuration for the view.

        renderer

          This is either a single string term (e.g. ``json``) or a
          string implying a path or :term:`asset specification`
          (e.g. ``templates/views.pt``) naming a :term:`renderer`
          implementation.  If the ``renderer`` value does not contain
          a dot ``.``, the specified string will be used to look up a
          renderer implementation, and that renderer implementation
          will be used to construct a response from the view return
          value.  If the ``renderer`` value contains a dot (``.``),
          the specified term will be treated as a path, and the
          filename extension of the last element in the path will be
          used to look up the renderer implementation, which will be
          passed the full path.  The renderer implementation will be
          used to construct a :term:`response` from the view return
          value.

          Note that if the view itself returns a :term:`response` (see
          :ref:`the_response`), the specified renderer implementation
          is never called.

          When the renderer is a path, although a path is usually just
          a simple relative pathname (e.g. ``templates/foo.pt``,
          implying that a template named "foo.pt" is in the
          "templates" directory relative to the directory of the
          current :term:`package` of the Configurator), a path can be
          absolute, starting with a slash on UNIX or a drive letter
          prefix on Windows.  The path can alternately be a
          :term:`asset specification` in the form
          ``some.dotted.package_name:relative/path``, making it
          possible to address template assets which live in a
          separate package.

          The ``renderer`` attribute is optional.  If it is not
          defined, the "null" renderer is assumed (no rendering is
          performed and the value is passed back to the upstream
          :app:`Pyramid` machinery unmodified).

        http_cache

          .. versionadded:: 1.1

          When you supply an ``http_cache`` value to a view configuration,
          the ``Expires`` and ``Cache-Control`` headers of a response
          generated by the associated view callable are modified.  The value
          for ``http_cache`` may be one of the following:

          - A nonzero integer.  If it's a nonzero integer, it's treated as a
            number of seconds.  This number of seconds will be used to
            compute the ``Expires`` header and the ``Cache-Control:
            max-age`` parameter of responses to requests which call this view.
            For example: ``http_cache=3600`` instructs the requesting browser
            to 'cache this response for an hour, please'.

          - A ``datetime.timedelta`` instance.  If it's a
            ``datetime.timedelta`` instance, it will be converted into a
            number of seconds, and that number of seconds will be used to
            compute the ``Expires`` header and the ``Cache-Control:
            max-age`` parameter of responses to requests which call this view.
            For example: ``http_cache=datetime.timedelta(days=1)`` instructs
            the requesting browser to 'cache this response for a day, please'.

          - Zero (``0``).  If the value is zero, the ``Cache-Control`` and
            ``Expires`` headers present in all responses from this view will
            be composed such that client browser cache (and any intermediate
            caches) are instructed to never cache the response.

          - A two-tuple.  If it's a two tuple (e.g. ``http_cache=(1,
            {'public':True})``), the first value in the tuple may be a
            nonzero integer or a ``datetime.timedelta`` instance; in either
            case this value will be used as the number of seconds to cache
            the response.  The second value in the tuple must be a
            dictionary.  The values present in the dictionary will be used as
            input to the ``Cache-Control`` response header.  For example:
            ``http_cache=(3600, {'public':True})`` means 'cache for an hour,
            and add ``public`` to the Cache-Control header of the response'.
            All keys and values supported by the
            ``webob.cachecontrol.CacheControl`` interface may be added to the
            dictionary.  Supplying ``{'public':True}`` is equivalent to
            calling ``response.cache_control.public = True``.

          Providing a non-tuple value as ``http_cache`` is equivalent to
          calling ``response.cache_expires(value)`` within your view's body.

          Providing a two-tuple value as ``http_cache`` is equivalent to
          calling ``response.cache_expires(value[0], **value[1])`` within your
          view's body.

          If you wish to avoid influencing, the ``Expires`` header, and
          instead wish to only influence ``Cache-Control`` headers, pass a
          tuple as ``http_cache`` with the first element of ``None``, e.g.:
          ``(None, {'public':True})``.

          If you wish to prevent a view that uses ``http_cache`` in its
          configuration from having its caching response headers changed by
          this machinery, set ``response.cache_control.prevent_auto = True``
          before returning the response from the view.  This effectively
          disables any HTTP caching done by ``http_cache`` for that response.

        require_csrf

          .. versionadded:: 1.7

          A boolean option or ``None``. Default: ``None``.

          If this option is set to ``True`` then CSRF checks will be enabled
          for requests to this view. The required token or header default to
          ``csrf_token`` and ``X-CSRF-Token``, respectively.

          CSRF checks only affect "unsafe" methods as defined by RFC2616. By
          default, these methods are anything except
          ``GET``, ``HEAD``, ``OPTIONS``, and ``TRACE``.

          The defaults here may be overridden by
          :meth:`pyramid.config.Configurator.set_default_csrf_options`.

          This feature requires a configured :term:`session factory`.

          If this option is set to ``False`` then CSRF checks will be disabled
          regardless of the default ``require_csrf`` setting passed
          to ``set_default_csrf_options``.

          See :ref:`auto_csrf_checking` for more information.

        wrapper

          The :term:`view name` of a different :term:`view
          configuration` which will receive the response body of this
          view as the ``request.wrapped_body`` attribute of its own
          :term:`request`, and the :term:`response` returned by this
          view as the ``request.wrapped_response`` attribute of its
          own request.  Using a wrapper makes it possible to "chain"
          views together to form a composite response.  The response
          of the outermost wrapper view will be returned to the user.
          The wrapper view will be found as any view is found: see
          :ref:`view_lookup`.  The "best" wrapper view will be found
          based on the lookup ordering: "under the hood" this wrapper
          view is looked up via
          ``pyramid.view.render_view_to_response(context, request,
          'wrapper_viewname')``. The context and request of a wrapper
          view is the same context and request of the inner view.  If
          this attribute is unspecified, no view wrapping is done.

        decorator

          A :term:`dotted Python name` to function (or the function itself,
          or an iterable of the aforementioned) which will be used to
          decorate the registered :term:`view callable`.  The decorator
          function(s) will be called with the view callable as a single
          argument.  The view callable it is passed will accept
          ``(context, request)``.  The decorator(s) must return a
          replacement view callable which also accepts ``(context,
          request)``.

          If decorator is an iterable, the callables will be combined and
          used in the order provided as a decorator.
          For example::

            @view_config(...,
                decorator=(decorator2,
                           decorator1))
            def myview(request):
                ....

          Is similar to doing::

            @view_config(...)
            @decorator2
            @decorator1
            def myview(request):
                ...

          Except with the existing benefits of ``decorator=`` (having a common
          decorator syntax for all view calling conventions and not having to
          think about preserving function attributes such as ``__name__`` and
          ``__module__`` within decorator logic).

          All view callables in the decorator chain must return a response
          object implementing :class:`pyramid.interfaces.IResponse` or raise
          an exception:

          .. code-block:: python

             def log_timer(wrapped):
                 def wrapper(context, request):
                     start = time.time()
                     response = wrapped(context, request)
                     duration = time.time() - start
                     response.headers['X-View-Time'] = '%.3f' % (duration,)
                     log.info('view took %.3f seconds', duration)
                     return response
                 return wrapper

          .. versionchanged:: 1.4a4
             Passing an iterable.

        mapper

          A Python object or :term:`dotted Python name` which refers to a
          :term:`view mapper`, or ``None``.  By default it is ``None``, which
          indicates that the view should use the default view mapper.  This
          plug-point is useful for Pyramid extension developers, but it's not
          very useful for 'civilians' who are just developing stock Pyramid
          applications. Pay no attention to the man behind the curtain.

        accept

          This value represents a match query for one or more mimetypes in the
          ``Accept`` HTTP request header.  If this value is specified, it must
          be in one of the following forms: a mimetype match token in the form
          ``text/plain``, a wildcard mimetype match token in the form
          ``text/*`` or a match-all wildcard mimetype match token in the form
          ``*/*``.  If any of the forms matches the ``Accept`` header of the
          request, or if the ``Accept`` header isn't set at all in the request,
          this will match the current view. If this does not match the
          ``Accept`` header of the request, view matching continues.

        Predicate Arguments

        name

          The :term:`view name`.  Read :ref:`traversal_chapter` to
          understand the concept of a view name.

        context

          An object or a :term:`dotted Python name` referring to an
          interface or class object that the :term:`context` must be
          an instance of, *or* the :term:`interface` that the
          :term:`context` must provide in order for this view to be
          found and called.  This predicate is true when the
          :term:`context` is an instance of the represented class or
          if the :term:`context` provides the represented interface;
          it is otherwise false.  This argument may also be provided
          to ``add_view`` as ``for_`` (an older, still-supported
          spelling).

        route_name

          This value must match the ``name`` of a :term:`route
          configuration` declaration (see :ref:`urldispatch_chapter`)
          that must match before this view will be called.

        request_type

          This value should be an :term:`interface` that the
          :term:`request` must provide in order for this view to be
          found and called.  This value exists only for backwards
          compatibility purposes.

        request_method

          This value can be either a string (such as ``"GET"``, ``"POST"``,
          ``"PUT"``, ``"DELETE"``, ``"HEAD"`` or ``"OPTIONS"``) representing
          an HTTP ``REQUEST_METHOD``, or a tuple containing one or more of
          these strings.  A view declaration with this argument ensures that
          the view will only be called when the ``method`` attribute of the
          request (aka the ``REQUEST_METHOD`` of the WSGI environment) matches
          a supplied value.  Note that use of ``GET`` also implies that the
          view will respond to ``HEAD`` as of Pyramid 1.4.

          .. versionchanged:: 1.2
             The ability to pass a tuple of items as ``request_method``.
             Previous versions allowed only a string.

        request_param

          This value can be any string or any sequence of strings.  A view
          declaration with this argument ensures that the view will only be
          called when the :term:`request` has a key in the ``request.params``
          dictionary (an HTTP ``GET`` or ``POST`` variable) that has a
          name which matches the supplied value (if the value is a string)
          or values (if the value is a tuple).  If any value
          supplied has a ``=`` sign in it,
          e.g. ``request_param="foo=123"``, then the key (``foo``)
          must both exist in the ``request.params`` dictionary, *and*
          the value must match the right hand side of the expression
          (``123``) for the view to "match" the current request.

        match_param

          .. versionadded:: 1.2

          This value can be a string of the format "key=value" or a tuple
          containing one or more of these strings.

          A view declaration with this argument ensures that the view will
          only be called when the :term:`request` has key/value pairs in its
          :term:`matchdict` that equal those supplied in the predicate.
          e.g. ``match_param="action=edit"`` would require the ``action``
          parameter in the :term:`matchdict` match the right hand side of
          the expression (``edit``) for the view to "match" the current
          request.

          If the ``match_param`` is a tuple, every key/value pair must match
          for the predicate to pass.

        containment

          This value should be a Python class or :term:`interface` (or a
          :term:`dotted Python name`) that an object in the
          :term:`lineage` of the context must provide in order for this view
          to be found and called.  The nodes in your object graph must be
          "location-aware" to use this feature.  See
          :ref:`location_aware` for more information about
          location-awareness.

        xhr

          This value should be either ``True`` or ``False``.  If this
          value is specified and is ``True``, the :term:`request`
          must possess an ``HTTP_X_REQUESTED_WITH`` (aka
          ``X-Requested-With``) header that has the value
          ``XMLHttpRequest`` for this view to be found and called.
          This is useful for detecting AJAX requests issued from
          jQuery, Prototype and other Javascript libraries.

        header

          This value represents an HTTP header name or a header
          name/value pair.  If the value contains a ``:`` (colon), it
          will be considered a name/value pair
          (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``).  The
          value portion should be a regular expression.  If the value
          does not contain a colon, the entire value will be
          considered to be the header name
          (e.g. ``If-Modified-Since``).  If the value evaluates to a
          header name only without a value, the header specified by
          the name must be present in the request for this predicate
          to be true.  If the value evaluates to a header name/value
          pair, the header specified by the name must be present in
          the request *and* the regular expression specified as the
          value must match the header value.  Whether or not the value
          represents a header name or a header name/value pair, the
          case of the header name is not significant.

        path_info

          This value represents a regular expression pattern that will
          be tested against the ``PATH_INFO`` WSGI environment
          variable.  If the regex matches, this predicate will be
          ``True``.

        check_csrf

          .. deprecated:: 1.7
             Use the ``require_csrf`` option or see :ref:`auto_csrf_checking`
             instead to have :class:`pyramid.exceptions.BadCSRFToken`
             exceptions raised.

          If specified, this value should be one of ``None``, ``True``,
          ``False``, or a string representing the 'check name'.  If the value
          is ``True`` or a string, CSRF checking will be performed.  If the
          value is ``False`` or ``None``, CSRF checking will not be performed.

          If the value provided is a string, that string will be used as the
          'check name'.  If the value provided is ``True``, ``csrf_token`` will
          be used as the check name.

          If CSRF checking is performed, the checked value will be the value
          of ``request.params[check_name]``.  This value will be compared
          against the value of ``request.session.get_csrf_token()``, and the
          check will pass if these two values are the same.  If the check
          passes, the associated view will be permitted to execute.  If the
          check fails, the associated view will not be permitted to execute.

          Note that using this feature requires a :term:`session factory` to
          have been configured.

          .. versionadded:: 1.4a2

        physical_path

          If specified, this value should be a string or a tuple representing
          the :term:`physical path` of the context found via traversal for this
          predicate to match as true.  For example: ``physical_path='/'`` or
          ``physical_path='/a/b/c'`` or ``physical_path=('', 'a', 'b', 'c')``.
          This is not a path prefix match or a regex, it's a whole-path match.
          It's useful when you want to always potentially show a view when some
          object is traversed to, but you can't be sure about what kind of
          object it will be, so you can't use the ``context`` predicate.  The
          individual path elements inbetween slash characters or in tuple
          elements should be the Unicode representation of the name of the
          resource and should not be encoded in any way.

          .. versionadded:: 1.4a3

        effective_principals

          If specified, this value should be a :term:`principal` identifier or
          a sequence of principal identifiers.  If the
          :attr:`pyramid.request.Request.effective_principals` property
          indicates that every principal named in the argument list is present
          in the current request, this predicate will return True; otherwise it
          will return False.  For example:
          ``effective_principals=pyramid.security.Authenticated`` or
          ``effective_principals=('fred', 'group:admins')``.

          .. versionadded:: 1.4a4

        custom_predicates

            .. deprecated:: 1.5
                This value should be a sequence of references to custom
                predicate callables.  Use custom predicates when no set of
                predefined predicates do what you need.  Custom predicates
                can be combined with predefined predicates as necessary.
                Each custom predicate callable should accept two arguments:
                ``context`` and ``request`` and should return either
                ``True`` or ``False`` after doing arbitrary evaluation of
                the context and/or the request.  The ``predicates`` argument
                to this method and the ability to register third-party view
                predicates via
                :meth:`pyramid.config.Configurator.add_view_predicate`
                obsoletes this argument, but it is kept around for backwards
                compatibility.

        view_options:

          Pass a key/value pair here to use a third-party predicate or set a
          value for a view deriver. See
          :meth:`pyramid.config.Configurator.add_view_predicate` and
          :meth:`pyramid.config.Configurator.add_view_deriver`. See
          :ref:`view_and_route_predicates` for more information about
          third-party predicates and :ref:`view_derivers` for information
          about view derivers.

          .. versionadded: 1.4a1

          .. versionchanged: 1.7

             Support setting view deriver options. Previously, only custom
             view predicate values could be supplied.

        """
        if custom_predicates:
            warnings.warn(
                ('The "custom_predicates" argument to Configurator.add_view '
                 'is deprecated as of Pyramid 1.5.  Use '
                 '"config.add_view_predicate" and use the registered '
                 'view predicate as a predicate argument to add_view instead. '
                 'See "Adding A Third Party View, Route, or Subscriber '
                 'Predicate" in the "Hooks" chapter of the documentation '
                 'for more information.'),
                DeprecationWarning,
                stacklevel=4,
                )

        if check_csrf is not None:
            warnings.warn(
                ('The "check_csrf" argument to Configurator.add_view is '
                 'deprecated as of Pyramid 1.7. Use the "require_csrf" option '
                 'instead or see "Checking CSRF Tokens Automatically" in the '
                 '"Sessions" chapter of the documentation for more '
                 'information.'),
                DeprecationWarning,
                stacklevel=4,
                )

        view = self.maybe_dotted(view)
        context = self.maybe_dotted(context)
        for_ = self.maybe_dotted(for_)
        containment = self.maybe_dotted(containment)
        mapper = self.maybe_dotted(mapper)

        def combine(*decorators):
            def decorated(view_callable):
                # reversed() allows a more natural ordering in the api
                for decorator in reversed(decorators):
                    view_callable = decorator(view_callable)
                return view_callable
            return decorated

        if is_nonstr_iter(decorator):
            decorator = combine(*map(self.maybe_dotted, decorator))
        else:
            decorator = self.maybe_dotted(decorator)

        if not view:
            if renderer:
                def view(context, request):
                    return {}
            else:
                raise ConfigurationError('"view" was not specified and '
                                         'no "renderer" specified')

        if request_type is not None:
            request_type = self.maybe_dotted(request_type)
            if not IInterface.providedBy(request_type):
                raise ConfigurationError(
                    'request_type must be an interface, not %s' % request_type)

        if context is None:
            context = for_

        r_context = context
        if r_context is None:
            r_context = Interface
        if not IInterface.providedBy(r_context):
            r_context = implementedBy(r_context)

        if isinstance(renderer, string_types):
            renderer = renderers.RendererHelper(
                name=renderer, package=self.package,
                registry=self.registry)

        if accept is not None:
            accept = accept.lower()

        introspectables = []
        ovals = view_options.copy()
        ovals.update(dict(
            xhr=xhr,
            request_method=request_method,
            path_info=path_info,
            request_param=request_param,
            header=header,
            accept=accept,
            containment=containment,
            request_type=request_type,
            match_param=match_param,
            check_csrf=check_csrf,
            custom=predvalseq(custom_predicates),
        ))

        def discrim_func():
            # We need to defer the discriminator until we know what the phash
            # is.  It can't be computed any sooner because thirdparty
            # predicates/view derivers may not yet exist when add_view is
            # called.
            valid_predicates = predlist.names()
            pvals = {}
            dvals = {}

            for (k, v) in ovals.items():
                if k in valid_predicates:
                    pvals[k] = v
                else:
                    dvals[k] = v

            self._check_view_options(**dvals)

            order, preds, phash = predlist.make(self, **pvals)

            view_intr.update({
                'phash': phash,
                'order': order,
                'predicates': preds,
                })
            return ('view', context, name, route_name, phash)

        discriminator = Deferred(discrim_func)

        if inspect.isclass(view) and attr:
            view_desc = 'method %r of %s' % (
                attr, self.object_description(view))
        else:
            view_desc = self.object_description(view)

        tmpl_intr = None

        view_intr = self.introspectable('views',
                                        discriminator,
                                        view_desc,
                                        'view')
        view_intr.update(dict(
            name=name,
            context=context,
            containment=containment,
            request_param=request_param,
            request_methods=request_method,
            route_name=route_name,
            attr=attr,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            match_param=match_param,
            check_csrf=check_csrf,
            http_cache=http_cache,
            require_csrf=require_csrf,
            callable=view,
            mapper=mapper,
            decorator=decorator,
        ))
        view_intr.update(view_options)
        introspectables.append(view_intr)
        predlist = self.get_predlist('view')

        def register(permission=permission, renderer=renderer):
            request_iface = IRequest
            if route_name is not None:
                request_iface = self.registry.queryUtility(IRouteRequest,
                                                           name=route_name)
                if request_iface is None:
                    # route configuration should have already happened in
                    # phase 2
                    raise ConfigurationError(
                        'No route named %s found for view registration' %
                        route_name)

            if renderer is None:
                # use default renderer if one exists (reg'd in phase 1)
                if self.registry.queryUtility(IRendererFactory) is not None:
                    renderer = renderers.RendererHelper(
                        name=None,
                        package=self.package,
                        registry=self.registry
                        )

            # added by discrim_func above during conflict resolving
            preds = view_intr['predicates']
            order = view_intr['order']
            phash = view_intr['phash']

            # __no_permission_required__ handled by _secure_view
            derived_view = self._derive_view(
                view,
                permission=permission,
                predicates=preds,
                attr=attr,
                context=context,
                renderer=renderer,
                wrapper_viewname=wrapper,
                viewname=name,
                accept=accept,
                order=order,
                phash=phash,
                decorator=decorator,
                mapper=mapper,
                http_cache=http_cache,
                require_csrf=require_csrf,
                extra_options=ovals,
            )
            derived_view.__discriminator__ = lambda *arg: discriminator
            # __discriminator__ is used by superdynamic systems
            # that require it for introspection after manual view lookup;
            # see also MultiView.__discriminator__
            view_intr['derived_callable'] = derived_view

            registered = self.registry.adapters.registered

            # A multiviews is a set of views which are registered for
            # exactly the same context type/request type/name triad.  Each
            # consituent view in a multiview differs only by the
            # predicates which it possesses.

            # To find a previously registered view for a context
            # type/request type/name triad, we need to use the
            # ``registered`` method of the adapter registry rather than
            # ``lookup``.  ``registered`` ignores interface inheritance
            # for the required and provided arguments, returning only a
            # view registered previously with the *exact* triad we pass
            # in.

            # We need to do this three times, because we use three
            # different interfaces as the ``provided`` interface while
            # doing registrations, and ``registered`` performs exact
            # matches on all the arguments it receives.

            old_view = None

            for view_type in (IView, ISecuredView, IMultiView):
                old_view = registered((IViewClassifier, request_iface,
                                       r_context), view_type, name)
                if old_view is not None:
                    break

            isexc = isexception(context)

            def regclosure():
                if hasattr(derived_view, '__call_permissive__'):
                    view_iface = ISecuredView
                else:
                    view_iface = IView
                self.registry.registerAdapter(
                    derived_view,
                    (IViewClassifier, request_iface, context), view_iface, name
                    )
                if isexc:
                    self.registry.registerAdapter(
                        derived_view,
                        (IExceptionViewClassifier, request_iface, context),
                        view_iface, name)

            is_multiview = IMultiView.providedBy(old_view)
            old_phash = getattr(old_view, '__phash__', DEFAULT_PHASH)

            if old_view is None:
                # - No component was yet registered for any of our I*View
                #   interfaces exactly; this is the first view for this
                #   triad.
                regclosure()

            elif (not is_multiview) and (old_phash == phash):
                # - A single view component was previously registered with
                #   the same predicate hash as this view; this registration
                #   is therefore an override.
                regclosure()

            else:
                # - A view or multiview was already registered for this
                #   triad, and the new view is not an override.

                # XXX we could try to be more efficient here and register
                # a non-secured view for a multiview if none of the
                # multiview's consituent views have a permission
                # associated with them, but this code is getting pretty
                # rough already
                if is_multiview:
                    multiview = old_view
                else:
                    multiview = MultiView(name)
                    old_accept = getattr(old_view, '__accept__', None)
                    old_order = getattr(old_view, '__order__', MAX_ORDER)
                    multiview.add(old_view, old_order, old_accept, old_phash)
                multiview.add(derived_view, order, accept, phash)
                for view_type in (IView, ISecuredView):
                    # unregister any existing views
                    self.registry.adapters.unregister(
                        (IViewClassifier, request_iface, r_context),
                        view_type, name=name)
                    if isexc:
                        self.registry.adapters.unregister(
                            (IExceptionViewClassifier, request_iface,
                             r_context), view_type, name=name)
                self.registry.registerAdapter(
                    multiview,
                    (IViewClassifier, request_iface, context),
                    IMultiView, name=name)
                if isexc:
                    self.registry.registerAdapter(
                        multiview,
                        (IExceptionViewClassifier, request_iface, context),
                        IMultiView, name=name)

            self.registry._clear_view_lookup_cache()
            renderer_type = getattr(renderer, 'type', None) # gard against None
            intrspc = self.introspector
            if (
                renderer_type is not None and
                tmpl_intr is not None and
                intrspc is not None and
                intrspc.get('renderer factories', renderer_type) is not None
                ):
                # allow failure of registered template factories to be deferred
                # until view execution, like other bad renderer factories; if
                # we tried to relate this to an existing renderer factory
                # without checking if it the factory actually existed, we'd end
                # up with a KeyError at startup time, which is inconsistent
                # with how other bad renderer registrations behave (they throw
                # a ValueError at view execution time)
                tmpl_intr.relate('renderer factories', renderer.type)

        if mapper:
            mapper_intr = self.introspectable(
                'view mappers',
                discriminator,
                'view mapper for %s' % view_desc,
                'view mapper'
                )
            mapper_intr['mapper'] = mapper
            mapper_intr.relate('views', discriminator)
            introspectables.append(mapper_intr)
        if route_name:
            view_intr.relate('routes', route_name) # see add_route
        if renderer is not None and renderer.name and '.' in renderer.name:
            # the renderer is a template
            tmpl_intr = self.introspectable(
                'templates',
                discriminator,
                renderer.name,
                'template'
                )
            tmpl_intr.relate('views', discriminator)
            tmpl_intr['name'] = renderer.name
            tmpl_intr['type'] = renderer.type
            tmpl_intr['renderer'] = renderer
            introspectables.append(tmpl_intr)
        if permission is not None:
            # if a permission exists, register a permission introspectable
            perm_intr = self.introspectable(
                'permissions',
                permission,
                permission,
                'permission'
                )
            perm_intr['value'] = permission
            perm_intr.relate('views', discriminator)
            introspectables.append(perm_intr)
        self.action(discriminator, register, introspectables=introspectables)

    def _check_view_options(self, **kw):
        # we only need to validate deriver options because the predicates
        # were checked by the predlist
        derivers = self.registry.getUtility(IViewDerivers)
        for deriver in derivers.values():
            for opt in getattr(deriver, 'options', []):
                kw.pop(opt, None)
        if kw:
            raise ConfigurationError('Unknown view options: %s' % (kw,))

    def _apply_view_derivers(self, info):
        d = pyramid.viewderivers

        # These derivers are not really derivers and so have fixed order
        outer_derivers = [('attr_wrapped_view', d.attr_wrapped_view),
                          ('predicated_view', d.predicated_view)]

        view = info.original_view
        derivers = self.registry.getUtility(IViewDerivers)
        for name, deriver in reversed(outer_derivers + derivers.sorted()):
            view = wraps_view(deriver)(view, info)
        return view

    @action_method
    def add_view_predicate(self, name, factory, weighs_more_than=None,
                           weighs_less_than=None):
        """
        .. versionadded:: 1.4

        Adds a view predicate factory.  The associated view predicate can
        later be named as a keyword argument to
        :meth:`pyramid.config.Configurator.add_view` in the
        ``predicates`` anonyous keyword argument dictionary.

        ``name`` should be the name of the predicate.  It must be a valid
        Python identifier (it will be used as a keyword argument to
        ``add_view`` by others).

        ``factory`` should be a :term:`predicate factory` or :term:`dotted
        Python name` which refers to a predicate factory.

        See :ref:`view_and_route_predicates` for more information.
        """
        self._add_predicate(
            'view',
            name,
            factory,
            weighs_more_than=weighs_more_than,
            weighs_less_than=weighs_less_than
            )

    def add_default_view_predicates(self):
        p = pyramid.config.predicates
        for (name, factory) in (
            ('xhr', p.XHRPredicate),
            ('request_method', p.RequestMethodPredicate),
            ('path_info', p.PathInfoPredicate),
            ('request_param', p.RequestParamPredicate),
            ('header', p.HeaderPredicate),
            ('accept', p.AcceptPredicate),
            ('containment', p.ContainmentPredicate),
            ('request_type', p.RequestTypePredicate),
            ('match_param', p.MatchParamPredicate),
            ('check_csrf', p.CheckCSRFTokenPredicate),
            ('physical_path', p.PhysicalPathPredicate),
            ('effective_principals', p.EffectivePrincipalsPredicate),
            ('custom', p.CustomPredicate),
            ):
            self.add_view_predicate(name, factory)

    @action_method
    def add_view_deriver(self, deriver, name=None, under=None, over=None):
        """
        .. versionadded:: 1.7

        Add a :term:`view deriver` to the view pipeline. View derivers are
        a feature used by extension authors to wrap views in custom code
        controllable by view-specific options.

        ``deriver`` should be a callable conforming to the
        :class:`pyramid.interfaces.IViewDeriver` interface.

        ``name`` should be the name of the view deriver.  There are no
        restrictions on the name of a view deriver. If left unspecified, the
        name will be constructed from the name of the ``deriver``.

        The ``under`` and ``over`` options can be used to control the ordering
        of view derivers by providing hints about where in the view pipeline
        the deriver is used. Each option may be a string or a list of strings.
        At least one view deriver in each, the over and under directions, must
        exist to fully satisfy the constraints.

        ``under`` means closer to the user-defined :term:`view callable`,
        and ``over`` means closer to view pipeline ingress.

        The default value for ``over`` is ``rendered_view`` and ``under`` is
        ``decorated_view``. This places the deriver somewhere between the two
        in the view pipeline. If the deriver should be placed elsewhere in the
        pipeline, such as above ``decorated_view``, then you MUST also specify
        ``under`` to something earlier in the order, or a
        ``CyclicDependencyError`` will be raised when trying to sort the
        derivers.

        See :ref:`view_derivers` for more information.

        """
        deriver = self.maybe_dotted(deriver)

        if name is None:
            name = deriver.__name__

        if name in (INGRESS, VIEW):
            raise ConfigurationError('%s is a reserved view deriver name'
                                     % name)

        if under is None:
            under = 'decorated_view'

        if over is None:
            over = 'rendered_view'

        over = as_sorted_tuple(over)
        under = as_sorted_tuple(under)

        if INGRESS in over:
            raise ConfigurationError('%s cannot be over INGRESS' % name)

        # ensure everything is always over mapped_view
        if VIEW in over and name != 'mapped_view':
            over = as_sorted_tuple(over + ('mapped_view',))

        if VIEW in under:
            raise ConfigurationError('%s cannot be under VIEW' % name)
        if 'mapped_view' in under:
            raise ConfigurationError('%s cannot be under "mapped_view"' % name)

        discriminator = ('view deriver', name)
        intr = self.introspectable(
            'view derivers',
            name,
            name,
            'view deriver')
        intr['name'] = name
        intr['deriver'] = deriver
        intr['under'] = under
        intr['over'] = over
        def register():
            derivers = self.registry.queryUtility(IViewDerivers)
            if derivers is None:
                derivers = TopologicalSorter(
                    default_before=None,
                    default_after=INGRESS,
                    first=INGRESS,
                    last=VIEW,
                )
                self.registry.registerUtility(derivers, IViewDerivers)
            derivers.add(name, deriver, before=over, after=under)
        self.action(discriminator, register, introspectables=(intr,),
                    order=PHASE1_CONFIG) # must be registered before add_view

    def add_default_view_derivers(self):
        d = pyramid.viewderivers
        derivers = [
            ('secured_view', d.secured_view),
            ('owrapped_view', d.owrapped_view),
            ('http_cached_view', d.http_cached_view),
            ('decorated_view', d.decorated_view),
            ('rendered_view', d.rendered_view),
            ('mapped_view', d.mapped_view),
        ]
        last = INGRESS
        for name, deriver in derivers:
            self.add_view_deriver(
                deriver,
                name=name,
                under=last,
                over=VIEW,
            )
            last = name

        # leave the csrf_view loosely coupled to the rest of the pipeline
        # by ensuring nothing in the default pipeline depends on the order
        # of the csrf_view
        self.add_view_deriver(
            d.csrf_view,
            'csrf_view',
            under='secured_view',
            over='owrapped_view',
        )

    def derive_view(self, view, attr=None, renderer=None):
        """
        Create a :term:`view callable` using the function, instance,
        or class (or :term:`dotted Python name` referring to the same)
        provided as ``view`` object.

        .. warning::

           This method is typically only used by :app:`Pyramid` framework
           extension authors, not by :app:`Pyramid` application developers.

        This is API is useful to framework extenders who create
        pluggable systems which need to register 'proxy' view
        callables for functions, instances, or classes which meet the
        requirements of being a :app:`Pyramid` view callable.  For
        example, a ``some_other_framework`` function in another
        framework may want to allow a user to supply a view callable,
        but he may want to wrap the view callable in his own before
        registering the wrapper as a :app:`Pyramid` view callable.
        Because a :app:`Pyramid` view callable can be any of a
        number of valid objects, the framework extender will not know
        how to call the user-supplied object.  Running it through
        ``derive_view`` normalizes it to a callable which accepts two
        arguments: ``context`` and ``request``.

        For example:

        .. code-block:: python

           def some_other_framework(user_supplied_view):
               config = Configurator(reg)
               proxy_view = config.derive_view(user_supplied_view)
               def my_wrapper(context, request):
                   do_something_that_mutates(request)
                   return proxy_view(context, request)
               config.add_view(my_wrapper)

        The ``view`` object provided should be one of the following:

        - A function or another non-class callable object that accepts
          a :term:`request` as a single positional argument and which
          returns a :term:`response` object.

        - A function or other non-class callable object that accepts
          two positional arguments, ``context, request`` and which
          returns a :term:`response` object.

        - A class which accepts a single positional argument in its
          constructor named ``request``, and which has a ``__call__``
          method that accepts no arguments that returns a
          :term:`response` object.

        - A class which accepts two positional arguments named
          ``context, request``, and which has a ``__call__`` method
          that accepts no arguments that returns a :term:`response`
          object.

        - A :term:`dotted Python name` which refers to any of the
          kinds of objects above.

        This API returns a callable which accepts the arguments
        ``context, request`` and which returns the result of calling
        the provided ``view`` object.

        The ``attr`` keyword argument is most useful when the view
        object is a class.  It names the method that should be used as
        the callable.  If ``attr`` is not provided, the attribute
        effectively defaults to ``__call__``.  See
        :ref:`class_as_view` for more information.

        The ``renderer`` keyword argument should be a renderer
        name. If supplied, it will cause the returned callable to use
        a :term:`renderer` to convert the user-supplied view result to
        a :term:`response` object.  If a ``renderer`` argument is not
        supplied, the user-supplied view must itself return a
        :term:`response` object.  """
        return self._derive_view(view, attr=attr, renderer=renderer)

    # b/w compat
    def _derive_view(self, view, permission=None, predicates=(),
                     attr=None, renderer=None, wrapper_viewname=None,
                     viewname=None, accept=None, order=MAX_ORDER,
                     phash=DEFAULT_PHASH, decorator=None,
                     mapper=None, http_cache=None, context=None,
                     require_csrf=None, extra_options=None):
        view = self.maybe_dotted(view)
        mapper = self.maybe_dotted(mapper)
        if isinstance(renderer, string_types):
            renderer = renderers.RendererHelper(
                name=renderer, package=self.package,
                registry=self.registry)
        if renderer is None:
            # use default renderer if one exists
            if self.registry.queryUtility(IRendererFactory) is not None:
                renderer = renderers.RendererHelper(
                    name=None,
                    package=self.package,
                    registry=self.registry)

        options = dict(
            view=view,
            context=context,
            permission=permission,
            attr=attr,
            renderer=renderer,
            wrapper=wrapper_viewname,
            name=viewname,
            accept=accept,
            mapper=mapper,
            decorator=decorator,
            http_cache=http_cache,
            require_csrf=require_csrf,
        )
        if extra_options:
            options.update(extra_options)

        info = ViewDeriverInfo(
            view=view,
            registry=self.registry,
            package=self.package,
            predicates=predicates,
            options=options,
        )

        # order and phash are only necessary for the predicated view and
        # are not really view deriver options
        info.order = order
        info.phash = phash

        return self._apply_view_derivers(info)

    @viewdefaults
    @action_method
    def add_forbidden_view(
        self,
        view=None,
        attr=None,
        renderer=None,
        wrapper=None,
        route_name=None,
        request_type=None,
        request_method=None,
        request_param=None,
        containment=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        decorator=None,
        mapper=None,
        match_param=None,
        **view_options
        ):
        """ Add a forbidden view to the current configuration state.  The
        view will be called when Pyramid or application code raises a
        :exc:`pyramid.httpexceptions.HTTPForbidden` exception and the set of
        circumstances implied by the predicates provided are matched.  The
        simplest example is:

          .. code-block:: python

            def forbidden(request):
                return Response('Forbidden', status='403 Forbidden')

            config.add_forbidden_view(forbidden)

        If ``view`` argument is not provided, the view callable defaults to
        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.

        All arguments have the same meaning as
        :meth:`pyramid.config.Configurator.add_view` and each predicate
        argument restricts the set of circumstances under which this forbidden
        view will be invoked.  Unlike
        :meth:`pyramid.config.Configurator.add_view`, this method will raise
        an exception if passed ``name``, ``permission``, ``context``,
        ``for_``, or ``http_cache`` keyword arguments.  These argument values
        make no sense in the context of a forbidden view.

        .. versionadded:: 1.3
        """
        for arg in (
            'name', 'permission', 'context', 'for_', 'http_cache',
            'require_csrf',
        ):
            if arg in view_options:
                raise ConfigurationError(
                    '%s may not be used as an argument to add_forbidden_view'
                    % arg
                    )

        if view is None:
            view = default_exceptionresponse_view

        settings = dict(
            view=view,
            context=HTTPForbidden,
            wrapper=wrapper,
            request_type=request_type,
            request_method=request_method,
            request_param=request_param,
            containment=containment,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            custom_predicates=custom_predicates,
            decorator=decorator,
            mapper=mapper,
            match_param=match_param,
            route_name=route_name,
            permission=NO_PERMISSION_REQUIRED,
            require_csrf=False,
            attr=attr,
            renderer=renderer,
            )
        settings.update(view_options)
        return self.add_view(**settings)

    set_forbidden_view = add_forbidden_view # deprecated sorta-bw-compat alias

    @viewdefaults
    @action_method
    def add_notfound_view(
        self,
        view=None,
        attr=None,
        renderer=None,
        wrapper=None,
        route_name=None,
        request_type=None,
        request_method=None,
        request_param=None,
        containment=None,
        xhr=None,
        accept=None,
        header=None,
        path_info=None,
        custom_predicates=(),
        decorator=None,
        mapper=None,
        match_param=None,
        append_slash=False,
        **view_options
        ):
        """ Add a default Not Found View to the current configuration state.
        The view will be called when Pyramid or application code raises an
        :exc:`pyramid.httpexceptions.HTTPNotFound` exception (e.g. when a
        view cannot be found for the request).  The simplest example is:

          .. code-block:: python

            def notfound(request):
                return Response('Not Found', status='404 Not Found')

            config.add_notfound_view(notfound)

        If ``view`` argument is not provided, the view callable defaults to
        :func:`~pyramid.httpexceptions.default_exceptionresponse_view`.

        All arguments except ``append_slash`` have the same meaning as
        :meth:`pyramid.config.Configurator.add_view` and each predicate
        argument restricts the set of circumstances under which this notfound
        view will be invoked.  Unlike
        :meth:`pyramid.config.Configurator.add_view`, this method will raise
        an exception if passed ``name``, ``permission``, ``context``,
        ``for_``, or ``http_cache`` keyword arguments.  These argument values
        make no sense in the context of a Not Found View.

        If ``append_slash`` is ``True``, when this Not Found View is invoked,
        and the current path info does not end in a slash, the notfound logic
        will attempt to find a :term:`route` that matches the request's path
        info suffixed with a slash.  If such a route exists, Pyramid will
        issue a redirect to the URL implied by the route; if it does not,
        Pyramid will return the result of the view callable provided as
        ``view``, as normal.

        If the argument provided as ``append_slash`` is not a boolean but
        instead implements :class:`~pyramid.interfaces.IResponse`, the
        append_slash logic will behave as if ``append_slash=True`` was passed,
        but the provided class will be used as the response class instead of
        the default :class:`~pyramid.httpexceptions.HTTPFound` response class
        when a redirect is performed.  For example:

          .. code-block:: python

            from pyramid.httpexceptions import HTTPMovedPermanently
            config.add_notfound_view(append_slash=HTTPMovedPermanently)

        The above means that a redirect to a slash-appended route will be
        attempted, but instead of :class:`~pyramid.httpexceptions.HTTPFound`
        being used, :class:`~pyramid.httpexceptions.HTTPMovedPermanently will
        be used` for the redirect response if a slash-appended route is found.

        .. versionchanged:: 1.6
        .. versionadded:: 1.3
        """
        for arg in (
            'name', 'permission', 'context', 'for_', 'http_cache',
            'require_csrf',
        ):
            if arg in view_options:
                raise ConfigurationError(
                    '%s may not be used as an argument to add_notfound_view'
                    % arg
                    )

        if view is None:
            view = default_exceptionresponse_view

        settings = dict(
            view=view,
            context=HTTPNotFound,
            wrapper=wrapper,
            request_type=request_type,
            request_method=request_method,
            request_param=request_param,
            containment=containment,
            xhr=xhr,
            accept=accept,
            header=header,
            path_info=path_info,
            custom_predicates=custom_predicates,
            decorator=decorator,
            mapper=mapper,
            match_param=match_param,
            route_name=route_name,
            permission=NO_PERMISSION_REQUIRED,
            require_csrf=False,
            )
        settings.update(view_options)
        if append_slash:
            view = self._derive_view(view, attr=attr, renderer=renderer)
            if IResponse.implementedBy(append_slash):
                view = AppendSlashNotFoundViewFactory(
                    view, redirect_class=append_slash,
                )
            else:
                view = AppendSlashNotFoundViewFactory(view)
            settings['view'] = view
        else:
            settings['attr'] = attr
            settings['renderer'] = renderer
        return self.add_view(**settings)

    set_notfound_view = add_notfound_view # deprecated sorta-bw-compat alias

    @action_method
    def set_view_mapper(self, mapper):
        """
        Setting a :term:`view mapper` makes it possible to make use of
        :term:`view callable` objects which implement different call
        signatures than the ones supported by :app:`Pyramid` as described in
        its narrative documentation.

        The ``mapper`` argument should be an object implementing
        :class:`pyramid.interfaces.IViewMapperFactory` or a :term:`dotted
        Python name` to such an object.  The provided ``mapper`` will become
        the default view mapper to be used by all subsequent :term:`view
        configuration` registrations.

        .. seealso::

            See also :ref:`using_a_view_mapper`.

        .. note::

           Using the ``default_view_mapper`` argument to the
           :class:`pyramid.config.Configurator` constructor
           can be used to achieve the same purpose.
        """
        mapper = self.maybe_dotted(mapper)
        def register():
            self.registry.registerUtility(mapper, IViewMapperFactory)
        # IViewMapperFactory is looked up as the result of view config
        # in phase 3
        intr = self.introspectable('view mappers',
                                   IViewMapperFactory,
                                   self.object_description(mapper),
                                   'default view mapper')
        intr['mapper'] = mapper
        self.action(IViewMapperFactory, register, order=PHASE1_CONFIG,
                    introspectables=(intr,))

    @action_method
    def add_static_view(self, name, path, **kw):
        """ Add a view used to render static assets such as images
        and CSS files.

        The ``name`` argument is a string representing an
        application-relative local URL prefix.  It may alternately be a full
        URL.

        The ``path`` argument is the path on disk where the static files
        reside.  This can be an absolute path, a package-relative path, or a
        :term:`asset specification`.

        The ``cache_max_age`` keyword argument is input to set the
        ``Expires`` and ``Cache-Control`` headers for static assets served.
        Note that this argument has no effect when the ``name`` is a *url
        prefix*.  By default, this argument is ``None``, meaning that no
        particular Expires or Cache-Control headers are set in the response.

        The ``permission`` keyword argument is used to specify the
        :term:`permission` required by a user to execute the static view.  By
        default, it is the string
        :data:`pyramid.security.NO_PERMISSION_REQUIRED`, a special sentinel
        which indicates that, even if a :term:`default permission` exists for
        the current application, the static view should be renderered to
        completely anonymous users.  This default value is permissive
        because, in most web apps, static assets seldom need protection from
        viewing.  If ``permission`` is specified, the security checking will
        be performed against the default root factory ACL.

        Any other keyword arguments sent to ``add_static_view`` are passed on
        to :meth:`pyramid.config.Configurator.add_route` (e.g. ``factory``,
        perhaps to define a custom factory with a custom ACL for this static
        view).

        *Usage*

        The ``add_static_view`` function is typically used in conjunction
        with the :meth:`pyramid.request.Request.static_url` method.
        ``add_static_view`` adds a view which renders a static asset when
        some URL is visited; :meth:`pyramid.request.Request.static_url`
        generates a URL to that asset.

        The ``name`` argument to ``add_static_view`` is usually a simple URL
        prefix (e.g. ``'images'``).  When this is the case, the
        :meth:`pyramid.request.Request.static_url` API will generate a URL
        which points to a Pyramid view, which will serve up a set of assets
        that live in the package itself. For example:

        .. code-block:: python

           add_static_view('images', 'mypackage:images/')

        Code that registers such a view can generate URLs to the view via
        :meth:`pyramid.request.Request.static_url`:

        .. code-block:: python

           request.static_url('mypackage:images/logo.png')

        When ``add_static_view`` is called with a ``name`` argument that
        represents a URL prefix, as it is above, subsequent calls to
        :meth:`pyramid.request.Request.static_url` with paths that start with
        the ``path`` argument passed to ``add_static_view`` will generate a
        URL something like ``http://<Pyramid app URL>/images/logo.png``,
        which will cause the ``logo.png`` file in the ``images`` subdirectory
        of the ``mypackage`` package to be served.

        ``add_static_view`` can alternately be used with a ``name`` argument
        which is a *URL*, causing static assets to be served from an external
        webserver.  This happens when the ``name`` argument is a fully
        qualified URL (e.g. starts with ``http://`` or similar).  In this
        mode, the ``name`` is used as the prefix of the full URL when
        generating a URL using :meth:`pyramid.request.Request.static_url`.
        Furthermore, if a protocol-relative URL (e.g. ``//example.com/images``)
        is used as the ``name`` argument, the generated URL will use the
        protocol of the request (http or https, respectively).

        For example, if ``add_static_view`` is called like so:

        .. code-block:: python

           add_static_view('http://example.com/images', 'mypackage:images/')

        Subsequently, the URLs generated by
        :meth:`pyramid.request.Request.static_url` for that static view will
        be prefixed with ``http://example.com/images`` (the external webserver
        listening on ``example.com`` must be itself configured to respond
        properly to such a request.):

        .. code-block:: python

           static_url('mypackage:images/logo.png', request)

        See :ref:`static_assets_section` for more information.
        """
        spec = self._make_spec(path)
        info = self._get_static_info()
        info.add(self, name, spec, **kw)

    def add_cache_buster(self, path, cachebust, explicit=False):
        """
        Add a cache buster to a set of files on disk.

        The ``path`` should be the path on disk where the static files
        reside.  This can be an absolute path, a package-relative path, or a
        :term:`asset specification`.

        The ``cachebust`` argument may be set to cause
        :meth:`~pyramid.request.Request.static_url` to use cache busting when
        generating URLs. See :ref:`cache_busting` for general information
        about cache busting. The value of the ``cachebust`` argument must
        be an object which implements
        :class:`~pyramid.interfaces.ICacheBuster`.

        If ``explicit`` is set to ``True`` then the ``path`` for the cache
        buster will be matched based on the ``rawspec`` instead of the
        ``pathspec`` as defined in the
        :class:`~pyramid.interfaces.ICacheBuster` interface.
        Default: ``False``.

        """
        spec = self._make_spec(path)
        info = self._get_static_info()
        info.add_cache_buster(self, spec, cachebust, explicit=explicit)

    def _get_static_info(self):
        info = self.registry.queryUtility(IStaticURLInfo)
        if info is None:
            info = StaticURLInfo()
            self.registry.registerUtility(info, IStaticURLInfo)
        return info

def isexception(o):
    if IInterface.providedBy(o):
        if IException.isEqualOrExtendedBy(o):
            return True
    return (
        isinstance(o, Exception) or
        (inspect.isclass(o) and (issubclass(o, Exception)))
        )

@implementer(IViewDeriverInfo)
class ViewDeriverInfo(object):
    def __init__(self, view, registry, package, predicates, options):
        self.original_view = view
        self.registry = registry
        self.package = package
        self.predicates = predicates or []
        self.options = options or {}

    @reify
    def settings(self):
        return self.registry.settings

@implementer(IStaticURLInfo)
class StaticURLInfo(object):
    def __init__(self):
        self.registrations = []
        self.cache_busters = []

    def generate(self, path, request, **kw):
        for (url, spec, route_name) in self.registrations:
            if path.startswith(spec):
                subpath = path[len(spec):]
                if WIN: # pragma: no cover
                    subpath = subpath.replace('\\', '/') # windows
                if self.cache_busters:
                    subpath, kw = self._bust_asset_path(
                        request, spec, subpath, kw)
                if url is None:
                    kw['subpath'] = subpath
                    return request.route_url(route_name, **kw)
                else:
                    app_url, scheme, host, port, qs, anchor = \
                        parse_url_overrides(kw)
                    parsed = url_parse(url)
                    if not parsed.scheme:
                        url = urlparse.urlunparse(parsed._replace(
                            scheme=request.environ['wsgi.url_scheme']))
                    subpath = url_quote(subpath)
                    result = urljoin(url, subpath)
                    return result + qs + anchor

        raise ValueError('No static URL definition matching %s' % path)

    def add(self, config, name, spec, **extra):
        # This feature only allows for the serving of a directory and
        # the files contained within, not of a single asset;
        # appending a slash here if the spec doesn't have one is
        # required for proper prefix matching done in ``generate``
        # (``subpath = path[len(spec):]``).
        if os.path.isabs(spec): # FBO windows
            sep = os.sep
        else:
            sep = '/'
        if not spec.endswith(sep) and not spec.endswith(':'):
            spec = spec + sep

        # we also make sure the name ends with a slash, purely as a
        # convenience: a name that is a url is required to end in a
        # slash, so that ``urljoin(name, subpath))`` will work above
        # when the name is a URL, and it doesn't hurt things for it to
        # have a name that ends in a slash if it's used as a route
        # name instead of a URL.
        if not name.endswith('/'):
            # make sure it ends with a slash
            name = name + '/'

        if url_parse(name).netloc:
            # it's a URL
            # url, spec, route_name
            url = name
            route_name = None
        else:
            # it's a view name
            url = None
            cache_max_age = extra.pop('cache_max_age', None)

            # create a view
            view = static_view(spec, cache_max_age=cache_max_age,
                               use_subpath=True)

            # Mutate extra to allow factory, etc to be passed through here.
            # Treat permission specially because we'd like to default to
            # permissiveness (see docs of config.add_static_view).
            permission = extra.pop('permission', None)
            if permission is None:
                permission = NO_PERMISSION_REQUIRED

            context = extra.pop('context', None)
            if context is None:
                context = extra.pop('for_', None)

            renderer = extra.pop('renderer', None)

            # register a route using the computed view, permission, and
            # pattern, plus any extras passed to us via add_static_view
            pattern = "%s*subpath" % name # name already ends with slash
            if config.route_prefix:
                route_name = '__%s/%s' % (config.route_prefix, name)
            else:
                route_name = '__%s' % name
            config.add_route(route_name, pattern, **extra)
            config.add_view(
                route_name=route_name,
                view=view,
                permission=permission,
                context=context,
                renderer=renderer,
            )

        def register():
            registrations = self.registrations

            names = [t[0] for t in registrations]

            if name in names:
                idx = names.index(name)
                registrations.pop(idx)

            # url, spec, route_name
            registrations.append((url, spec, route_name))

        intr = config.introspectable('static views',
                                     name,
                                     'static view for %r' % name,
                                     'static view')
        intr['name'] = name
        intr['spec'] = spec

        config.action(None, callable=register, introspectables=(intr,))

    def add_cache_buster(self, config, spec, cachebust, explicit=False):
        # ensure the spec always has a trailing slash as we only support
        # adding cache busters to folders, not files
        if os.path.isabs(spec): # FBO windows
            sep = os.sep
        else:
            sep = '/'
        if not spec.endswith(sep) and not spec.endswith(':'):
            spec = spec + sep

        def register():
            if config.registry.settings.get('pyramid.prevent_cachebust'):
                return

            cache_busters = self.cache_busters

            # find duplicate cache buster (old_idx)
            # and insertion location (new_idx)
            new_idx, old_idx = len(cache_busters), None
            for idx, (spec_, cb_, explicit_) in enumerate(cache_busters):
                # if we find an identical (spec, explicit) then use it
                if spec == spec_ and explicit == explicit_:
                    old_idx = new_idx = idx
                    break

                # past all explicit==False specs then add to the end
                elif not explicit and explicit_:
                    new_idx = idx
                    break

                # explicit matches and spec is shorter
                elif explicit == explicit_ and len(spec) < len(spec_):
                    new_idx = idx
                    break

            if old_idx is not None:
                cache_busters.pop(old_idx)

            cache_busters.insert(new_idx, (spec, cachebust, explicit))

        intr = config.introspectable('cache busters',
                                     spec,
                                     'cache buster for %r' % spec,
                                     'cache buster')
        intr['cachebust'] = cachebust
        intr['path'] = spec
        intr['explicit'] = explicit

        config.action(None, callable=register, introspectables=(intr,))

    def _bust_asset_path(self, request, spec, subpath, kw):
        registry = request.registry
        pkg_name, pkg_subpath = resolve_asset_spec(spec)
        rawspec = None

        if pkg_name is not None:
            pathspec = '{0}:{1}{2}'.format(pkg_name, pkg_subpath, subpath)
            overrides = registry.queryUtility(IPackageOverrides, name=pkg_name)
            if overrides is not None:
                resource_name = posixpath.join(pkg_subpath, subpath)
                sources = overrides.filtered_sources(resource_name)
                for source, filtered_path in sources:
                    rawspec = source.get_path(filtered_path)
                    if hasattr(source, 'pkg_name'):
                        rawspec = '{0}:{1}'.format(source.pkg_name, rawspec)
                    break

        else:
            pathspec = pkg_subpath + subpath

        if rawspec is None:
            rawspec = pathspec

        kw['pathspec'] = pathspec
        kw['rawspec'] = rawspec
        for spec_, cachebust, explicit in reversed(self.cache_busters):
            if (
                (explicit and rawspec.startswith(spec_)) or
                (not explicit and pathspec.startswith(spec_))
            ):
                subpath, kw = cachebust(request, subpath, kw)
                break
        return subpath, kw

```
--- END FILE ---

Please first localize the bug based on the issue statement, and then generate *SEARCH/REPLACE* edits to fix the issue.

Every *SEARCH/REPLACE* edit must use this format:
1. The file path
2. The start of search block: <<<<<<< SEARCH
3. A contiguous chunk of lines to search for in the existing source code
4. The dividing line: =======
5. The lines to replace into the source code
6. The end of the replace block: >>>>>>> REPLACE

Here is an example:

```python
### mathweb/flask/app.py
<<<<<<< SEARCH
from flask import Flask
=======
import math
from flask import Flask
>>>>>>> REPLACE
```
</solution>

Please note that the *SEARCH/REPLACE* edit REQUIRES PROPER INDENTATION. If you would like to add the line '        print(x)', you must fully write that out, with all those spaces before the code!
Wrap each *SEARCH/REPLACE* edit in a code block as shown in the example above. If you have multiple *SEARCH/REPLACE* edits, use a separate code block for each one.
user