summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@plope.com>2010-12-08 18:29:50 -0500
committerChris McDonough <chrism@plope.com>2010-12-08 18:29:50 -0500
commit427a02393da7c9ad5198be3c7be870662d229f83 (patch)
tree1116d6113e12ba111b57cfd72747baff4cda1958
parent421baeeef8db473a71d9c66f6e29a73afb8ee91c (diff)
downloadpyramid-427a02393da7c9ad5198be3c7be870662d229f83.tar.gz
pyramid-427a02393da7c9ad5198be3c7be870662d229f83.tar.bz2
pyramid-427a02393da7c9ad5198be3c7be870662d229f83.zip
configuration.Config->config.Configurator
-rw-r--r--pyramid/config.py2871
-rw-r--r--pyramid/configuration.py2949
-rw-r--r--pyramid/router.py69
-rw-r--r--pyramid/testing.py20
-rw-r--r--pyramid/tests/test_config.py4573
-rw-r--r--pyramid/tests/test_configuration.py4646
-rw-r--r--pyramid/tests/test_integration.py12
-rw-r--r--pyramid/tests/test_router.py73
-rw-r--r--pyramid/tests/test_util.py2
-rw-r--r--pyramid/tests/test_zcml.py8
-rw-r--r--pyramid/zcml.py36
11 files changed, 7646 insertions, 7613 deletions
diff --git a/pyramid/config.py b/pyramid/config.py
new file mode 100644
index 000000000..d7820cdd1
--- /dev/null
+++ b/pyramid/config.py
@@ -0,0 +1,2871 @@
+import inspect
+import os
+import re
+import sys
+import threading
+import traceback
+
+import venusian
+
+from translationstring import ChameleonTranslate
+
+from zope.configuration import xmlconfig
+from zope.configuration.config import GroupingContextDecorator
+from zope.configuration.config import ConfigurationMachine
+from zope.configuration.xmlconfig import registerCommonDirectives
+
+from zope.interface import Interface
+from zope.interface import implementedBy
+from zope.interface.interfaces import IInterface
+from zope.interface import implements
+
+from pyramid.interfaces import IAuthenticationPolicy
+from pyramid.interfaces import IAuthorizationPolicy
+from pyramid.interfaces import IChameleonTranslate
+from pyramid.interfaces import IDebugLogger
+from pyramid.interfaces import IDefaultPermission
+from pyramid.interfaces import IDefaultRootFactory
+from pyramid.interfaces import IException
+from pyramid.interfaces import IExceptionResponse
+from pyramid.interfaces import IExceptionViewClassifier
+from pyramid.interfaces import ILocaleNegotiator
+from pyramid.interfaces import IMultiView
+from pyramid.interfaces import IPackageOverrides
+from pyramid.interfaces import IRendererFactory
+from pyramid.interfaces import IRendererGlobalsFactory
+from pyramid.interfaces import IRequest
+from pyramid.interfaces import IRequestFactory
+from pyramid.interfaces import IRootFactory
+from pyramid.interfaces import IRouteRequest
+from pyramid.interfaces import IRoutesMapper
+from pyramid.interfaces import ISecuredView
+from pyramid.interfaces import ISessionFactory
+from pyramid.interfaces import IStaticURLInfo
+from pyramid.interfaces import ITranslationDirectories
+from pyramid.interfaces import ITraverser
+from pyramid.interfaces import IView
+from pyramid.interfaces import IViewClassifier
+
+try:
+ from pyramid import chameleon_text
+except TypeError: # pragma: no cover
+ chameleon_text = None # pypy
+try:
+ from pyramid import chameleon_zpt
+except TypeError: # pragma: no cover
+ chameleon_zpt = None # pypy
+
+from pyramid import renderers
+from pyramid.authorization import ACLAuthorizationPolicy
+from pyramid.compat import all
+from pyramid.compat import md5
+from pyramid.events import ApplicationCreated
+from pyramid.exceptions import ConfigurationError
+from pyramid.exceptions import Forbidden
+from pyramid.exceptions import NotFound
+from pyramid.exceptions import PredicateMismatch
+from pyramid.i18n import get_localizer
+from pyramid.log import make_stream_logger
+from pyramid.mako_templating import renderer_factory as mako_renderer_factory
+from pyramid.path import caller_package
+from pyramid.path import package_path
+from pyramid.path import package_of
+from pyramid.registry import Registry
+from pyramid.renderers import RendererHelper
+from pyramid.request import route_request_iface
+from pyramid.resource import PackageOverrides
+from pyramid.resource import resolve_resource_spec
+from pyramid.settings import Settings
+from pyramid.static import StaticURLInfo
+from pyramid.threadlocal import get_current_registry
+from pyramid.threadlocal import get_current_request
+from pyramid.threadlocal import manager
+from pyramid.traversal import DefaultRootFactory
+from pyramid.traversal import find_interface
+from pyramid.traversal import traversal_path
+from pyramid.urldispatch import RoutesMapper
+from pyramid.util import DottedNameResolver
+from pyramid.view import default_exceptionresponse_view
+from pyramid.view import render_view_to_response
+
+MAX_ORDER = 1 << 30
+DEFAULT_PHASH = md5().hexdigest()
+
+DEFAULT_RENDERERS = (
+ ('.mak', mako_renderer_factory),
+ ('.mako', mako_renderer_factory),
+ ('json', renderers.json_renderer_factory),
+ ('string', renderers.string_renderer_factory),
+ )
+
+if chameleon_text:
+ DEFAULT_RENDERERS += (('.pt', chameleon_zpt.renderer_factory),)
+if chameleon_zpt:
+ DEFAULT_RENDERERS += (('.txt', chameleon_text.renderer_factory),)
+
+def config_method(wrapped):
+ def wrapper(self, *arg, **kw):
+ context = self._ctx
+ if context is not None:
+ if (not context.autocommit) and (not context.info):
+ # Try to provide more accurate info for conflict reports by
+ # wrapping the context in a decorator and attaching caller info
+ # to it, unless the context already has info (if it already has
+ # info, it's likely a context generated by a ZCML directive).
+ # This is nasty.
+ newctx = GroupingContextDecorator(context)
+ try:
+ f = traceback.extract_stack(limit=3)
+ info = f[-2]
+ except:
+ info = ''
+ newctx.info = info
+ self._ctx = newctx
+ result = wrapped(self, *arg, **kw)
+ if context is not None:
+ self._ctx = context
+ return result
+ wrapper.__doc__ = wrapped.__doc__
+ wrapper.__name__ = wrapped.__name__
+ return wrapper
+
+class Configurator(object):
+ """
+ A Configurator is used to configure a :app:`Pyramid`
+ :term:`application registry`.
+
+ The Configurator accepts a number of arguments: ``registry``,
+ ``package``, ``settings``, ``root_factory``,
+ ``authentication_policy``, ``authorization_policy``, ``renderers``
+ ``debug_logger``, ``locale_negotiator``, ``request_factory``, and
+ ``renderer_globals_factory``.
+
+ If the ``registry`` argument is passed as a non-``None`` value, it
+ must be an instance of the :class:`pyramid.registry.Registry`
+ class representing the registry to configure. If ``registry`` is
+ ``None``, the configurator will create a
+ :class:`pyramid.registry.Registry` instance itself; it will
+ also perform some default configuration that would not otherwise
+ be done. After construction, the configurator may be used to add
+ configuration to the registry. The overall state of a registry is
+ called the 'configuration state'.
+
+ .. warning:: If a ``registry`` is passed to the Configurator
+ constructor, all other constructor arguments except ``package``
+ are ignored.
+
+ If the ``package`` argument is passed, it must be a reference to a
+ Python :term:`package` (e.g. ``sys.modules['thepackage']``) or a
+ :term:`dotted Python name` to same. This value is used as a basis
+ to convert relative paths passed to various configuration methods,
+ such as methods which accept a ``renderer`` argument, into
+ absolute paths. If ``None`` is passed (the default), the package
+ is assumed to be the Python package in which the *caller* of the
+ ``Configurator`` constructor lives.
+
+ If the ``settings`` argument is passed, it should be a Python dictionary
+ representing the deployment settings for this application. These are
+ later retrievable using the :attr:`pyramid.registry.Registry.settings`
+ attribute (aka ``request.registry.settings``).
+
+ If the ``root_factory`` argument is passed, it should be an object
+ representing the default :term:`root factory` for your application
+ or a :term:`dotted Python name` to same. If it is ``None``, a
+ default root factory will be used.
+
+ If ``authentication_policy`` is passed, it should be an instance
+ of an :term:`authentication policy` or a :term:`dotted Python
+ name` to same.
+
+ If ``authorization_policy`` is passed, it should be an instance of
+ an :term:`authorization policy` or a :term:`dotted Python name` to
+ same.
+
+ .. note:: A ``ConfigurationError`` will be raised when an
+ authorization policy is supplied without also supplying an
+ authentication policy (authorization requires authentication).
+
+ If ``renderers`` is passed, it should be a list of tuples
+ representing a set of :term:`renderer` factories which should be
+ configured into this application (each tuple representing a set of
+ positional values that should be passed to
+ :meth:`pyramid.configuration.Configurator.add_renderer`). If
+ it is not passed, a default set of renderer factories is used.
+
+ If ``debug_logger`` is not passed, a default debug logger that
+ logs to stderr will be used. If it is passed, it should be an
+ instance of the :class:`logging.Logger` (PEP 282) standard library
+ class or a :term:`dotted Python name` to same. The debug logger
+ is used by :app:`Pyramid` itself to log warnings and
+ authorization debugging information.
+
+ If ``locale_negotiator`` is passed, it should be a :term:`locale
+ negotiator` implementation or a :term:`dotted Python name` to
+ same. See :ref:`custom_locale_negotiator`.
+
+ If ``request_factory`` is passed, it should be a :term:`request
+ factory` implementation or a :term:`dotted Python name` to same.
+ See :ref:`custom_request_factory`. By default it is ``None``,
+ which means use the default request factory.
+
+ If ``renderer_globals_factory`` is passed, it should be a
+ :term:`renderer globals` factory implementation or a :term:`dotted
+ Python name` to same. See :ref:`custom_renderer_globals_factory`.
+ By default, it is ``None``, which means use no renderer globals
+ factory.
+
+ If ``default_permission`` is passed, it should be a
+ :term:`permission` string to be used as the default permission for
+ all view configuration registrations performed against this
+ Configurator. An example of a permission string:``'view'``.
+ Adding a default permission makes it unnecessary to protect each
+ view configuration with an explicit permission, unless your
+ application policy requires some exception for a particular view.
+ By default, ``default_permission`` is ``None``, meaning that view
+ configurations which do not explicitly declare a permission will
+ always be executable by entirely anonymous users (any
+ authorization policy in effect is ignored). See also
+ :ref:`setting_a_default_permission`.
+
+ If ``session_factory`` is passed, it should be an object which
+ implements the :term:`session factory` interface. If a nondefault
+ value is passed, the ``session_factory`` will be used to create a
+ session object when ``request.session`` is accessed. Note that
+ the same outcome can be achieved by calling
+ :ref:`pyramid.configration.Configurator.set_session_factory`. By
+ default, this argument is ``None``, indicating that no session
+ factory will be configured (and thus accessing ``request.session``
+ will throw an error) unless ``set_session_factory`` is called later
+ during configuration. """
+
+ manager = manager # for testing injection
+ venusian = venusian # for testing injection
+ _ctx = None
+
+ def __init__(self,
+ registry=None,
+ package=None,
+ settings=None,
+ root_factory=None,
+ authentication_policy=None,
+ authorization_policy=None,
+ renderers=DEFAULT_RENDERERS,
+ debug_logger=None,
+ locale_negotiator=None,
+ request_factory=None,
+ renderer_globals_factory=None,
+ default_permission=None,
+ session_factory=None,
+ autocommit=False,
+ ):
+ if package is None:
+ package = caller_package()
+ name_resolver = DottedNameResolver(package)
+ self.name_resolver = name_resolver
+ self.package_name = name_resolver.package_name
+ self.package = name_resolver.package
+ self.registry = registry
+ self.autocommit = autocommit
+ if registry is None:
+ registry = Registry(self.package_name)
+ self.registry = registry
+ self.setup_registry(
+ settings=settings,
+ root_factory=root_factory,
+ authentication_policy=authentication_policy,
+ authorization_policy=authorization_policy,
+ renderers=renderers,
+ debug_logger=debug_logger,
+ locale_negotiator=locale_negotiator,
+ request_factory=request_factory,
+ renderer_globals_factory=renderer_globals_factory,
+ default_permission=default_permission,
+ session_factory=session_factory,
+ )
+
+ def _action(self, discriminator, callable=None, args=(), kw=None, order=0):
+ """ Register an action which will be executed during a commit. """
+ if kw is None:
+ kw = {}
+ if self.autocommit:
+ if callable is not None:
+ callable(*args, **kw)
+ else:
+ if self._ctx is None:
+ self._ctx = self._make_context()
+ self._ctx.action(discriminator, callable, args, kw, order)
+
+ def _set_settings(self, mapping):
+ settings = Settings(mapping or {})
+ self.registry.settings = settings
+ return settings
+
+ @config_method
+ def _set_root_factory(self, factory):
+ """ Add a :term:`root factory` to the current configuration
+ state. If the ``factory`` argument is ``None`` a default root
+ factory will be registered."""
+ factory = self.maybe_dotted(factory)
+ if factory is None:
+ factory = DefaultRootFactory
+ def register():
+ self.registry.registerUtility(factory, IRootFactory)
+ self.registry.registerUtility(factory, IDefaultRootFactory) # b/c
+ self._action(IRootFactory, register)
+
+ @config_method
+ def _set_authentication_policy(self, policy):
+ """ Add a :app:`Pyramid` :term:`authentication policy` to
+ the current configuration."""
+ policy = self.maybe_dotted(policy)
+ self.registry.registerUtility(policy, IAuthenticationPolicy)
+ self._action(IAuthenticationPolicy)
+
+ @config_method
+ def _set_authorization_policy(self, policy):
+ """ Add a :app:`Pyramid` :term:`authorization policy` to
+ the current configuration state (also accepts a :term:`dotted
+ Python name`."""
+ policy = self.maybe_dotted(policy)
+ self.registry.registerUtility(policy, IAuthorizationPolicy)
+ self._action(IAuthorizationPolicy, None)
+
+ def _make_spec(self, path_or_spec):
+ package, filename = resolve_resource_spec(path_or_spec,
+ self.package_name)
+ if package is None:
+ return filename # absolute filename
+ return '%s:%s' % (package, filename)
+
+ def _split_spec(self, path_or_spec):
+ return resolve_resource_spec(path_or_spec, self.package_name)
+
+ 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):
+ if renderer is None: # use default renderer if one exists
+ default_renderer_factory = self.registry.queryUtility(
+ IRendererFactory)
+ if default_renderer_factory is not None:
+ renderer = {'name':None, 'package':self.package}
+ view = self.maybe_dotted(view)
+ authn_policy = self.registry.queryUtility(IAuthenticationPolicy)
+ authz_policy = self.registry.queryUtility(IAuthorizationPolicy)
+ settings = self.registry.settings
+ logger = self.registry.queryUtility(IDebugLogger)
+ mapped_view = _map_view(view, self.registry, attr, renderer)
+ owrapped_view = _owrap_view(mapped_view, viewname, wrapper_viewname)
+ secured_view = _secure_view(owrapped_view, permission,
+ authn_policy, authz_policy)
+ debug_view = _authdebug_view(secured_view, permission,
+ authn_policy, authz_policy, settings,
+ logger)
+ predicated_view = _predicate_wrap(debug_view, predicates)
+ derived_view = _attr_wrap(predicated_view, accept, order, phash)
+ return derived_view
+
+ def _override(self, package, path, override_package, override_prefix,
+ PackageOverrides=PackageOverrides):
+ pkg_name = package.__name__
+ override_pkg_name = override_package.__name__
+ override = self.registry.queryUtility(
+ IPackageOverrides, name=pkg_name)
+ if override is None:
+ override = PackageOverrides(package)
+ self.registry.registerUtility(override, IPackageOverrides,
+ name=pkg_name)
+ override.insert(path, override_pkg_name, override_prefix)
+
+ def _set_security_policies(self, authentication, authorization=None):
+ if authorization is None:
+ authorization = ACLAuthorizationPolicy() # default
+ if authorization and not authentication:
+ raise ConfigurationError(
+ 'If the "authorization" is passed a value, '
+ 'the "authentication" argument must also be '
+ 'passed a value; authorization requires authentication.')
+ self._set_authentication_policy(authentication)
+ self._set_authorization_policy(authorization)
+
+ def _fix_registry(self):
+ """ Fix up a ZCA component registry that is not a
+ pyramid.registry.Registry by adding analogues of ``has_listeners``,
+ and ``notify`` through monkey-patching."""
+
+ _registry = self.registry
+
+ if not hasattr(_registry, 'notify'):
+ def notify(*events):
+ [ _ for _ in _registry.subscribers(events, None) ]
+ _registry.notify = notify
+
+ if not hasattr(_registry, 'has_listeners'):
+ _registry.has_listeners = True
+
+ def _make_context(self, autocommit=False):
+ context = PyramidConfigurationMachine()
+ registerCommonDirectives(context)
+ context.registry = self.registry
+ context.autocommit = autocommit
+ return context
+
+ # API
+
+ def commit(self):
+ """ Commit pending configuration actions. """
+ if self._ctx is None:
+ return
+ self._ctx.execute_actions()
+ # unwrap and reset the context
+ self._ctx = None
+
+ @classmethod
+ def with_context(cls, context):
+ """ Used by ZCML directives to obtain a configurator with 'the right'
+ context """
+ configurator = cls(registry=context.registry, package=context.package,
+ autocommit=context.autocommit)
+ configurator._ctx = context
+ return configurator
+
+ def with_package(self, package):
+ """ Return a new Configurator instance with the same registry
+ as this configurator using the package supplied as the
+ ``package`` argument to the new configurator. ``package`` may
+ be an actual Python package object or a Python dotted name
+ representing a package."""
+ context = self._ctx
+ if context is None:
+ context = self._ctx = self._make_context(self.autocommit)
+ context = GroupingContextDecorator(context)
+ context.package = package
+ return self.__class__.with_context(context)
+
+ def maybe_dotted(self, dotted):
+ """ Resolve the :term:`dotted Python name` ``dotted`` to a
+ global Python object. If ``dotted`` is not a string, return
+ it without attempting to do any name resolution. If
+ ``dotted`` is a relative dotted name (e.g. ``.foo.bar``,
+ consider it relative to the ``package`` argument supplied to
+ this Configurator's constructor."""
+ return self.name_resolver.maybe_resolve(dotted)
+
+ def absolute_resource_spec(self, relative_spec):
+ """ Resolve the potentially relative :term:`resource
+ specification` string passed as ``relative_spec`` into an
+ absolute resource specification string and return the string.
+ Use the ``package`` of this configurator as the package to
+ which the resource specification will be considered relative
+ when generating an absolute resource specification. If the
+ provided ``relative_spec`` argument is already absolute, or if
+ the ``relative_spec`` is not a string, it is simply returned."""
+ if not isinstance(relative_spec, basestring):
+ return relative_spec
+ return self._make_spec(relative_spec)
+
+ def setup_registry(self, settings=None, root_factory=None,
+ authentication_policy=None, authorization_policy=None,
+ renderers=DEFAULT_RENDERERS, debug_logger=None,
+ locale_negotiator=None, request_factory=None,
+ renderer_globals_factory=None,
+ default_permission=None,
+ session_factory=None):
+ """ When you pass a non-``None`` ``registry`` argument to the
+ :term:`Configurator` constructor, no initial 'setup' is
+ performed against the registry. This is because the registry
+ you pass in may have already been initialized for use under
+ :app:`Pyramid` via a different configurator. However, in
+ some circumstances, such as when you want to use the Zope
+ 'global` registry instead of a registry created as a result of
+ the Configurator constructor, or when you want to reset the
+ initial setup of a registry, you *do* want to explicitly
+ initialize the registry associated with a Configurator for use
+ under :app:`Pyramid`. Use ``setup_registry`` to do this
+ initialization.
+
+ ``setup_registry`` configures settings, a root factory,
+ security policies, renderers, a debug logger, a locale
+ negotiator, and various other settings using the
+ configurator's current registry, as per the descriptions in
+ the Configurator constructor."""
+ registry = self.registry
+ self._fix_registry()
+ self._set_settings(settings)
+ self._set_root_factory(root_factory)
+ debug_logger = self.maybe_dotted(debug_logger)
+ if debug_logger is None:
+ debug_logger = make_stream_logger('pyramid.debug', sys.stderr)
+ registry.registerUtility(debug_logger, IDebugLogger)
+ if authentication_policy or authorization_policy:
+ self._set_security_policies(authentication_policy,
+ authorization_policy)
+ for name, renderer in renderers:
+ self.add_renderer(name, renderer)
+ self.add_view(default_exceptionresponse_view,
+ context=IExceptionResponse)
+ if locale_negotiator:
+ locale_negotiator = self.maybe_dotted(locale_negotiator)
+ registry.registerUtility(locale_negotiator, ILocaleNegotiator)
+ if request_factory:
+ request_factory = self.maybe_dotted(request_factory)
+ self.set_request_factory(request_factory)
+ if renderer_globals_factory:
+ renderer_globals_factory = self.maybe_dotted(
+ renderer_globals_factory)
+ self.set_renderer_globals_factory(renderer_globals_factory)
+ if default_permission:
+ self.set_default_permission(default_permission)
+ if session_factory is not None:
+ self.set_session_factory(session_factory)
+ self.commit()
+
+ # getSiteManager is a unit testing dep injection
+ def hook_zca(self, getSiteManager=None):
+ """ Call :func:`zope.component.getSiteManager.sethook` with
+ the argument
+ :data:`pyramid.threadlocal.get_current_registry`, causing
+ the :term:`Zope Component Architecture` 'global' APIs such as
+ :func:`zope.component.getSiteManager`,
+ :func:`zope.component.getAdapter` and others to use the
+ :app:`Pyramid` :term:`application registry` rather than the
+ Zope 'global' registry. If :mod:`zope.component` cannot be
+ imported, this method will raise an :exc:`ImportError`."""
+ if getSiteManager is None:
+ from zope.component import getSiteManager
+ getSiteManager.sethook(get_current_registry)
+
+ # getSiteManager is a unit testing dep injection
+ def unhook_zca(self, getSiteManager=None):
+ """ Call :func:`zope.component.getSiteManager.reset` to undo
+ the action of
+ :meth:`pyramid.configuration.Configurator.hook_zca`. If
+ :mod:`zope.component` cannot be imported, this method will
+ raise an :exc:`ImportError`."""
+ if getSiteManager is None: # pragma: no cover
+ from zope.component import getSiteManager
+ getSiteManager.reset()
+
+ def begin(self, request=None):
+ """ Indicate that application or test configuration has begun.
+ This pushes a dictionary containing the :term:`application
+ registry` implied by ``registry`` attribute of this
+ configurator and the :term:`request` implied by the
+ ``request`` argument on to the :term:`thread local` stack
+ consulted by various :mod:`pyramid.threadlocal` API
+ functions."""
+ self.manager.push({'registry':self.registry, 'request':request})
+
+ def end(self):
+ """ Indicate that application or test configuration has ended.
+ This pops the last value pushed on to the :term:`thread local`
+ stack (usually by the ``begin`` method) and returns that
+ value.
+ """
+ return self.manager.pop()
+
+ 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.
+
+ 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. """
+
+ if renderer is not None and not isinstance(renderer, dict):
+ renderer = {'name':renderer, 'package':self.package}
+ return self._derive_view(view, attr=attr, renderer=renderer)
+
+ @config_method
+ def add_subscriber(self, subscriber, iface=None):
+ """Add an event :term:`subscriber` for the event stream
+ implied by the supplied ``iface`` interface. The
+ ``subscriber`` argument represents a callable object (or a
+ :term:`dotted Python name` which identifies a callable); it
+ will be called with a single object ``event`` whenever
+ :app:`Pyramid` emits an :term:`event` associated with the
+ ``iface``, which may be an :term:`interface` or a class or a
+ :term:`dotted Python name` to a global object representing an
+ interface or a class. Using the default ``iface`` value,
+ ``None`` will cause the subscriber to be registered for all
+ event types. See :ref:`events_chapter` for more information
+ about events and subscribers."""
+ dotted = self.maybe_dotted
+ subscriber, iface = dotted(subscriber), dotted(iface)
+ if iface is None:
+ iface = (Interface,)
+ if not isinstance(iface, (tuple, list)):
+ iface = (iface,)
+ def register():
+ self.registry.registerHandler(subscriber, iface)
+ self._action(None, register)
+ return subscriber
+
+ def add_settings(self, settings=None, **kw):
+ """Augment the ``settings`` argument passed in to the Configurator
+ constructor with one or more 'setting' key/value pairs. A setting is
+ a single key/value pair in the dictionary-ish object returned from
+ the API :attr:`pyramid.registry.Registry.settings` and
+ :meth:`pyramid.configuration.Configurator.get_settings`.
+
+ You may pass a dictionary::
+
+ config.add_settings({'external_uri':'http://example.com'})
+
+ Or a set of key/value pairs::
+
+ config.add_settings(external_uri='http://example.com')
+
+ This function is useful when you need to test code that accesses the
+ :attr:`pyramid.registry.Registry.settings` API (or the
+ :meth:`pyramid.configuration.Configurator.get_settings` API) and
+ which uses values from that API.
+ """
+ if settings is None:
+ settings = {}
+ utility = self.registry.settings
+ if utility is None:
+ utility = self._set_settings(settings)
+ utility.update(settings)
+ utility.update(kw)
+
+ def get_settings(self):
+ """
+ Return a 'settings' object for the current application. A
+ 'settings' object is a dictionary-like object that contains
+ key/value pairs based on the dictionary passed as the ``settings``
+ argument to the :class:`pyramid.configuration.Configurator`
+ constructor or the :func:`pyramid.router.make_app` API.
+
+ .. note:: For backwards compatibility, dictionary keys can also be
+ looked up as attributes of the settings object.
+
+ .. note:: the :attr:`pyramid.registry.Registry.settings` API
+ performs the same duty.
+ """
+ return self.registry.settings
+
+ def make_wsgi_app(self):
+ """ Returns a :app:`Pyramid` WSGI application representing
+ the current configuration state and sends a
+ :class:`pyramid.events.ApplicationCreated`
+ event to all listeners."""
+ self.commit()
+ from pyramid.router import Router # avoid circdep
+ app = Router(self.registry)
+ # We push the registry on to the stack here in case any code
+ # that depends on the registry threadlocal APIs used in
+ # listeners subscribed to the IApplicationCreated event.
+ self.manager.push({'registry':self.registry, 'request':None})
+ try:
+ self.registry.notify(ApplicationCreated(app))
+ finally:
+ self.manager.pop()
+ return app
+
+ @config_method
+ def load_zcml(self, spec='configure.zcml', lock=threading.Lock()):
+ """ Load configuration from a :term:`ZCML` file into the
+ current configuration state. The ``spec`` argument is an
+ absolute filename, a relative filename, or a :term:`resource
+ specification`, defaulting to ``configure.zcml`` (relative to
+ the package of the configurator's caller)."""
+ package_name, filename = self._split_spec(spec)
+ if package_name is None: # absolute filename
+ package = self.package
+ else:
+ __import__(package_name)
+ package = sys.modules[package_name]
+
+ registry = self.registry
+ self.manager.push({'registry':registry, 'request':None})
+ context = self._ctx
+ if context is None:
+ context = self._ctx = self._make_context(self.autocommit)
+
+ lock.acquire()
+ try:
+ context.package = package
+ xmlconfig.file(filename, package, context=context,
+ execute=self.autocommit)
+ finally:
+ lock.release()
+ self.manager.pop()
+ return registry
+
+ def include(self, *funcs):
+ """ Include one or more configuration callables. A configuration
+ callable should be a callable that accepts a single argument named
+ ``config``, which will be an instance of a :term:`Configurator`. (be
+ warned that it will not be the same configurator instance on which
+ you call this method, however). The code which runs as the result of
+ calling the callable should invoke methods on the configurator which
+ add configuration state. The return value of a callable will be
+ ignored.
+
+ Values allowed to be presented via the ``*funcs`` argument to this
+ method: any callable Python object or any :term:`dotted Python name`
+ which resolves to a callable Python object.
+ """
+ sourcefiles = []
+
+ for func in funcs:
+ func = self.maybe_dotted(func)
+ sourcefile = inspect.getsourcefile(func)
+ module = inspect.getmodule(func)
+ sourcefiles.append((sourcefile, func, module))
+
+ _context = self._ctx
+ if _context is None:
+ _context = self._ctx = self._make_context(self.autocommit)
+
+ for filename, func, module in sourcefiles:
+ spec = module.__name__ + ':' + func.__name__
+ if _context.processSpec(spec):
+ context = GroupingContextDecorator(_context)
+ context.basepath = os.path.dirname(filename)
+ context.includepath = _context.includepath + (spec,)
+ context.package = package_of(module)
+ config = self.__class__.with_context(context)
+ func(config)
+
+ def add_handler(self, route_name, pattern, handler, action=None, **kw):
+
+ """ Add a Pylons-style view handler. This function adds a
+ route and some number of views based on a handler object
+ (usually a class).
+
+ ``route_name`` is the name of the route (to be used later in
+ URL generation).
+
+ ``pattern`` is the matching pattern,
+ e.g. ``'/blog/{action}'``. ``pattern`` may be ``None``, in
+ which case the pattern of an existing route named the same as
+ ``route_name`` is used. If ``pattern`` is ``None`` and no
+ route named ``route_name`` exists, a ``ConfigurationError`` is
+ raised.
+
+ ``handler`` is a dotted name of (or direct reference to) a
+ Python handler class,
+ e.g. ``'my.package.handlers.MyHandler'``.
+
+ If ``{action}`` or ``:action`` is in
+ the pattern, the exposed methods of the handler will be used
+ as views.
+
+ If ``action`` is passed, it will be considered the method name
+ of the handler to use as a view.
+
+ Passing both ``action`` and having an ``{action}`` in the
+ route pattern is disallowed.
+
+ Any extra keyword arguments are passed along to ``add_route``.
+
+ See :ref:`handlers_chapter` for more explanatory documentation.
+
+ This method returns the result of add_route."""
+ handler = self.maybe_dotted(handler)
+
+ if pattern is not None:
+ route = self.add_route(route_name, pattern, **kw)
+ else:
+ mapper = self.get_routes_mapper()
+ route = mapper.get_route(route_name)
+ if route is None:
+ raise ConfigurationError(
+ 'The "pattern" parameter may only be "None" when a route '
+ 'with the route_name argument was previously registered. '
+ 'No such route named %r exists' % route_name)
+
+ pattern = route.pattern
+
+ path_has_action = ':action' in pattern or '{action}' in pattern
+
+ if action and path_has_action:
+ raise ConfigurationError(
+ 'action= (%r) disallowed when an action is in the route '
+ 'path %r' % (action, pattern))
+
+ if path_has_action:
+ autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+')
+ if autoexpose:
+ try:
+ autoexpose = re.compile(autoexpose).match
+ except (re.error, TypeError), why:
+ raise ConfigurationError(why[0])
+ for method_name, method in inspect.getmembers(
+ handler, inspect.ismethod):
+ configs = getattr(method, '__exposed__', [])
+ if autoexpose and not configs:
+ if autoexpose(method_name):
+ configs = [{}]
+ for expose_config in configs:
+ # we don't want to mutate any dict in __exposed__,
+ # so we copy each
+ view_args = expose_config.copy()
+ action = view_args.pop('name', method_name)
+ preds = list(view_args.pop('custom_predicates', []))
+ preds.append(ActionPredicate(action))
+ view_args['custom_predicates'] = preds
+ self.add_view(view=handler, attr=method_name,
+ route_name=route_name, **view_args)
+ else:
+ method_name = action
+ if method_name is None:
+ method_name = '__call__'
+
+ # Scan the controller for any other methods with this action name
+ for meth_name, method in inspect.getmembers(
+ handler, inspect.ismethod):
+ configs = getattr(method, '__exposed__', [{}])
+ for expose_config in configs:
+ # Don't re-register the same view if this method name is
+ # the action name
+ if meth_name == action:
+ continue
+ # We only reg a view if the name matches the action
+ if expose_config.get('name') != method_name:
+ continue
+ # we don't want to mutate any dict in __exposed__,
+ # so we copy each
+ view_args = expose_config.copy()
+ del view_args['name']
+ self.add_view(view=handler, attr=meth_name,
+ route_name=route_name, **view_args)
+
+ # Now register the method itself
+ method = getattr(handler, method_name, None)
+ configs = getattr(method, '__exposed__', [{}])
+ for expose_config in configs:
+ self.add_view(view=handler, attr=action, route_name=route_name,
+ **expose_config)
+
+ return route
+
+ @config_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=False, accept=None,
+ header=None, path_info=None, custom_predicates=(),
+ context=None):
+ """ 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
+
+ The name of 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. If ``permission`` is omitted, a
+ *default* permission may be used for this view registration
+ if one was named as the
+ :class:`pyramid.configuration.Configurator` constructor's
+ ``default_permission`` argument, or if
+ :meth:`pyramid.configuration.Configurator.set_default_permission`
+ was used prior to this view registration. Pass the string
+ ``__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
+
+ 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. This is
+ most useful when the view definition is a class.
+
+ renderer
+
+ This is either a single string term (e.g. ``json``) or a
+ string implying a path or :term:`resource 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:`resource specification` in the form
+ ``some.dotted.package_name:relative/path``, making it
+ possible to address template resources 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 unmolested).
+
+ 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.
+
+ 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. Note that
+ the ``route`` configuration referred to by ``route_name``
+ usually has a ``*traverse`` token in the value of its
+ ``path``, representing a part of the path that will be used
+ by :term:`traversal` against the result of the route's
+ :term:`root factory`.
+
+ .. warning:: Using this argument services an advanced
+ feature that isn't often used unless you want to perform
+ traversal *after* a route has matched. See
+ :ref:`hybrid_chapter` for more information on using this
+ advanced feature.
+
+ 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 either be one of the strings ``GET``,
+ ``POST``, ``PUT``, ``DELETE``, or ``HEAD`` representing an
+ HTTP ``REQUEST_METHOD``. A view declaration with this
+ argument ensures that the view will only be called when the
+ request's ``method`` attribute (aka the ``REQUEST_METHOD`` of
+ the WSGI environment) string matches the supplied value.
+
+ request_param
+
+ This value can be any string. 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
+ supplied has a ``=`` sign in it,
+ e.g. ``request_params="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.
+
+ containment
+
+ This value should be a Python class or :term:`interface` or
+ a :term:`dotted Python name` to such an object that a parent
+ object in the :term:`lineage` 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.
+
+ accept
+
+ The value of this argument 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, this predicate will be true.
+
+ 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``.
+
+
+ custom_predicates
+
+ 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. If all callables return
+ ``True``, the associated view callable will be considered
+ viable for a given request.
+
+ """
+ view = self.maybe_dotted(view)
+ context = self.maybe_dotted(context)
+ for_ = self.maybe_dotted(for_)
+ containment = self.maybe_dotted(containment)
+
+ 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)
+
+ request_iface = IRequest
+
+ if route_name is not None:
+ request_iface = self.registry.queryUtility(IRouteRequest,
+ name=route_name)
+ if request_iface is None:
+ deferred_views = getattr(self.registry,
+ 'deferred_route_views', None)
+ if deferred_views is None:
+ deferred_views = self.registry.deferred_route_views = {}
+ info = dict(
+ view=view, name=name, for_=for_, permission=permission,
+ request_type=request_type, route_name=route_name,
+ request_method=request_method, request_param=request_param,
+ containment=containment, attr=attr,
+ renderer=renderer, wrapper=wrapper, xhr=xhr, accept=accept,
+ header=header, path_info=path_info,
+ custom_predicates=custom_predicates, context=context,
+ )
+ view_info = deferred_views.setdefault(route_name, [])
+ view_info.append(info)
+ return
+
+ order, predicates, phash = _make_predicates(xhr=xhr,
+ request_method=request_method, path_info=path_info,
+ request_param=request_param, header=header, accept=accept,
+ containment=containment, request_type=request_type,
+ custom=custom_predicates)
+
+ if renderer is not None and not isinstance(renderer, dict):
+ renderer = {'name':renderer, 'package':self.package}
+
+ 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)
+
+ def register(permission=permission):
+
+ if permission is None:
+ # intent: will be None if no default permission is registered
+ permission = self.registry.queryUtility(IDefaultPermission)
+
+ # NO_PERMISSION_REQUIRED handled by _secure_view
+ derived_view = self._derive_view(view, permission, predicates, attr,
+ renderer, wrapper, name, accept,
+ order, phash)
+
+ 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)
+
+ discriminator = [
+ 'view', context, name, request_type, IView, containment,
+ request_param, request_method, route_name, attr,
+ xhr, accept, header, path_info]
+ discriminator.extend(sorted(custom_predicates))
+ discriminator = tuple(discriminator)
+ self._action(discriminator, register)
+
+ @config_method
+ def add_route(self,
+ name,
+ pattern=None,
+ view=None,
+ view_for=None,
+ permission=None,
+ factory=None,
+ for_=None,
+ header=None,
+ xhr=False,
+ accept=None,
+ path_info=None,
+ request_method=None,
+ request_param=None,
+ traverse=None,
+ custom_predicates=(),
+ view_permission=None,
+ renderer=None,
+ view_renderer=None,
+ view_context=None,
+ view_attr=None,
+ use_global_views=False,
+ path=None,
+ pregenerator=None,
+ ):
+ """ Add a :term:`route configuration` to the current
+ configuration state, as well as possibly a :term:`view
+ configuration` to be used to specify a :term:`view callable`
+ that will be invoked when this route matches. The arguments
+ to this method are divided into *predicate*, *non-predicate*,
+ and *view-related* types. :term:`Route predicate` arguments
+ narrow the circumstances in which a route will be match a
+ request; non-predicate arguments are informational.
+
+ Non-Predicate Arguments
+
+ name
+
+ The name of the route, e.g. ``myroute``. This attribute is
+ required. It must be unique among all defined routes in a given
+ application.
+
+ factory
+
+ A Python object (often a function or a class) or a
+ :term:`dotted Python name` which refers to the same object
+ that will generate a :app:`Pyramid` :term:`context`
+ object when this route matches. For example,
+ ``mypackage.models.MyFactoryClass``. If this argument is
+ not specified, a default root factory will be used.
+
+ traverse
+
+ If you would like to cause the :term:`context` to be
+ something other than the :term:`root` object when this route
+ matches, you can spell a traversal pattern as the
+ ``traverse`` argument. This traversal pattern will be used
+ as the traversal path: traversal will begin at the root
+ object implied by this route (either the global root, or the
+ object returned by the ``factory`` associated with this
+ route).
+
+ The syntax of the ``traverse`` argument is the same as it is
+ for ``pattern``. For example, if the ``pattern`` provided to
+ ``add_route`` is ``articles/{article}/edit``, and the
+ ``traverse`` argument provided to ``add_route`` is
+ ``/{article}``, when a request comes in that causes the route
+ to match in such a way that the ``article`` match value is
+ '1' (when the request URI is ``/articles/1/edit``), the
+ traversal path will be generated as ``/1``. This means that
+ the root object's ``__getitem__`` will be called with the
+ name ``1`` during the traversal phase. If the ``1`` object
+ exists, it will become the :term:`context` of the request.
+ :ref:`traversal_chapter` has more information about
+ traversal.
+
+ If the traversal path contains segment marker names which
+ are not present in the ``pattern`` argument, a runtime error
+ will occur. The ``traverse`` pattern should not contain
+ segment markers that do not exist in the ``pattern``
+ argument.
+
+ A similar combining of routing and traversal is available
+ when a route is matched which contains a ``*traverse``
+ remainder marker in its pattern (see
+ :ref:`using_traverse_in_a_route_pattern`). The ``traverse``
+ argument to add_route allows you to associate route patterns
+ with an arbitrary traversal path without using a a
+ ``*traverse`` remainder marker; instead you can use other
+ match information.
+
+ Note that the ``traverse`` argument to ``add_route`` is
+ ignored when attached to a route that has a ``*traverse``
+ remainder marker in its pattern.
+
+ pregenerator
+
+ This option should be a callable object that implements the
+ :class:`pyramid.interfaces.IRoutePregenerator`
+ interface. A :term:`pregenerator` is a callable called by
+ the :mod:`pyramid.url.route_url` function to augment or
+ replace the arguments it is passed when generating a URL
+ for the route. This is a feature not often used directly
+ by applications, it is meant to be hooked by frameworks
+ that use :app:`Pyramid` as a base.
+
+ Predicate Arguments
+
+ pattern
+
+ The pattern of the route e.g. ``ideas/{idea}``. This
+ argument is required. See :ref:`route_path_pattern_syntax`
+ for information about the syntax of route patterns. If the
+ pattern doesn't match the current URL, route matching
+ continues.
+
+ .. note:: For backwards compatibility purposes (as of
+ :app:`Pyramid` 1.0), a ``path`` keyword argument passed
+ to this function will be used to represent the pattern
+ value if the ``pattern`` argument is ``None``. If both
+ ``path`` and ``pattern`` are passed, ``pattern`` wins.
+
+ 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 for this route to match. This
+ is useful for detecting AJAX requests issued from jQuery,
+ Prototype and other Javascript libraries. If this predicate
+ returns ``False``, route matching continues.
+
+ request_method
+
+ A string representing an HTTP method name, e.g. ``GET``,
+ ``POST``, ``HEAD``, ``DELETE``, ``PUT``. If this argument
+ is not specified, this route will match if the request has
+ *any* request method. If this predicate returns ``False``,
+ route matching continues.
+
+ 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 return
+ ``True``. If this predicate returns ``False``, route
+ matching continues.
+
+ request_param
+
+ This value can be any string. A view declaration with this
+ argument ensures that the associated route will only match
+ when the 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
+ supplied as the argument has a ``=`` sign in it,
+ e.g. ``request_params="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 route to "match" the current request. If this predicate
+ returns ``False``, route matching continues.
+
+ header
+
+ This argument represents an HTTP header name or a header
+ name/value pair. If the argument contains a ``:`` (colon),
+ it will be considered a name/value pair
+ (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If
+ the value contains a colon, 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. If this
+ predicate returns ``False``, route matching continues.
+
+ 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, this predicate will be true. If this predicate
+ returns ``False``, route matching continues.
+
+ custom_predicates
+
+ This value should be a sequence of references to custom
+ predicate callables. Use custom predicates when no set of
+ predefined predicates does what you need. Custom predicates
+ can be combined with predefined predicates as necessary.
+ Each custom predicate callable should accept two arguments:
+ ``info`` and ``request`` and should return either ``True``
+ or ``False`` after doing arbitrary evaluation of the info
+ and/or the request. If all custom and non-custom predicate
+ callables return ``True`` the associated route will be
+ considered viable for a given request. If any predicate
+ callable returns ``False``, route matching continues. Note
+ that the value ``info`` passed to a custom route predicate
+ is a dictionary containing matching information; see
+ :ref:`custom_route_predicates` for more information about
+ ``info``.
+
+ View-Related Arguments
+
+ view
+
+ A Python object or :term:`dotted Python name` to the same
+ object that will be used as a view callable when this route
+ matches. e.g. ``mypackage.views.my_view``.
+
+ view_context
+
+ A class or an :term:`interface` or :term:`dotted Python
+ name` to the same object which the :term:`context` of the
+ view should match for the view named by the route to be
+ used. This argument is only useful if the ``view``
+ attribute is used. If this attribute is not specified, the
+ default (``None``) will be used.
+
+ If the ``view`` argument is not provided, this argument has
+ no effect.
+
+ This attribute can also be spelled as ``for_`` or ``view_for``.
+
+ view_permission
+
+ The permission name required to invoke the view associated
+ with this route. e.g. ``edit``. (see
+ :ref:`using_security_with_urldispatch` for more information
+ about permissions).
+
+ If the ``view`` attribute is not provided, this argument has
+ no effect.
+
+ This argument can also be spelled as ``permission``.
+
+ view_renderer
+
+ This is either a single string term (e.g. ``json``) or a
+ string implying a path or :term:`resource specification`
+ (e.g. ``templates/views.pt``). If the renderer value is a
+ single term (does not contain a dot ``.``), the specified
+ term 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 term
+ 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 response
+ from the view return value. See
+ :ref:`views_which_use_a_renderer` for more information.
+
+ If the ``view`` argument is not provided, this argument has
+ no effect.
+
+ This argument can also be spelled as ``renderer``.
+
+ view_attr
+
+ The view machinery defaults to using the ``__call__`` method
+ of the view callable (or the function itself, if the view
+ callable is a function) to obtain a response dictionary.
+ 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. This is
+ most useful when the view definition is a class.
+
+ If the ``view`` argument is not provided, this argument has no
+ effect.
+
+ use_global_views
+
+ When a request matches this route, and view lookup cannot
+ find a view which has a ``route_name`` predicate argument
+ that matches the route, try to fall back to using a view
+ that otherwise matches the context, request, and view name
+ (but which does not match the route_name predicate).
+
+ """
+ # these are route predicates; if they do not match, the next route
+ # in the routelist will be tried
+ ignored, predicates, ignored = _make_predicates(
+ xhr=xhr,
+ request_method=request_method,
+ path_info=path_info,
+ request_param=request_param,
+ header=header,
+ accept=accept,
+ traverse=traverse,
+ custom=custom_predicates
+ )
+
+ request_iface = self.registry.queryUtility(IRouteRequest, name=name)
+ if request_iface is None:
+ bases = use_global_views and (IRequest,) or ()
+ request_iface = route_request_iface(name, bases)
+ self.registry.registerUtility(
+ request_iface, IRouteRequest, name=name)
+ deferred_views = getattr(self.registry, 'deferred_route_views', {})
+ view_info = deferred_views.pop(name, ())
+ for info in view_info:
+ self.add_view(**info)
+
+ if view:
+ if view_context is None:
+ view_context = view_for
+ if view_context is None:
+ view_context = for_
+ view_permission = view_permission or permission
+ view_renderer = view_renderer or renderer
+ self.add_view(
+ permission=view_permission,
+ context=view_context,
+ view=view,
+ name='',
+ route_name=name,
+ renderer=view_renderer,
+ attr=view_attr,
+ )
+
+ mapper = self.get_routes_mapper()
+
+ factory = self.maybe_dotted(factory)
+ if pattern is None:
+ pattern = path
+ if pattern is None:
+ raise ConfigurationError('"pattern" argument may not be None')
+
+ discriminator = ['route', name, xhr, request_method, path_info,
+ request_param, header, accept]
+ discriminator.extend(sorted(custom_predicates))
+ discriminator = tuple(discriminator)
+
+ self._action(discriminator, None)
+
+ return mapper.connect(name, pattern, factory, predicates=predicates,
+ pregenerator=pregenerator)
+
+ def get_routes_mapper(self):
+ """ Return the :term:`routes mapper` object associated with
+ this configurator's :term:`registry`."""
+ mapper = self.registry.queryUtility(IRoutesMapper)
+ if mapper is None:
+ mapper = RoutesMapper()
+ self.registry.registerUtility(mapper, IRoutesMapper)
+ return mapper
+
+ @config_method
+ def scan(self, package=None, categories=None):
+ """ Scan a Python package and any of its subpackages for
+ objects marked with :term:`configuration decoration` such as
+ :class:`pyramid.view.view_config`. Any decorated object found
+ will influence the current configuration state.
+
+ The ``package`` argument should be a Python :term:`package` or
+ module object (or a :term:`dotted Python name` which refers to
+ such a package or module). If ``package`` is ``None``, the
+ package of the *caller* is used.
+
+ The ``categories`` argument, if provided, should be the
+ :term:`Venusian` 'scan categories' to use during scanning.
+ Providing this argument is not often necessary; specifying
+ scan categories is an extremely advanced usage.
+
+ By default, ``categories`` is ``None`` which will execute
+ *all* Venusian decorator callbacks including
+ :app:`Pyramid`-related decorators such as
+ :class:`pyramid.view.view_config`. If this is not desirable
+ because the codebase has other Venusian-using decorators that
+ aren't meant to be invoked during a particular scan, use
+ ``('pyramid',)`` as a ``categories`` value to limit the execution
+ of decorator callbacks to only those registered by
+ :app:`Pyramid` itself. Or pass a sequence of Venusian scan
+ categories as necessary (e.g. ``('pyramid', 'myframework')``) to
+ limit the decorators called to the set of categories required.
+ """
+ package = self.maybe_dotted(package)
+ if package is None: # pragma: no cover
+ package = caller_package()
+
+ scanner = self.venusian.Scanner(config=self)
+ scanner.scan(package, categories=categories)
+
+ @config_method
+ def add_renderer(self, name, factory):
+ """
+ Add a :app:`Pyramid` :term:`renderer` factory to the
+ current configuration state.
+
+ The ``name`` argument is the renderer name. Use ``None`` to
+ represent the default renderer (a renderer which will be used for all
+ views unless they name another renderer specifically).
+
+ The ``factory`` argument is Python reference to an
+ implementation of a :term:`renderer` factory or a
+ :term:`dotted Python name` to same.
+
+ Note that this function must be called *before* any
+ ``add_view`` invocation that names the renderer name as an
+ argument. As a result, it's usually a better idea to pass
+ globally used renderers into the ``Configurator`` constructor
+ in the sequence of renderers passed as ``renderer`` than it is
+ to use this method.
+ """
+ factory = self.maybe_dotted(factory)
+ # if name is None or the empty string, we're trying to register
+ # a default renderer, but registerUtility is too dumb to accept None
+ # as a name
+ if not name:
+ name = ''
+ # we need to register renderers eagerly because they are used during
+ # view configuration
+ self.registry.registerUtility(factory, IRendererFactory, name=name)
+ self._action((IRendererFactory, name), None)
+
+ @config_method
+ def override_resource(self, to_override, override_with, _override=None):
+ """ Add a :app:`Pyramid` resource override to the current
+ configuration state.
+
+ ``to_override`` is a :term:`resource specification` to the
+ resource being overridden.
+
+ ``override_with`` is a :term:`resource specification` to the
+ resource that is performing the override.
+
+ See :ref:`resources_chapter` for more
+ information about resource overrides."""
+ if to_override == override_with:
+ raise ConfigurationError('You cannot override a resource with '
+ 'itself')
+
+ package = to_override
+ path = ''
+ if ':' in to_override:
+ package, path = to_override.split(':', 1)
+
+ override_package = override_with
+ override_prefix = ''
+ if ':' in override_with:
+ override_package, override_prefix = override_with.split(':', 1)
+
+ if path and path.endswith('/'):
+ if override_prefix and (not override_prefix.endswith('/')):
+ raise ConfigurationError(
+ 'A directory cannot be overridden with a file (put a '
+ 'slash at the end of override_with if necessary)')
+
+ if override_prefix and override_prefix.endswith('/'):
+ if path and (not path.endswith('/')):
+ raise ConfigurationError(
+ 'A file cannot be overridden with a directory (put a '
+ 'slash at the end of to_override if necessary)')
+
+ override = _override or self._override # test jig
+ def register():
+ __import__(package)
+ __import__(override_package)
+ from_package = sys.modules[package]
+ to_package = sys.modules[override_package]
+ override(from_package, path, to_package, override_prefix)
+ self._action(None, register)
+
+ def set_forbidden_view(self, view=None, attr=None, renderer=None,
+ wrapper=None):
+ """ Add a default forbidden view to the current configuration
+ state.
+
+ .. warning:: This method has been deprecated in :app:`Pyramid`
+ 1.0. *Do not use it for new development; it should only be
+ used to support older code bases which depend upon it.* See
+ :ref:`changing_the_forbidden_view` to see how a forbidden
+ view should be registered in new projects.
+
+ The ``view`` argument should be a :term:`view callable` or a
+ :term:`dotted Python name` which refers to a view callable.
+
+ The ``attr`` argument should be the attribute of the view
+ callable used to retrieve the response (see the ``add_view``
+ method's ``attr`` argument for a description).
+
+ The ``renderer`` argument should be the name of (or path to) a
+ :term:`renderer` used to generate a response for this view
+ (see the
+ :meth:`pyramid.configuration.Configurator.add_view`
+ method's ``renderer`` argument for information about how a
+ configurator relates to a renderer).
+
+ The ``wrapper`` argument should be the name of another view
+ which will wrap this view when rendered (see the ``add_view``
+ method's ``wrapper`` argument for a description)."""
+ if renderer is not None and not isinstance(renderer, dict):
+ renderer = {'name':renderer, 'package':self.package}
+ view = self._derive_view(view, attr=attr, renderer=renderer)
+ def bwcompat_view(context, request):
+ context = getattr(request, 'context', None)
+ return view(context, request)
+ return self.add_view(bwcompat_view, context=Forbidden, wrapper=wrapper)
+
+ def set_notfound_view(self, view=None, attr=None, renderer=None,
+ wrapper=None):
+ """ Add a default not found view to the current configuration
+ state.
+
+ .. warning:: This method has been deprecated in
+ :app:`Pyramid` 1.0. *Do not use it for new development;
+ it should only be used to support older code bases which
+ depend upon it.* See :ref:`changing_the_notfound_view` to
+ see how a not found view should be registered in new
+ projects.
+
+ The ``view`` argument should be a :term:`view callable` or a
+ :term:`dotted Python name` which refers to a view callable.
+
+ The ``attr`` argument should be the attribute of the view
+ callable used to retrieve the response (see the ``add_view``
+ method's ``attr`` argument for a description).
+
+ The ``renderer`` argument should be the name of (or path to) a
+ :term:`renderer` used to generate a response for this view
+ (see the
+ :meth:`pyramid.configuration.Configurator.add_view`
+ method's ``renderer`` argument for information about how a
+ configurator relates to a renderer).
+
+ The ``wrapper`` argument should be the name of another view
+ which will wrap this view when rendered (see the ``add_view``
+ method's ``wrapper`` argument for a description).
+ """
+ if renderer is not None and not isinstance(renderer, dict):
+ renderer = {'name':renderer, 'package':self.package}
+ view = self._derive_view(view, attr=attr, renderer=renderer)
+ def bwcompat_view(context, request):
+ context = getattr(request, 'context', None)
+ return view(context, request)
+ return self.add_view(bwcompat_view, context=NotFound, wrapper=wrapper)
+
+ @config_method
+ def set_request_factory(self, factory):
+ """ The object passed as ``factory`` should be an object (or a
+ :term:`dotted Python name` which refers to an object) which
+ will be used by the :app:`Pyramid` router to create all
+ request objects. This factory object must have the same
+ methods and attributes as the
+ :class:`pyramid.request.Request` class (particularly
+ ``__call__``, and ``blank``).
+
+ .. note:: Using the :meth:``request_factory`` argument to the
+ :class:`pyramid.configuration.Configurator` constructor
+ can be used to achieve the same purpose.
+ """
+ factory = self.maybe_dotted(factory)
+ def register():
+ self.registry.registerUtility(factory, IRequestFactory)
+ self._action(IRequestFactory, register)
+
+ @config_method
+ def set_renderer_globals_factory(self, factory):
+ """ The object passed as ``factory`` should be an callable (or
+ a :term:`dotted Python name` which refers to an callable) that
+ will be used by the :app:`Pyramid` rendering machinery as a
+ renderers global factory (see :ref:`adding_renderer_globals`).
+
+ The ``factory`` callable must accept a single argument named
+ ``system`` (which will be a dictionary) and it must return a
+ dictionary. When an application uses a renderer, the
+ factory's return dictionary will be merged into the ``system``
+ dictionary, and therefore will be made available to the code
+ which uses the renderer.
+
+ .. note:: Using the :meth:`renderer_globals_factory`
+ argument to the
+ :class:`pyramid.configuration.Configurator` constructor
+ can be used to achieve the same purpose.
+ """
+ factory = self.maybe_dotted(factory)
+ def register():
+ self.registry.registerUtility(factory, IRendererGlobalsFactory)
+ self._action(IRendererGlobalsFactory, register)
+
+ @config_method
+ def set_locale_negotiator(self, negotiator):
+ """
+ Set the :term:`locale negotiator` for this application. The
+ :term:`locale negotiator` is a callable which accepts a
+ :term:`request` object and which returns a :term:`locale
+ name`. The ``negotiator`` argument should be the locale
+ negotiator implementation or a :term:`dotted Python name`
+ which refers to such an implementation.
+
+ Later calls to this method override earlier calls; there can
+ be only one locale negotiator active at a time within an
+ application. See :ref:`activating_translation` for more
+ information.
+
+ .. note:: Using the ``locale_negotiator`` argument to the
+ :class:`pyramid.configuration.Configurator` constructor
+ can be used to achieve the same purpose.
+ """
+ negotiator = self.maybe_dotted(negotiator)
+ def register():
+ self.registry.registerUtility(negotiator, ILocaleNegotiator)
+ self._action(ILocaleNegotiator, register)
+
+ @config_method
+ def set_default_permission(self, permission):
+ """
+ Set the default permission to be used by all subsequent
+ :term:`view configuration` registrations. ``permission``
+ should be a :term:`permission` string to be used as the
+ default permission. An example of a permission
+ string:``'view'``. Adding a default permission makes it
+ unnecessary to protect each view configuration with an
+ explicit permission, unless your application policy requires
+ some exception for a particular view.
+
+ If a default permission is *not* set, views represented by
+ view configuration registrations which do not explicitly
+ declare a permission will be executable by entirely anonymous
+ users (any authorization policy is ignored).
+
+ Later calls to this method override earlier calls; there can
+ be only one default permission active at a time within an
+ application.
+
+ See also :ref:`setting_a_default_permission`.
+
+ .. note:: Using the ``default_permission`` argument to the
+ :class:`pyramid.configuration.Configurator` constructor
+ can be used to achieve the same purpose.
+ """
+ # default permission used during view registration
+ self.registry.registerUtility(permission, IDefaultPermission)
+ self._action(IDefaultPermission, None)
+
+ @config_method
+ def set_session_factory(self, session_factory):
+ """
+ Configure the application with a :term:`session factory`. If
+ this method is called, the ``session_factory`` argument must
+ be a session factory callable.
+ """
+ def register():
+ self.registry.registerUtility(session_factory, ISessionFactory)
+ self._action(ISessionFactory, register)
+
+ @config_method
+ def add_translation_dirs(self, *specs):
+ """ Add one or more :term:`translation directory` paths to the
+ current configuration state. The ``specs`` argument is a
+ sequence that may contain absolute directory paths
+ (e.g. ``/usr/share/locale``) or :term:`resource specification`
+ names naming a directory path (e.g. ``some.package:locale``)
+ or a combination of the two.
+
+ Example:
+
+ .. code-block:: python
+
+ add_translations_dirs('/usr/share/locale', 'some.package:locale')
+
+ """
+ for spec in specs:
+
+ package_name, filename = self._split_spec(spec)
+ if package_name is None: # absolute filename
+ directory = filename
+ else:
+ __import__(package_name)
+ package = sys.modules[package_name]
+ directory = os.path.join(package_path(package), filename)
+
+ if not os.path.isdir(os.path.realpath(directory)):
+ raise ConfigurationError('"%s" is not a directory' % directory)
+
+ tdirs = self.registry.queryUtility(ITranslationDirectories)
+ if tdirs is None:
+ tdirs = []
+ self.registry.registerUtility(tdirs, ITranslationDirectories)
+
+ tdirs.insert(0, directory)
+ # XXX no action?
+
+ if specs:
+
+ # We actually only need an IChameleonTranslate function
+ # utility to be registered zero or one times. We register the
+ # same function once for each added translation directory,
+ # which does too much work, but has the same effect.
+
+ def translator(msg):
+ request = get_current_request()
+ localizer = get_localizer(request)
+ return localizer.translate(msg)
+
+ ctranslate = ChameleonTranslate(translator)
+ self.registry.registerUtility(ctranslate, IChameleonTranslate)
+
+ def add_static_view(self, name, path, **kw):
+ """ Add a view used to render static resources such as images
+ and CSS files.
+
+ The ``name`` argument is a string representing :term:`view
+ name` of the view which is registered. It may alternately be
+ a *url prefix*.
+
+ 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:`resource specification`.
+
+ The ``cache_max_age`` keyword argument is input to set the
+ ``Expires`` and ``Cache-Control`` headers for static resources
+ 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
+ ``__no_permission_required__``. The
+ ``__no_permission_required__`` string is 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 resources
+ seldom need protection from viewing.
+
+ *Usage*
+
+ The ``add_static_view`` function is typically used in
+ conjunction with the :func:`pyramid.url.static_url`
+ function. ``add_static_view`` adds a view which renders a
+ static resource when some URL is visited;
+ :func:`pyramid.url.static_url` generates a URL to that
+ resource.
+
+ The ``name`` argument to ``add_static_view`` is usually a
+ :term:`view name`. When this is the case, the
+ :func:`pyramid.url.static_url` API will generate a URL
+ which points to a Pyramid view, which will serve up a set of
+ resources 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 :func:`pyramid.url.static_url`:
+
+ .. code-block:: python
+
+ static_url('mypackage:images/logo.png', request)
+
+ When ``add_static_view`` is called with a ``name`` argument
+ that represents a simple view name, as it is above, subsequent
+ calls to :func:`pyramid.url.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 resources to be
+ served from an external webserver. This happens when the
+ ``name`` argument is a URL (detected as any string with a
+ slash in it). In this mode, the ``name`` is used as the URL
+ prefix when generating a URL using
+ :func:`pyramid.url.static_url`. 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
+ :func:`pyramid.url.static_url` for that static view will be
+ prefixed with ``http://example.com/images``:
+
+ .. code-block:: python
+
+ static_url('mypackage:images/logo.png', request)
+
+ When ``add_static_view`` is called with a ``name`` argument
+ that is the URL prefix ``http://example.com/images``,
+ subsequent calls to :func:`pyramid.url.static_url` with
+ paths that start with the ``path`` argument passed to
+ ``add_static_view`` will generate a URL something like
+ ``http://example.com/logo.png``. The external webserver
+ listening on ``example.com`` must be itself configured to
+ respond properly to such a request.
+
+ See :ref:`static_resources_section` for more information.
+ """
+ spec = self._make_spec(path)
+ info = self.registry.queryUtility(IStaticURLInfo)
+ if info is None:
+ info = StaticURLInfo(self)
+ self.registry.registerUtility(info, IStaticURLInfo)
+
+ info.add(name, spec, **kw)
+
+ # testing API
+ def testing_securitypolicy(self, userid=None, groupids=(),
+ permissive=True):
+ """Unit/integration testing helper: Registers a pair of faux
+ :app:`Pyramid` security policies: a :term:`authentication
+ policy` and a :term:`authorization policy`.
+
+ The behavior of the registered :term:`authorization policy`
+ depends on the ``permissive`` argument. If ``permissive`` is
+ true, a permissive :term:`authorization policy` is registered;
+ this policy allows all access. If ``permissive`` is false, a
+ nonpermissive :term:`authorization policy` is registered; this
+ policy denies all access.
+
+ The behavior of the registered :term:`authentication policy`
+ depends on the values provided for the ``userid`` and
+ ``groupids`` argument. The authentication policy will return
+ the userid identifier implied by the ``userid`` argument and
+ the group ids implied by the ``groupids`` argument when the
+ :func:`pyramid.security.authenticated_userid` or
+ :func:`pyramid.security.effective_principals` APIs are
+ used.
+
+ This function is most useful when testing code that uses
+ the APIs named :func:`pyramid.security.has_permission`,
+ :func:`pyramid.security.authenticated_userid`,
+ :func:`pyramid.security.effective_principals`, and
+ :func:`pyramid.security.principals_allowed_by_permission`.
+ """
+ from pyramid.testing import DummySecurityPolicy
+ policy = DummySecurityPolicy(userid, groupids, permissive)
+ self.registry.registerUtility(policy, IAuthorizationPolicy)
+ self.registry.registerUtility(policy, IAuthenticationPolicy)
+
+ def testing_models(self, models):
+ """Unit/integration testing helper: registers a dictionary of
+ :term:`model` objects that can be resolved via the
+ :func:`pyramid.traversal.find_model` API.
+
+ The :func:`pyramid.traversal.find_model` API is called with
+ a path as one of its arguments. If the dictionary you
+ register when calling this method contains that path as a
+ string key (e.g. ``/foo/bar`` or ``foo/bar``), the
+ corresponding value will be returned to ``find_model`` (and
+ thus to your code) when
+ :func:`pyramid.traversal.find_model` is called with an
+ equivalent path string or tuple.
+ """
+ class DummyTraverserFactory:
+ def __init__(self, context):
+ self.context = context
+
+ def __call__(self, request):
+ path = request['PATH_INFO']
+ ob = models[path]
+ traversed = traversal_path(path)
+ return {'context':ob, 'view_name':'','subpath':(),
+ 'traversed':traversed, 'virtual_root':ob,
+ 'virtual_root_path':(), 'root':ob}
+ self.registry.registerAdapter(DummyTraverserFactory, (Interface,),
+ ITraverser)
+ return models
+
+ def testing_add_subscriber(self, event_iface=None):
+ """Unit/integration testing helper: Registers a
+ :term:`subscriber` which listens for events of the type
+ ``event_iface``. This method returns a list object which is
+ appended to by the subscriber whenever an event is captured.
+
+ When an event is dispatched that matches the value implied by
+ the ``event_iface`` argument, that event will be appended to
+ the list. You can then compare the values in the list to
+ expected event notifications. This method is useful when
+ testing code that wants to call
+ :meth:`pyramid.registry.Registry.notify`,
+ :func:`zope.component.event.dispatch` or
+ :func:`zope.component.event.objectEventNotify`.
+
+ The default value of ``event_iface`` (``None``) implies a
+ subscriber registered for *any* kind of event.
+ """
+ event_iface = self.maybe_dotted(event_iface)
+ L = []
+ def subscriber(*event):
+ L.extend(event)
+ self.add_subscriber(subscriber, event_iface)
+ return L
+
+ def testing_add_renderer(self, path, renderer=None):
+ """Unit/integration testing helper: register a renderer at
+ ``path`` (usually a relative filename ala ``templates/foo.pt``
+ or a resource specification) and return the renderer object.
+ If the ``renderer`` argument is None, a 'dummy' renderer will
+ be used. This function is useful when testing code that calls
+ the :func:`pyramid.renderers.render` function or
+ :func:`pyramid.renderers.render_to_response` function or
+ any other ``render_*`` or ``get_*`` API of the
+ :mod:`pyramid.renderers` module.
+
+ Note that calling this method for with a ``path`` argument
+ representing a renderer factory type (e.g. for ``foo.pt``
+ usually implies the ``chameleon_zpt`` renderer factory)
+ clobbers any existing renderer factory registered for that
+ type.
+
+ .. note:: This method is also available under the alias
+ ``testing_add_template`` (an older name for it).
+
+ """
+ from pyramid.testing import DummyRendererFactory
+ helper = RendererHelper(name=path, registry=self.registry)
+ factory = self.registry.queryUtility(IRendererFactory, name=helper.type)
+ if not isinstance(factory, DummyRendererFactory):
+ factory = DummyRendererFactory(helper.type, factory)
+ self.registry.registerUtility(factory, IRendererFactory,
+ name=helper.type)
+
+ from pyramid.testing import DummyTemplateRenderer
+ if renderer is None:
+ renderer = DummyTemplateRenderer()
+ factory.add(path, renderer)
+ return renderer
+
+ testing_add_template = testing_add_renderer
+
+def _make_predicates(xhr=None, request_method=None, path_info=None,
+ request_param=None, header=None, accept=None,
+ containment=None, request_type=None,
+ traverse=None, custom=()):
+
+ # PREDICATES
+ # ----------
+ #
+ # Given an argument list, a predicate list is computed.
+ # Predicates are added to a predicate list in (presumed)
+ # computation expense order. All predicates associated with a
+ # view or route must evaluate true for the view or route to
+ # "match" during a request. Elsewhere in the code, we evaluate
+ # predicates using a generator expression. The fastest predicate
+ # should be evaluated first, then the next fastest, and so on, as
+ # if one returns false, the remainder of the predicates won't need
+ # to be evaluated.
+ #
+ # While we compute predicates, we also compute a predicate hash
+ # (aka phash) that can be used by a caller to identify identical
+ # predicate lists.
+ #
+ # ORDERING
+ # --------
+ #
+ # A "order" is computed for the predicate list. An order is
+ # a scoring.
+ #
+ # Each predicate is associated with a weight value, which is a
+ # multiple of 2. The weight of a predicate symbolizes the
+ # relative potential "importance" of the predicate to all other
+ # predicates. A larger weight indicates greater importance.
+ #
+ # All weights for a given predicate list are bitwise ORed together
+ # to create a "score"; this score is then subtracted from
+ # MAX_ORDER and divided by an integer representing the number of
+ # predicates+1 to determine the order.
+ #
+ # The order represents the ordering in which a "multiview" ( a
+ # collection of views that share the same context/request/name
+ # triad but differ in other ways via predicates) will attempt to
+ # call its set of views. Views with lower orders will be tried
+ # first. The intent is to a) ensure that views with more
+ # predicates are always evaluated before views with fewer
+ # predicates and b) to ensure a stable call ordering of views that
+ # share the same number of predicates. Views which do not have
+ # any predicates get an order of MAX_ORDER, meaning that they will
+ # be tried very last.
+
+ predicates = []
+ weights = []
+ h = md5()
+
+ if xhr:
+ def xhr_predicate(context, request):
+ return request.is_xhr
+ weights.append(1 << 1)
+ predicates.append(xhr_predicate)
+ h.update('xhr:%r' % bool(xhr))
+
+ if request_method is not None:
+ def request_method_predicate(context, request):
+ return request.method == request_method
+ weights.append(1 << 2)
+ predicates.append(request_method_predicate)
+ h.update('request_method:%r' % request_method)
+
+ if path_info is not None:
+ try:
+ path_info_val = re.compile(path_info)
+ except re.error, why:
+ raise ConfigurationError(why[0])
+ def path_info_predicate(context, request):
+ return path_info_val.match(request.path_info) is not None
+ weights.append(1 << 3)
+ predicates.append(path_info_predicate)
+ h.update('path_info:%r' % path_info)
+
+ if request_param is not None:
+ request_param_val = None
+ if '=' in request_param:
+ request_param, request_param_val = request_param.split('=', 1)
+ def request_param_predicate(context, request):
+ if request_param_val is None:
+ return request_param in request.params
+ return request.params.get(request_param) == request_param_val
+ weights.append(1 << 4)
+ predicates.append(request_param_predicate)
+ h.update('request_param:%r=%r' % (request_param, request_param_val))
+
+ if header is not None:
+ header_name = header
+ header_val = None
+ if ':' in header:
+ header_name, header_val = header.split(':', 1)
+ try:
+ header_val = re.compile(header_val)
+ except re.error, why:
+ raise ConfigurationError(why[0])
+ def header_predicate(context, request):
+ if header_val is None:
+ return header_name in request.headers
+ val = request.headers.get(header_name)
+ if val is None:
+ return False
+ return header_val.match(val) is not None
+ weights.append(1 << 5)
+ predicates.append(header_predicate)
+ h.update('header:%r=%r' % (header_name, header_val))
+
+ if accept is not None:
+ def accept_predicate(context, request):
+ return accept in request.accept
+ weights.append(1 << 6)
+ predicates.append(accept_predicate)
+ h.update('accept:%r' % accept)
+
+ if containment is not None:
+ def containment_predicate(context, request):
+ return find_interface(context, containment) is not None
+ weights.append(1 << 7)
+ predicates.append(containment_predicate)
+ h.update('containment:%r' % hash(containment))
+
+ if request_type is not None:
+ def request_type_predicate(context, request):
+ return request_type.providedBy(request)
+ weights.append(1 << 8)
+ predicates.append(request_type_predicate)
+ h.update('request_type:%r' % hash(request_type))
+
+ if traverse is not None:
+ # ``traverse`` can only be used as a *route* "predicate"; it
+ # adds 'traverse' to the matchdict if it's specified in the
+ # routing args. This causes the ModelGraphTraverser to use
+ # the resolved traverse pattern as the traversal path.
+ from pyramid.urldispatch import _compile_route
+ _, tgenerate = _compile_route(traverse)
+ def traverse_predicate(context, request):
+ if 'traverse' in context:
+ return True
+ m = context['match']
+ tvalue = tgenerate(m)
+ m['traverse'] = traversal_path(tvalue)
+ return True
+ # This isn't actually a predicate, it's just a infodict
+ # modifier that injects ``traverse`` into the matchdict. As a
+ # result, the ``traverse_predicate`` function above always
+ # returns True, and we don't need to update the hash or attach
+ # a weight to it
+ predicates.append(traverse_predicate)
+
+ if custom:
+ for num, predicate in enumerate(custom):
+ predicates.append(predicate)
+ # using hash() here rather than id() is intentional: we
+ # want to allow custom predicates that are part of
+ # frameworks to be able to define custom __hash__
+ # functions for custom predicates, so that the hash output
+ # of predicate instances which are "logically the same"
+ # may compare equal.
+ h.update('custom%s:%r' % (num, hash(predicate)))
+ weights.append(1 << 10)
+
+ score = 0
+ for bit in weights:
+ score = score | bit
+ order = (MAX_ORDER - score) / (len(predicates) + 1)
+ phash = h.hexdigest()
+ return order, predicates, phash
+
+class MultiView(object):
+ implements(IMultiView)
+
+ def __init__(self, name):
+ self.name = name
+ self.media_views = {}
+ self.views = []
+ self.accepts = []
+
+ 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()
+ else:
+ subset = self.media_views.setdefault(accept, [])
+ subset.append((order, view, phash))
+ subset.sort()
+ 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)
+
+def decorate_view(wrapped_view, original_view):
+ if wrapped_view is original_view:
+ return False
+ wrapped_view.__module__ = original_view.__module__
+ wrapped_view.__doc__ = original_view.__doc__
+ try:
+ wrapped_view.__name__ = original_view.__name__
+ except AttributeError:
+ wrapped_view.__name__ = repr(original_view)
+ try:
+ wrapped_view.__permitted__ = original_view.__permitted__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__call_permissive__ = original_view.__call_permissive__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__predicated__ = original_view.__predicated__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__accept__ = original_view.__accept__
+ except AttributeError:
+ pass
+ try:
+ wrapped_view.__order__ = original_view.__order__
+ except AttributeError:
+ pass
+ return True
+
+def requestonly(class_or_callable, attr=None):
+ """ Return true of the class or callable accepts only a request argument,
+ as opposed to something that accepts context, request """
+ if attr is None:
+ attr = '__call__'
+ if inspect.isfunction(class_or_callable):
+ fn = class_or_callable
+ elif inspect.isclass(class_or_callable):
+ try:
+ fn = class_or_callable.__init__
+ except AttributeError:
+ return False
+ else:
+ try:
+ fn = getattr(class_or_callable, attr)
+ except AttributeError:
+ return False
+
+ try:
+ argspec = inspect.getargspec(fn)
+ except TypeError:
+ return False
+
+ args = argspec[0]
+ defaults = argspec[3]
+
+ if hasattr(fn, 'im_func'):
+ # it's an instance method
+ if not args:
+ return False
+ args = args[1:]
+ if not args:
+ return False
+
+ if len(args) == 1:
+ return True
+
+ elif args[0] == 'request':
+ if len(args) - len(defaults) == 1:
+ return True
+
+ return False
+
+def is_response(ob):
+ if ( hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and
+ hasattr(ob, 'status') ):
+ return True
+ return False
+
+def _map_view(view, registry, attr=None, renderer=None):
+ wrapped_view = view
+
+ helper = None
+
+ if renderer is not None:
+ helper = RendererHelper(renderer['name'],
+ package=renderer['package'],
+ registry=registry)
+
+ if inspect.isclass(view):
+ # If the object we've located is a class, turn it into a
+ # function that operates like a Zope view (when it's invoked,
+ # construct an instance using 'context' and 'request' as
+ # position arguments, then immediately invoke the __call__
+ # method of the instance with no arguments; __call__ should
+ # return an IResponse).
+ if requestonly(view, attr):
+ # its __init__ accepts only a single request argument,
+ # instead of both context and request
+ def _class_requestonly_view(context, request):
+ inst = view(request)
+ if attr is None:
+ response = inst()
+ else:
+ response = getattr(inst, attr)()
+ if helper is not None:
+ if not is_response(response):
+ system = {
+ 'view':inst,
+ 'renderer_name':renderer['name'], # b/c
+ 'renderer_info':renderer,
+ 'context':context,
+ 'request':request
+ }
+ response = helper.render_to_response(response, system,
+ request=request)
+ return response
+ wrapped_view = _class_requestonly_view
+ else:
+ # its __init__ accepts both context and request
+ def _class_view(context, request):
+ inst = view(context, request)
+ if attr is None:
+ response = inst()
+ else:
+ response = getattr(inst, attr)()
+ if helper is not None:
+ if not is_response(response):
+ system = {'view':inst,
+ 'renderer_name':renderer['name'], # b/c
+ 'renderer_info':renderer,
+ 'context':context,
+ 'request':request
+ }
+ response = helper.render_to_response(response, system,
+ request=request)
+ return response
+ wrapped_view = _class_view
+
+ elif requestonly(view, attr):
+ # its __call__ accepts only a single request argument,
+ # instead of both context and request
+ def _requestonly_view(context, request):
+ if attr is None:
+ response = view(request)
+ else:
+ response = getattr(view, attr)(request)
+
+ if helper is not None:
+ if not is_response(response):
+ system = {
+ 'view':view,
+ 'renderer_name':renderer['name'],
+ 'renderer_info':renderer,
+ 'context':context,
+ 'request':request
+ }
+ response = helper.render_to_response(response, system,
+ request=request)
+ return response
+ wrapped_view = _requestonly_view
+
+ elif attr:
+ def _attr_view(context, request):
+ response = getattr(view, attr)(context, request)
+ if helper is not None:
+ if not is_response(response):
+ system = {
+ 'view':view,
+ 'renderer_name':renderer['name'],
+ 'renderer_info':renderer,
+ 'context':context,
+ 'request':request
+ }
+ response = helper.render_to_response(response, system,
+ request=request)
+ return response
+ wrapped_view = _attr_view
+
+ elif helper is not None:
+ def _rendered_view(context, request):
+ response = view(context, request)
+ if not is_response(response):
+ system = {
+ 'view':view,
+ 'renderer_name':renderer['name'], # b/c
+ 'renderer_info':renderer,
+ 'context':context,
+ 'request':request
+ }
+ response = helper.render_to_response(response, system,
+ request=request)
+ return response
+ wrapped_view = _rendered_view
+
+ decorate_view(wrapped_view, view)
+ return wrapped_view
+
+def _owrap_view(view, viewname, wrapper_viewname):
+ if not wrapper_viewname:
+ return view
+ def _owrapped_view(context, request):
+ response = view(context, request)
+ request.wrapped_response = response
+ request.wrapped_body = response.body
+ request.wrapped_view = view
+ wrapped_response = render_view_to_response(context, request,
+ wrapper_viewname)
+ if wrapped_response is None:
+ raise ValueError(
+ 'No wrapper view named %r found when executing view '
+ 'named %r' % (wrapper_viewname, viewname))
+ return wrapped_response
+ decorate_view(_owrapped_view, view)
+ return _owrapped_view
+
+def _predicate_wrap(view, predicates):
+ if not predicates:
+ return view
+ def predicate_wrapper(context, request):
+ if all((predicate(context, request) for predicate in predicates)):
+ return view(context, request)
+ raise PredicateMismatch('predicate mismatch for view %s' % view)
+ def checker(context, request):
+ return all((predicate(context, request) for predicate in
+ predicates))
+ predicate_wrapper.__predicated__ = checker
+ decorate_view(predicate_wrapper, view)
+ return predicate_wrapper
+
+def _secure_view(view, permission, authn_policy, authz_policy):
+ if permission == '__no_permission_required__':
+ # allow views registered within configurations that have a
+ # default permission to explicitly override the default
+ # permission, replacing it with no permission at all
+ permission = None
+
+ wrapped_view = view
+ if authn_policy and authz_policy and (permission is not None):
+ def _secured_view(context, request):
+ principals = authn_policy.effective_principals(request)
+ if authz_policy.permits(context, principals, permission):
+ return view(context, request)
+ msg = getattr(request, 'authdebug_message',
+ 'Unauthorized: %s failed permission check' % view)
+ raise Forbidden(msg)
+ _secured_view.__call_permissive__ = view
+ def _permitted(context, request):
+ principals = authn_policy.effective_principals(request)
+ return authz_policy.permits(context, principals, permission)
+ _secured_view.__permitted__ = _permitted
+ wrapped_view = _secured_view
+ decorate_view(wrapped_view, view)
+
+ return wrapped_view
+
+def _authdebug_view(view, permission, authn_policy, authz_policy, settings,
+ logger):
+ wrapped_view = view
+ if settings and settings.get('debug_authorization', False):
+ def _authdebug_view(context, request):
+ view_name = getattr(request, 'view_name', None)
+
+ if authn_policy and authz_policy:
+ if permission is None:
+ msg = 'Allowed (no permission registered)'
+ else:
+ principals = authn_policy.effective_principals(request)
+ msg = str(authz_policy.permits(context, principals,
+ permission))
+ else:
+ msg = 'Allowed (no authorization policy in use)'
+
+ view_name = getattr(request, 'view_name', None)
+ url = getattr(request, 'url', None)
+ msg = ('debug_authorization of url %s (view name %r against '
+ 'context %r): %s' % (url, view_name, context, msg))
+ logger and logger.debug(msg)
+ if request is not None:
+ request.authdebug_message = msg
+ return view(context, request)
+
+ wrapped_view = _authdebug_view
+ decorate_view(wrapped_view, view)
+
+ return wrapped_view
+
+def _attr_wrap(view, accept, order, phash):
+ # this is a little silly but we don't want to decorate the original
+ # function with attributes that indicate accept, order, and phash,
+ # so we use a wrapper
+ if (accept is None) and (order == MAX_ORDER) and (phash == DEFAULT_PHASH):
+ return view # defaults
+ def attr_view(context, request):
+ return view(context, request)
+ attr_view.__accept__ = accept
+ attr_view.__order__ = order
+ attr_view.__phash__ = phash
+ decorate_view(attr_view, view)
+ return attr_view
+
+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)))
+ )
+
+class ActionPredicate(object):
+ action_name = 'action'
+ def __init__(self, action):
+ self.action = action
+ try:
+ self.action_re = re.compile(action + '$')
+ except (re.error, TypeError), why:
+ raise ConfigurationError(why[0])
+
+ def __call__(self, context, request):
+ matchdict = request.matchdict
+ if matchdict is None:
+ return False
+ action = matchdict.get(self.action_name)
+ if action is None:
+ return False
+ return bool(self.action_re.match(action))
+
+ def __hash__(self):
+ # allow this predicate's phash to be compared as equal to
+ # others that share the same action name
+ return hash(self.action)
+
+class PyramidConfigurationMachine(ConfigurationMachine):
+ autocommit = False
+
+ def processSpec(self, spec):
+ """Check whether a callable needs to be processed. The ``spec``
+ refers to a unique identifier for the callable.
+
+ Return True if processing is needed and False otherwise. If
+ the callable needs to be processed, it will be marked as
+ processed, assuming that the caller will procces the callable if
+ it needs to be processed.
+ """
+ if spec in self._seen_files:
+ return False
+ self._seen_files.add(spec)
+ return True
+
diff --git a/pyramid/configuration.py b/pyramid/configuration.py
index 33a02e1b7..8cf764840 100644
--- a/pyramid/configuration.py
+++ b/pyramid/configuration.py
@@ -1,2285 +1,16 @@
-import inspect
-import os
-import re
-import sys
-import threading
-import traceback
-
-import venusian
-
-from translationstring import ChameleonTranslate
-
-from zope.configuration import xmlconfig
-from zope.configuration.config import GroupingContextDecorator
-from zope.configuration.config import ConfigurationMachine
-from zope.configuration.xmlconfig import registerCommonDirectives
-from zope.deprecation import deprecated
-
-from zope.interface import Interface
-from zope.interface import implementedBy
-from zope.interface.interfaces import IInterface
-from zope.interface import implements
-
-from pyramid.interfaces import IAuthenticationPolicy
-from pyramid.interfaces import IAuthorizationPolicy
-from pyramid.interfaces import IChameleonTranslate
-from pyramid.interfaces import IDebugLogger
-from pyramid.interfaces import IDefaultPermission
-from pyramid.interfaces import IDefaultRootFactory
-from pyramid.interfaces import IException
-from pyramid.interfaces import IExceptionResponse
-from pyramid.interfaces import IExceptionViewClassifier
-from pyramid.interfaces import ILocaleNegotiator
-from pyramid.interfaces import IMultiView
-from pyramid.interfaces import IPackageOverrides
-from pyramid.interfaces import IRendererFactory
-from pyramid.interfaces import IRendererGlobalsFactory
-from pyramid.interfaces import IRequest
-from pyramid.interfaces import IRequestFactory
-from pyramid.interfaces import IRootFactory
-from pyramid.interfaces import IRouteRequest
-from pyramid.interfaces import IRoutesMapper
-from pyramid.interfaces import ISecuredView
-from pyramid.interfaces import ISessionFactory
-from pyramid.interfaces import IStaticURLInfo
-from pyramid.interfaces import ITranslationDirectories
-from pyramid.interfaces import ITraverser
-from pyramid.interfaces import IView
-from pyramid.interfaces import IViewClassifier
-
-try:
- from pyramid import chameleon_text
-except TypeError: # pragma: no cover
- chameleon_text = None # pypy
-try:
- from pyramid import chameleon_zpt
-except TypeError: # pragma: no cover
- chameleon_zpt = None # pypy
-
-from pyramid import renderers
-from pyramid.authorization import ACLAuthorizationPolicy
-from pyramid.compat import all
-from pyramid.compat import md5
-from pyramid.events import ApplicationCreated
-from pyramid.exceptions import ConfigurationError
-from pyramid.exceptions import Forbidden
-from pyramid.exceptions import NotFound
-from pyramid.exceptions import PredicateMismatch
-from pyramid.i18n import get_localizer
-from pyramid.log import make_stream_logger
-from pyramid.mako_templating import renderer_factory as mako_renderer_factory
+from pyramid.config import Configurator as BaseConfigurator
+from pyramid.config import ConfigurationError # API
+from pyramid.config import DEFAULT_RENDERERS
from pyramid.path import caller_package
-from pyramid.path import package_path
-from pyramid.path import package_of
-from pyramid.registry import Registry
-from pyramid.renderers import RendererHelper
-from pyramid.request import route_request_iface
-from pyramid.resource import PackageOverrides
-from pyramid.resource import resolve_resource_spec
-from pyramid.settings import Settings
-from pyramid.static import StaticURLInfo
-from pyramid.threadlocal import get_current_registry
-from pyramid.threadlocal import get_current_request
-from pyramid.threadlocal import manager
-from pyramid.traversal import DefaultRootFactory
-from pyramid.traversal import find_interface
-from pyramid.traversal import traversal_path
-from pyramid.urldispatch import RoutesMapper
-from pyramid.util import DottedNameResolver
-from pyramid.view import default_exceptionresponse_view
-from pyramid.view import render_view_to_response
-
-MAX_ORDER = 1 << 30
-DEFAULT_PHASH = md5().hexdigest()
-
-DEFAULT_RENDERERS = (
- ('.mak', mako_renderer_factory),
- ('.mako', mako_renderer_factory),
- ('json', renderers.json_renderer_factory),
- ('string', renderers.string_renderer_factory),
- )
-
-if chameleon_text:
- DEFAULT_RENDERERS += (('.pt', chameleon_zpt.renderer_factory),)
-if chameleon_zpt:
- DEFAULT_RENDERERS += (('.txt', chameleon_text.renderer_factory),)
-
-def config_method(wrapped):
- def wrapper(self, *arg, **kw):
- context = self._ctx
- if context is not None:
- if (not context.autocommit) and (not context.info):
- # Try to provide more accurate info for conflict reports by
- # wrapping the context in a decorator and attaching caller info
- # to it, unless the context already has info (if it already has
- # info, it's likely a context generated by a ZCML directive).
- # This is nasty.
- newctx = GroupingContextDecorator(context)
- try:
- f = traceback.extract_stack(limit=3)
- info = f[-2]
- except:
- info = ''
- newctx.info = info
- self._ctx = newctx
- result = wrapped(self, *arg, **kw)
- if context is not None:
- self._ctx = context
- return result
- wrapper.__doc__ = wrapped.__doc__
- wrapper.__name__ = wrapped.__name__
- return wrapper
-
-class Config(object):
- """
- A Configurator is used to configure a :app:`Pyramid`
- :term:`application registry`.
-
- The Configurator accepts a number of arguments: ``registry``,
- ``package``, ``settings``, ``root_factory``,
- ``authentication_policy``, ``authorization_policy``, ``renderers``
- ``debug_logger``, ``locale_negotiator``, ``request_factory``, and
- ``renderer_globals_factory``.
-
- If the ``registry`` argument is passed as a non-``None`` value, it
- must be an instance of the :class:`pyramid.registry.Registry`
- class representing the registry to configure. If ``registry`` is
- ``None``, the configurator will create a
- :class:`pyramid.registry.Registry` instance itself; it will
- also perform some default configuration that would not otherwise
- be done. After construction, the configurator may be used to add
- configuration to the registry. The overall state of a registry is
- called the 'configuration state'.
-
- .. warning:: If a ``registry`` is passed to the Configurator
- constructor, all other constructor arguments except ``package``
- are ignored.
-
- If the ``package`` argument is passed, it must be a reference to a
- Python :term:`package` (e.g. ``sys.modules['thepackage']``) or a
- :term:`dotted Python name` to same. This value is used as a basis
- to convert relative paths passed to various configuration methods,
- such as methods which accept a ``renderer`` argument, into
- absolute paths. If ``None`` is passed (the default), the package
- is assumed to be the Python package in which the *caller* of the
- ``Configurator`` constructor lives.
-
- If the ``settings`` argument is passed, it should be a Python dictionary
- representing the deployment settings for this application. These are
- later retrievable using the :attr:`pyramid.registry.Registry.settings`
- attribute (aka ``request.registry.settings``).
-
- If the ``root_factory`` argument is passed, it should be an object
- representing the default :term:`root factory` for your application
- or a :term:`dotted Python name` to same. If it is ``None``, a
- default root factory will be used.
-
- If ``authentication_policy`` is passed, it should be an instance
- of an :term:`authentication policy` or a :term:`dotted Python
- name` to same.
-
- If ``authorization_policy`` is passed, it should be an instance of
- an :term:`authorization policy` or a :term:`dotted Python name` to
- same.
-
- .. note:: A ``ConfigurationError`` will be raised when an
- authorization policy is supplied without also supplying an
- authentication policy (authorization requires authentication).
-
- If ``renderers`` is passed, it should be a list of tuples
- representing a set of :term:`renderer` factories which should be
- configured into this application (each tuple representing a set of
- positional values that should be passed to
- :meth:`pyramid.configuration.Configurator.add_renderer`). If
- it is not passed, a default set of renderer factories is used.
-
- If ``debug_logger`` is not passed, a default debug logger that
- logs to stderr will be used. If it is passed, it should be an
- instance of the :class:`logging.Logger` (PEP 282) standard library
- class or a :term:`dotted Python name` to same. The debug logger
- is used by :app:`Pyramid` itself to log warnings and
- authorization debugging information.
-
- If ``locale_negotiator`` is passed, it should be a :term:`locale
- negotiator` implementation or a :term:`dotted Python name` to
- same. See :ref:`custom_locale_negotiator`.
-
- If ``request_factory`` is passed, it should be a :term:`request
- factory` implementation or a :term:`dotted Python name` to same.
- See :ref:`custom_request_factory`. By default it is ``None``,
- which means use the default request factory.
-
- If ``renderer_globals_factory`` is passed, it should be a
- :term:`renderer globals` factory implementation or a :term:`dotted
- Python name` to same. See :ref:`custom_renderer_globals_factory`.
- By default, it is ``None``, which means use no renderer globals
- factory.
-
- If ``default_permission`` is passed, it should be a
- :term:`permission` string to be used as the default permission for
- all view configuration registrations performed against this
- Configurator. An example of a permission string:``'view'``.
- Adding a default permission makes it unnecessary to protect each
- view configuration with an explicit permission, unless your
- application policy requires some exception for a particular view.
- By default, ``default_permission`` is ``None``, meaning that view
- configurations which do not explicitly declare a permission will
- always be executable by entirely anonymous users (any
- authorization policy in effect is ignored). See also
- :ref:`setting_a_default_permission`.
-
- If ``session_factory`` is passed, it should be an object which
- implements the :term:`session factory` interface. If a nondefault
- value is passed, the ``session_factory`` will be used to create a
- session object when ``request.session`` is accessed. Note that
- the same outcome can be achieved by calling
- :ref:`pyramid.configration.Configurator.set_session_factory`. By
- default, this argument is ``None``, indicating that no session
- factory will be configured (and thus accessing ``request.session``
- will throw an error) unless ``set_session_factory`` is called later
- during configuration. """
-
- manager = manager # for testing injection
- venusian = venusian # for testing injection
- _ctx = None
-
- def __init__(self,
- registry=None,
- package=None,
- settings=None,
- root_factory=None,
- authentication_policy=None,
- authorization_policy=None,
- renderers=DEFAULT_RENDERERS,
- debug_logger=None,
- locale_negotiator=None,
- request_factory=None,
- renderer_globals_factory=None,
- default_permission=None,
- session_factory=None,
- autocommit=False,
- ):
- if package is None:
- package = caller_package()
- name_resolver = DottedNameResolver(package)
- self.name_resolver = name_resolver
- self.package_name = name_resolver.package_name
- self.package = name_resolver.package
- self.registry = registry
- self.autocommit = autocommit
- if registry is None:
- registry = Registry(self.package_name)
- self.registry = registry
- self.setup_registry(
- settings=settings,
- root_factory=root_factory,
- authentication_policy=authentication_policy,
- authorization_policy=authorization_policy,
- renderers=renderers,
- debug_logger=debug_logger,
- locale_negotiator=locale_negotiator,
- request_factory=request_factory,
- renderer_globals_factory=renderer_globals_factory,
- default_permission=default_permission,
- session_factory=session_factory,
- )
-
- def _action(self, discriminator, callable=None, args=(), kw=None, order=0):
- """ Register an action which will be executed during a commit. """
- if kw is None:
- kw = {}
- if self.autocommit:
- if callable is not None:
- callable(*args, **kw)
- else:
- if self._ctx is None:
- self._ctx = self._make_context(self.autocommit)
- self._ctx.action(discriminator, callable, args, kw, order)
-
- def _set_settings(self, mapping):
- settings = Settings(mapping or {})
- self.registry.settings = settings
- return settings
-
- @config_method
- def _set_root_factory(self, factory):
- """ Add a :term:`root factory` to the current configuration
- state. If the ``factory`` argument is ``None`` a default root
- factory will be registered."""
- factory = self.maybe_dotted(factory)
- if factory is None:
- factory = DefaultRootFactory
- def register():
- self.registry.registerUtility(factory, IRootFactory)
- self.registry.registerUtility(factory, IDefaultRootFactory) # b/c
- self._action(IRootFactory, register)
-
- @config_method
- def _set_authentication_policy(self, policy):
- """ Add a :app:`Pyramid` :term:`authentication policy` to
- the current configuration."""
- policy = self.maybe_dotted(policy)
- self.registry.registerUtility(policy, IAuthenticationPolicy)
- self._action(IAuthenticationPolicy)
-
- @config_method
- def _set_authorization_policy(self, policy):
- """ Add a :app:`Pyramid` :term:`authorization policy` to
- the current configuration state (also accepts a :term:`dotted
- Python name`."""
- policy = self.maybe_dotted(policy)
- self.registry.registerUtility(policy, IAuthorizationPolicy)
- self._action(IAuthorizationPolicy, None)
-
- def _make_spec(self, path_or_spec):
- package, filename = resolve_resource_spec(path_or_spec,
- self.package_name)
- if package is None:
- return filename # absolute filename
- return '%s:%s' % (package, filename)
-
- def _split_spec(self, path_or_spec):
- return resolve_resource_spec(path_or_spec, self.package_name)
-
- 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):
- if renderer is None: # use default renderer if one exists
- default_renderer_factory = self.registry.queryUtility(
- IRendererFactory)
- if default_renderer_factory is not None:
- renderer = {'name':None, 'package':self.package}
- view = self.maybe_dotted(view)
- authn_policy = self.registry.queryUtility(IAuthenticationPolicy)
- authz_policy = self.registry.queryUtility(IAuthorizationPolicy)
- settings = self.registry.settings
- logger = self.registry.queryUtility(IDebugLogger)
- mapped_view = _map_view(view, self.registry, attr, renderer)
- owrapped_view = _owrap_view(mapped_view, viewname, wrapper_viewname)
- secured_view = _secure_view(owrapped_view, permission,
- authn_policy, authz_policy)
- debug_view = _authdebug_view(secured_view, permission,
- authn_policy, authz_policy, settings,
- logger)
- predicated_view = _predicate_wrap(debug_view, predicates)
- derived_view = _attr_wrap(predicated_view, accept, order, phash)
- return derived_view
-
- def _override(self, package, path, override_package, override_prefix,
- PackageOverrides=PackageOverrides):
- pkg_name = package.__name__
- override_pkg_name = override_package.__name__
- override = self.registry.queryUtility(
- IPackageOverrides, name=pkg_name)
- if override is None:
- override = PackageOverrides(package)
- self.registry.registerUtility(override, IPackageOverrides,
- name=pkg_name)
- override.insert(path, override_pkg_name, override_prefix)
-
- def _set_security_policies(self, authentication, authorization=None):
- if authorization is None:
- authorization = ACLAuthorizationPolicy() # default
- if authorization and not authentication:
- raise ConfigurationError(
- 'If the "authorization" is passed a value, '
- 'the "authentication" argument must also be '
- 'passed a value; authorization requires authentication.')
- self._set_authentication_policy(authentication)
- self._set_authorization_policy(authorization)
-
- def _fix_registry(self):
- """ Fix up a ZCA component registry that is not a
- pyramid.registry.Registry by adding analogues of ``has_listeners``,
- and ``notify`` through monkey-patching."""
-
- _registry = self.registry
-
- if not hasattr(_registry, 'notify'):
- def notify(*events):
- [ _ for _ in _registry.subscribers(events, None) ]
- _registry.notify = notify
-
- if not hasattr(_registry, 'has_listeners'):
- _registry.has_listeners = True
-
- def _make_context(self, autocommit=False):
- context = PyramidConfigurationMachine()
- registerCommonDirectives(context)
- context.registry = self.registry
- context.autocommit = autocommit
- return context
-
- # API
-
- def commit(self):
- """ Commit pending configuration actions. """
- if self._ctx is None:
- return
- self._ctx.execute_actions()
- # unwrap and reset the context
- self._ctx = None
-
- @classmethod
- def with_context(cls, context):
- """ Used by ZCML directives to obtain a configurator with 'the right'
- context """
- configurator = cls(registry=context.registry, package=context.package,
- autocommit=context.autocommit)
- configurator._ctx = context
- return configurator
-
- def with_package(self, package):
- """ Return a new Configurator instance with the same registry
- as this configurator using the package supplied as the
- ``package`` argument to the new configurator. ``package`` may
- be an actual Python package object or a Python dotted name
- representing a package."""
- context = self._ctx
- if context is None:
- context = self._ctx = self._make_context(self.autocommit)
- context = GroupingContextDecorator(context)
- context.package = package
- return self.__class__.with_context(context)
-
- def maybe_dotted(self, dotted):
- """ Resolve the :term:`dotted Python name` ``dotted`` to a
- global Python object. If ``dotted`` is not a string, return
- it without attempting to do any name resolution. If
- ``dotted`` is a relative dotted name (e.g. ``.foo.bar``,
- consider it relative to the ``package`` argument supplied to
- this Configurator's constructor."""
- return self.name_resolver.maybe_resolve(dotted)
-
- def absolute_resource_spec(self, relative_spec):
- """ Resolve the potentially relative :term:`resource
- specification` string passed as ``relative_spec`` into an
- absolute resource specification string and return the string.
- Use the ``package`` of this configurator as the package to
- which the resource specification will be considered relative
- when generating an absolute resource specification. If the
- provided ``relative_spec`` argument is already absolute, or if
- the ``relative_spec`` is not a string, it is simply returned."""
- if not isinstance(relative_spec, basestring):
- return relative_spec
- return self._make_spec(relative_spec)
-
- def setup_registry(self, settings=None, root_factory=None,
- authentication_policy=None, authorization_policy=None,
- renderers=DEFAULT_RENDERERS, debug_logger=None,
- locale_negotiator=None, request_factory=None,
- renderer_globals_factory=None,
- default_permission=None,
- session_factory=None):
- """ When you pass a non-``None`` ``registry`` argument to the
- :term:`Configurator` constructor, no initial 'setup' is
- performed against the registry. This is because the registry
- you pass in may have already been initialized for use under
- :app:`Pyramid` via a different configurator. However, in
- some circumstances, such as when you want to use the Zope
- 'global` registry instead of a registry created as a result of
- the Configurator constructor, or when you want to reset the
- initial setup of a registry, you *do* want to explicitly
- initialize the registry associated with a Configurator for use
- under :app:`Pyramid`. Use ``setup_registry`` to do this
- initialization.
-
- ``setup_registry`` configures settings, a root factory,
- security policies, renderers, a debug logger, a locale
- negotiator, and various other settings using the
- configurator's current registry, as per the descriptions in
- the Configurator constructor."""
- registry = self.registry
- self._fix_registry()
- self._set_settings(settings)
- self._set_root_factory(root_factory)
- debug_logger = self.maybe_dotted(debug_logger)
- if debug_logger is None:
- debug_logger = make_stream_logger('pyramid.debug', sys.stderr)
- registry.registerUtility(debug_logger, IDebugLogger)
- if authentication_policy or authorization_policy:
- self._set_security_policies(authentication_policy,
- authorization_policy)
- for name, renderer in renderers:
- self.add_renderer(name, renderer)
- self.add_view(default_exceptionresponse_view,
- context=IExceptionResponse)
- if locale_negotiator:
- locale_negotiator = self.maybe_dotted(locale_negotiator)
- registry.registerUtility(locale_negotiator, ILocaleNegotiator)
- if request_factory:
- request_factory = self.maybe_dotted(request_factory)
- self.set_request_factory(request_factory)
- if renderer_globals_factory:
- renderer_globals_factory = self.maybe_dotted(
- renderer_globals_factory)
- self.set_renderer_globals_factory(renderer_globals_factory)
- if default_permission:
- self.set_default_permission(default_permission)
- if session_factory is not None:
- self.set_session_factory(session_factory)
- self.commit()
-
- # getSiteManager is a unit testing dep injection
- def hook_zca(self, getSiteManager=None):
- """ Call :func:`zope.component.getSiteManager.sethook` with
- the argument
- :data:`pyramid.threadlocal.get_current_registry`, causing
- the :term:`Zope Component Architecture` 'global' APIs such as
- :func:`zope.component.getSiteManager`,
- :func:`zope.component.getAdapter` and others to use the
- :app:`Pyramid` :term:`application registry` rather than the
- Zope 'global' registry. If :mod:`zope.component` cannot be
- imported, this method will raise an :exc:`ImportError`."""
- if getSiteManager is None:
- from zope.component import getSiteManager
- getSiteManager.sethook(get_current_registry)
-
- # getSiteManager is a unit testing dep injection
- def unhook_zca(self, getSiteManager=None):
- """ Call :func:`zope.component.getSiteManager.reset` to undo
- the action of
- :meth:`pyramid.configuration.Configurator.hook_zca`. If
- :mod:`zope.component` cannot be imported, this method will
- raise an :exc:`ImportError`."""
- if getSiteManager is None: # pragma: no cover
- from zope.component import getSiteManager
- getSiteManager.reset()
-
- def begin(self, request=None):
- """ Indicate that application or test configuration has begun.
- This pushes a dictionary containing the :term:`application
- registry` implied by ``registry`` attribute of this
- configurator and the :term:`request` implied by the
- ``request`` argument on to the :term:`thread local` stack
- consulted by various :mod:`pyramid.threadlocal` API
- functions."""
- self.manager.push({'registry':self.registry, 'request':request})
-
- def end(self):
- """ Indicate that application or test configuration has ended.
- This pops the last value pushed on to the :term:`thread local`
- stack (usually by the ``begin`` method) and returns that
- value.
- """
- return self.manager.pop()
-
- 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.
-
- 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. """
-
- if renderer is not None and not isinstance(renderer, dict):
- renderer = {'name':renderer, 'package':self.package}
- return self._derive_view(view, attr=attr, renderer=renderer)
-
- @config_method
- def add_subscriber(self, subscriber, iface=None):
- """Add an event :term:`subscriber` for the event stream
- implied by the supplied ``iface`` interface. The
- ``subscriber`` argument represents a callable object (or a
- :term:`dotted Python name` which identifies a callable); it
- will be called with a single object ``event`` whenever
- :app:`Pyramid` emits an :term:`event` associated with the
- ``iface``, which may be an :term:`interface` or a class or a
- :term:`dotted Python name` to a global object representing an
- interface or a class. Using the default ``iface`` value,
- ``None`` will cause the subscriber to be registered for all
- event types. See :ref:`events_chapter` for more information
- about events and subscribers."""
- dotted = self.maybe_dotted
- subscriber, iface = dotted(subscriber), dotted(iface)
- if iface is None:
- iface = (Interface,)
- if not isinstance(iface, (tuple, list)):
- iface = (iface,)
- def register():
- self.registry.registerHandler(subscriber, iface)
- self._action(None, register)
- return subscriber
-
- def add_settings(self, settings=None, **kw):
- """Augment the ``settings`` argument passed in to the Configurator
- constructor with one or more 'setting' key/value pairs. A setting is
- a single key/value pair in the dictionary-ish object returned from
- the API :attr:`pyramid.registry.Registry.settings` and
- :meth:`pyramid.configuration.Configurator.get_settings`.
-
- You may pass a dictionary::
-
- config.add_settings({'external_uri':'http://example.com'})
-
- Or a set of key/value pairs::
-
- config.add_settings(external_uri='http://example.com')
-
- This function is useful when you need to test code that accesses the
- :attr:`pyramid.registry.Registry.settings` API (or the
- :meth:`pyramid.configuration.Configurator.get_settings` API) and
- which uses values from that API.
- """
- if settings is None:
- settings = {}
- utility = self.registry.settings
- if utility is None:
- utility = self._set_settings(settings)
- utility.update(settings)
- utility.update(kw)
-
- def get_settings(self):
- """
- Return a 'settings' object for the current application. A
- 'settings' object is a dictionary-like object that contains
- key/value pairs based on the dictionary passed as the ``settings``
- argument to the :class:`pyramid.configuration.Configurator`
- constructor or the :func:`pyramid.router.make_app` API.
-
- .. note:: For backwards compatibility, dictionary keys can also be
- looked up as attributes of the settings object.
-
- .. note:: the :attr:`pyramid.registry.Registry.settings` API
- performs the same duty.
- """
- return self.registry.settings
-
- def make_wsgi_app(self):
- """ Returns a :app:`Pyramid` WSGI application representing
- the current configuration state and sends a
- :class:`pyramid.events.ApplicationCreated`
- event to all listeners."""
- self.commit()
- from pyramid.router import Router # avoid circdep
- app = Router(self.registry)
- # We push the registry on to the stack here in case any code
- # that depends on the registry threadlocal APIs used in
- # listeners subscribed to the IApplicationCreated event.
- self.manager.push({'registry':self.registry, 'request':None})
- try:
- self.registry.notify(ApplicationCreated(app))
- finally:
- self.manager.pop()
- return app
-
- @config_method
- def load_zcml(self, spec='configure.zcml', lock=threading.Lock()):
- """ Load configuration from a :term:`ZCML` file into the
- current configuration state. The ``spec`` argument is an
- absolute filename, a relative filename, or a :term:`resource
- specification`, defaulting to ``configure.zcml`` (relative to
- the package of the configurator's caller)."""
- package_name, filename = self._split_spec(spec)
- if package_name is None: # absolute filename
- package = self.package
- else:
- __import__(package_name)
- package = sys.modules[package_name]
-
- registry = self.registry
- self.manager.push({'registry':registry, 'request':None})
- context = self._ctx
- if context is None:
- context = self._ctx = self._make_context(self.autocommit)
-
- lock.acquire()
- try:
- context.package = package
- xmlconfig.file(filename, package, context=context,
- execute=self.autocommit)
- finally:
- lock.release()
- self.manager.pop()
- return registry
-
- def include(self, *funcs):
- """ Include one or more configuration callables. A configuration
- callable should be a callable that accepts a single argument named
- ``config``, which will be an instance of a :term:`Configurator`. (be
- warned that it will not be the same configurator instance on which
- you call this method, however). The code which runs as the result of
- calling the callable should invoke methods on the configurator which
- add configuration state. The return value of a callable will be
- ignored.
-
- Values allowed to be presented via the ``*funcs`` argument to this
- method: any callable Python object or any :term:`dotted Python name`
- which resolves to a callable Python object.
- """
- sourcefiles = []
-
- for func in funcs:
- func = self.maybe_dotted(func)
- sourcefile = inspect.getsourcefile(func)
- module = inspect.getmodule(func)
- sourcefiles.append((sourcefile, func, module))
-
- _context = self._ctx
- if _context is None:
- _context = self._ctx = self._make_context(self.autocommit)
-
- for filename, func, module in sourcefiles:
- spec = module.__name__ + ':' + func.__name__
- if _context.processSpec(spec):
- context = GroupingContextDecorator(_context)
- context.basepath = os.path.dirname(filename)
- context.includepath = _context.includepath + (spec,)
- context.package = package_of(module)
- config = self.__class__.with_context(context)
- func(config)
-
- def add_handler(self, route_name, pattern, handler, action=None, **kw):
-
- """ Add a Pylons-style view handler. This function adds a
- route and some number of views based on a handler object
- (usually a class).
-
- ``route_name`` is the name of the route (to be used later in
- URL generation).
-
- ``pattern`` is the matching pattern,
- e.g. ``'/blog/{action}'``. ``pattern`` may be ``None``, in
- which case the pattern of an existing route named the same as
- ``route_name`` is used. If ``pattern`` is ``None`` and no
- route named ``route_name`` exists, a ``ConfigurationError`` is
- raised.
-
- ``handler`` is a dotted name of (or direct reference to) a
- Python handler class,
- e.g. ``'my.package.handlers.MyHandler'``.
-
- If ``{action}`` or ``:action`` is in
- the pattern, the exposed methods of the handler will be used
- as views.
-
- If ``action`` is passed, it will be considered the method name
- of the handler to use as a view.
-
- Passing both ``action`` and having an ``{action}`` in the
- route pattern is disallowed.
-
- Any extra keyword arguments are passed along to ``add_route``.
-
- See :ref:`handlers_chapter` for more explanatory documentation.
-
- This method returns the result of add_route."""
- handler = self.maybe_dotted(handler)
-
- if pattern is not None:
- route = self.add_route(route_name, pattern, **kw)
- else:
- mapper = self.get_routes_mapper()
- route = mapper.get_route(route_name)
- if route is None:
- raise ConfigurationError(
- 'The "pattern" parameter may only be "None" when a route '
- 'with the route_name argument was previously registered. '
- 'No such route named %r exists' % route_name)
-
- pattern = route.pattern
-
- path_has_action = ':action' in pattern or '{action}' in pattern
-
- if action and path_has_action:
- raise ConfigurationError(
- 'action= (%r) disallowed when an action is in the route '
- 'path %r' % (action, pattern))
-
- if path_has_action:
- autoexpose = getattr(handler, '__autoexpose__', r'[A-Za-z]+')
- if autoexpose:
- try:
- autoexpose = re.compile(autoexpose).match
- except (re.error, TypeError), why:
- raise ConfigurationError(why[0])
- for method_name, method in inspect.getmembers(
- handler, inspect.ismethod):
- configs = getattr(method, '__exposed__', [])
- if autoexpose and not configs:
- if autoexpose(method_name):
- configs = [{}]
- for expose_config in configs:
- # we don't want to mutate any dict in __exposed__,
- # so we copy each
- view_args = expose_config.copy()
- action = view_args.pop('name', method_name)
- preds = list(view_args.pop('custom_predicates', []))
- preds.append(ActionPredicate(action))
- view_args['custom_predicates'] = preds
- self.add_view(view=handler, attr=method_name,
- route_name=route_name, **view_args)
- else:
- method_name = action
- if method_name is None:
- method_name = '__call__'
-
- # Scan the controller for any other methods with this action name
- for meth_name, method in inspect.getmembers(
- handler, inspect.ismethod):
- configs = getattr(method, '__exposed__', [{}])
- for expose_config in configs:
- # Don't re-register the same view if this method name is
- # the action name
- if meth_name == action:
- continue
- # We only reg a view if the name matches the action
- if expose_config.get('name') != method_name:
- continue
- # we don't want to mutate any dict in __exposed__,
- # so we copy each
- view_args = expose_config.copy()
- del view_args['name']
- self.add_view(view=handler, attr=meth_name,
- route_name=route_name, **view_args)
-
- # Now register the method itself
- method = getattr(handler, method_name, None)
- configs = getattr(method, '__exposed__', [{}])
- for expose_config in configs:
- self.add_view(view=handler, attr=action, route_name=route_name,
- **expose_config)
-
- return route
-
- @config_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=False, accept=None,
- header=None, path_info=None, custom_predicates=(),
- context=None):
- """ 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
-
- The name of 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. If ``permission`` is omitted, a
- *default* permission may be used for this view registration
- if one was named as the
- :class:`pyramid.configuration.Configurator` constructor's
- ``default_permission`` argument, or if
- :meth:`pyramid.configuration.Configurator.set_default_permission`
- was used prior to this view registration. Pass the string
- ``__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
-
- 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. This is
- most useful when the view definition is a class.
-
- renderer
-
- This is either a single string term (e.g. ``json``) or a
- string implying a path or :term:`resource 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:`resource specification` in the form
- ``some.dotted.package_name:relative/path``, making it
- possible to address template resources 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 unmolested).
-
- 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.
-
- 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. Note that
- the ``route`` configuration referred to by ``route_name``
- usually has a ``*traverse`` token in the value of its
- ``path``, representing a part of the path that will be used
- by :term:`traversal` against the result of the route's
- :term:`root factory`.
-
- .. warning:: Using this argument services an advanced
- feature that isn't often used unless you want to perform
- traversal *after* a route has matched. See
- :ref:`hybrid_chapter` for more information on using this
- advanced feature.
-
- 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 either be one of the strings ``GET``,
- ``POST``, ``PUT``, ``DELETE``, or ``HEAD`` representing an
- HTTP ``REQUEST_METHOD``. A view declaration with this
- argument ensures that the view will only be called when the
- request's ``method`` attribute (aka the ``REQUEST_METHOD`` of
- the WSGI environment) string matches the supplied value.
-
- request_param
-
- This value can be any string. 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
- supplied has a ``=`` sign in it,
- e.g. ``request_params="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.
-
- containment
-
- This value should be a Python class or :term:`interface` or
- a :term:`dotted Python name` to such an object that a parent
- object in the :term:`lineage` 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.
-
- accept
-
- The value of this argument 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, this predicate will be true.
-
- 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``.
-
-
- custom_predicates
-
- 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. If all callables return
- ``True``, the associated view callable will be considered
- viable for a given request.
-
- """
- view = self.maybe_dotted(view)
- context = self.maybe_dotted(context)
- for_ = self.maybe_dotted(for_)
- containment = self.maybe_dotted(containment)
-
- 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)
-
- request_iface = IRequest
-
- if route_name is not None:
- request_iface = self.registry.queryUtility(IRouteRequest,
- name=route_name)
- if request_iface is None:
- deferred_views = getattr(self.registry,
- 'deferred_route_views', None)
- if deferred_views is None:
- deferred_views = self.registry.deferred_route_views = {}
- info = dict(
- view=view, name=name, for_=for_, permission=permission,
- request_type=request_type, route_name=route_name,
- request_method=request_method, request_param=request_param,
- containment=containment, attr=attr,
- renderer=renderer, wrapper=wrapper, xhr=xhr, accept=accept,
- header=header, path_info=path_info,
- custom_predicates=custom_predicates, context=context,
- )
- view_info = deferred_views.setdefault(route_name, [])
- view_info.append(info)
- return
-
- order, predicates, phash = _make_predicates(xhr=xhr,
- request_method=request_method, path_info=path_info,
- request_param=request_param, header=header, accept=accept,
- containment=containment, request_type=request_type,
- custom=custom_predicates)
-
- if renderer is not None and not isinstance(renderer, dict):
- renderer = {'name':renderer, 'package':self.package}
-
- 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)
-
- def register(permission=permission):
-
- if permission is None:
- # intent: will be None if no default permission is registered
- permission = self.registry.queryUtility(IDefaultPermission)
-
- # NO_PERMISSION_REQUIRED handled by _secure_view
- derived_view = self._derive_view(view, permission, predicates, attr,
- renderer, wrapper, name, accept,
- order, phash)
-
- 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)
-
- discriminator = [
- 'view', context, name, request_type, IView, containment,
- request_param, request_method, route_name, attr,
- xhr, accept, header, path_info]
- discriminator.extend(sorted(custom_predicates))
- discriminator = tuple(discriminator)
- self._action(discriminator, register)
-
- @config_method
- def add_route(self,
- name,
- pattern=None,
- view=None,
- view_for=None,
- permission=None,
- factory=None,
- for_=None,
- header=None,
- xhr=False,
- accept=None,
- path_info=None,
- request_method=None,
- request_param=None,
- traverse=None,
- custom_predicates=(),
- view_permission=None,
- renderer=None,
- view_renderer=None,
- view_context=None,
- view_attr=None,
- use_global_views=False,
- path=None,
- pregenerator=None,
- ):
- """ Add a :term:`route configuration` to the current
- configuration state, as well as possibly a :term:`view
- configuration` to be used to specify a :term:`view callable`
- that will be invoked when this route matches. The arguments
- to this method are divided into *predicate*, *non-predicate*,
- and *view-related* types. :term:`Route predicate` arguments
- narrow the circumstances in which a route will be match a
- request; non-predicate arguments are informational.
-
- Non-Predicate Arguments
-
- name
-
- The name of the route, e.g. ``myroute``. This attribute is
- required. It must be unique among all defined routes in a given
- application.
-
- factory
-
- A Python object (often a function or a class) or a
- :term:`dotted Python name` which refers to the same object
- that will generate a :app:`Pyramid` :term:`context`
- object when this route matches. For example,
- ``mypackage.models.MyFactoryClass``. If this argument is
- not specified, a default root factory will be used.
-
- traverse
-
- If you would like to cause the :term:`context` to be
- something other than the :term:`root` object when this route
- matches, you can spell a traversal pattern as the
- ``traverse`` argument. This traversal pattern will be used
- as the traversal path: traversal will begin at the root
- object implied by this route (either the global root, or the
- object returned by the ``factory`` associated with this
- route).
-
- The syntax of the ``traverse`` argument is the same as it is
- for ``pattern``. For example, if the ``pattern`` provided to
- ``add_route`` is ``articles/{article}/edit``, and the
- ``traverse`` argument provided to ``add_route`` is
- ``/{article}``, when a request comes in that causes the route
- to match in such a way that the ``article`` match value is
- '1' (when the request URI is ``/articles/1/edit``), the
- traversal path will be generated as ``/1``. This means that
- the root object's ``__getitem__`` will be called with the
- name ``1`` during the traversal phase. If the ``1`` object
- exists, it will become the :term:`context` of the request.
- :ref:`traversal_chapter` has more information about
- traversal.
-
- If the traversal path contains segment marker names which
- are not present in the ``pattern`` argument, a runtime error
- will occur. The ``traverse`` pattern should not contain
- segment markers that do not exist in the ``pattern``
- argument.
-
- A similar combining of routing and traversal is available
- when a route is matched which contains a ``*traverse``
- remainder marker in its pattern (see
- :ref:`using_traverse_in_a_route_pattern`). The ``traverse``
- argument to add_route allows you to associate route patterns
- with an arbitrary traversal path without using a a
- ``*traverse`` remainder marker; instead you can use other
- match information.
-
- Note that the ``traverse`` argument to ``add_route`` is
- ignored when attached to a route that has a ``*traverse``
- remainder marker in its pattern.
-
- pregenerator
- This option should be a callable object that implements the
- :class:`pyramid.interfaces.IRoutePregenerator`
- interface. A :term:`pregenerator` is a callable called by
- the :mod:`pyramid.url.route_url` function to augment or
- replace the arguments it is passed when generating a URL
- for the route. This is a feature not often used directly
- by applications, it is meant to be hooked by frameworks
- that use :app:`Pyramid` as a base.
-
- Predicate Arguments
-
- pattern
-
- The pattern of the route e.g. ``ideas/{idea}``. This
- argument is required. See :ref:`route_path_pattern_syntax`
- for information about the syntax of route patterns. If the
- pattern doesn't match the current URL, route matching
- continues.
-
- .. note:: For backwards compatibility purposes (as of
- :app:`Pyramid` 1.0), a ``path`` keyword argument passed
- to this function will be used to represent the pattern
- value if the ``pattern`` argument is ``None``. If both
- ``path`` and ``pattern`` are passed, ``pattern`` wins.
-
- 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 for this route to match. This
- is useful for detecting AJAX requests issued from jQuery,
- Prototype and other Javascript libraries. If this predicate
- returns ``False``, route matching continues.
-
- request_method
-
- A string representing an HTTP method name, e.g. ``GET``,
- ``POST``, ``HEAD``, ``DELETE``, ``PUT``. If this argument
- is not specified, this route will match if the request has
- *any* request method. If this predicate returns ``False``,
- route matching continues.
-
- 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 return
- ``True``. If this predicate returns ``False``, route
- matching continues.
-
- request_param
-
- This value can be any string. A view declaration with this
- argument ensures that the associated route will only match
- when the 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
- supplied as the argument has a ``=`` sign in it,
- e.g. ``request_params="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 route to "match" the current request. If this predicate
- returns ``False``, route matching continues.
-
- header
-
- This argument represents an HTTP header name or a header
- name/value pair. If the argument contains a ``:`` (colon),
- it will be considered a name/value pair
- (e.g. ``User-Agent:Mozilla/.*`` or ``Host:localhost``). If
- the value contains a colon, 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. If this
- predicate returns ``False``, route matching continues.
-
- 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, this predicate will be true. If this predicate
- returns ``False``, route matching continues.
-
- custom_predicates
-
- This value should be a sequence of references to custom
- predicate callables. Use custom predicates when no set of
- predefined predicates does what you need. Custom predicates
- can be combined with predefined predicates as necessary.
- Each custom predicate callable should accept two arguments:
- ``info`` and ``request`` and should return either ``True``
- or ``False`` after doing arbitrary evaluation of the info
- and/or the request. If all custom and non-custom predicate
- callables return ``True`` the associated route will be
- considered viable for a given request. If any predicate
- callable returns ``False``, route matching continues. Note
- that the value ``info`` passed to a custom route predicate
- is a dictionary containing matching information; see
- :ref:`custom_route_predicates` for more information about
- ``info``.
-
- View-Related Arguments
-
- view
-
- A Python object or :term:`dotted Python name` to the same
- object that will be used as a view callable when this route
- matches. e.g. ``mypackage.views.my_view``.
-
- view_context
-
- A class or an :term:`interface` or :term:`dotted Python
- name` to the same object which the :term:`context` of the
- view should match for the view named by the route to be
- used. This argument is only useful if the ``view``
- attribute is used. If this attribute is not specified, the
- default (``None``) will be used.
-
- If the ``view`` argument is not provided, this argument has
- no effect.
-
- This attribute can also be spelled as ``for_`` or ``view_for``.
-
- view_permission
-
- The permission name required to invoke the view associated
- with this route. e.g. ``edit``. (see
- :ref:`using_security_with_urldispatch` for more information
- about permissions).
-
- If the ``view`` attribute is not provided, this argument has
- no effect.
-
- This argument can also be spelled as ``permission``.
-
- view_renderer
-
- This is either a single string term (e.g. ``json``) or a
- string implying a path or :term:`resource specification`
- (e.g. ``templates/views.pt``). If the renderer value is a
- single term (does not contain a dot ``.``), the specified
- term 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 term
- 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 response
- from the view return value. See
- :ref:`views_which_use_a_renderer` for more information.
-
- If the ``view`` argument is not provided, this argument has
- no effect.
-
- This argument can also be spelled as ``renderer``.
-
- view_attr
-
- The view machinery defaults to using the ``__call__`` method
- of the view callable (or the function itself, if the view
- callable is a function) to obtain a response dictionary.
- 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. This is
- most useful when the view definition is a class.
-
- If the ``view`` argument is not provided, this argument has no
- effect.
-
- use_global_views
-
- When a request matches this route, and view lookup cannot
- find a view which has a ``route_name`` predicate argument
- that matches the route, try to fall back to using a view
- that otherwise matches the context, request, and view name
- (but which does not match the route_name predicate).
-
- """
- # these are route predicates; if they do not match, the next route
- # in the routelist will be tried
- ignored, predicates, ignored = _make_predicates(
- xhr=xhr,
- request_method=request_method,
- path_info=path_info,
- request_param=request_param,
- header=header,
- accept=accept,
- traverse=traverse,
- custom=custom_predicates
- )
-
- request_iface = self.registry.queryUtility(IRouteRequest, name=name)
- if request_iface is None:
- bases = use_global_views and (IRequest,) or ()
- request_iface = route_request_iface(name, bases)
- self.registry.registerUtility(
- request_iface, IRouteRequest, name=name)
- deferred_views = getattr(self.registry, 'deferred_route_views', {})
- view_info = deferred_views.pop(name, ())
- for info in view_info:
- self.add_view(**info)
-
- if view:
- if view_context is None:
- view_context = view_for
- if view_context is None:
- view_context = for_
- view_permission = view_permission or permission
- view_renderer = view_renderer or renderer
- self.add_view(
- permission=view_permission,
- context=view_context,
- view=view,
- name='',
- route_name=name,
- renderer=view_renderer,
- attr=view_attr,
- )
-
- mapper = self.get_routes_mapper()
-
- factory = self.maybe_dotted(factory)
- if pattern is None:
- pattern = path
- if pattern is None:
- raise ConfigurationError('"pattern" argument may not be None')
-
- discriminator = ['route', name, xhr, request_method, path_info,
- request_param, header, accept]
- discriminator.extend(sorted(custom_predicates))
- discriminator = tuple(discriminator)
-
- self._action(discriminator, None)
-
- return mapper.connect(name, pattern, factory, predicates=predicates,
- pregenerator=pregenerator)
-
- def get_routes_mapper(self):
- """ Return the :term:`routes mapper` object associated with
- this configurator's :term:`registry`."""
- mapper = self.registry.queryUtility(IRoutesMapper)
- if mapper is None:
- mapper = RoutesMapper()
- self.registry.registerUtility(mapper, IRoutesMapper)
- return mapper
-
- @config_method
- def scan(self, package=None, categories=None):
- """ Scan a Python package and any of its subpackages for
- objects marked with :term:`configuration decoration` such as
- :class:`pyramid.view.view_config`. Any decorated object found
- will influence the current configuration state.
-
- The ``package`` argument should be a Python :term:`package` or
- module object (or a :term:`dotted Python name` which refers to
- such a package or module). If ``package`` is ``None``, the
- package of the *caller* is used.
-
- The ``categories`` argument, if provided, should be the
- :term:`Venusian` 'scan categories' to use during scanning.
- Providing this argument is not often necessary; specifying
- scan categories is an extremely advanced usage.
-
- By default, ``categories`` is ``None`` which will execute
- *all* Venusian decorator callbacks including
- :app:`Pyramid`-related decorators such as
- :class:`pyramid.view.view_config`. If this is not desirable
- because the codebase has other Venusian-using decorators that
- aren't meant to be invoked during a particular scan, use
- ``('pyramid',)`` as a ``categories`` value to limit the execution
- of decorator callbacks to only those registered by
- :app:`Pyramid` itself. Or pass a sequence of Venusian scan
- categories as necessary (e.g. ``('pyramid', 'myframework')``) to
- limit the decorators called to the set of categories required.
- """
- package = self.maybe_dotted(package)
- if package is None: # pragma: no cover
- package = caller_package()
-
- scanner = self.venusian.Scanner(config=self)
- scanner.scan(package, categories=categories)
-
- @config_method
- def add_renderer(self, name, factory):
- """
- Add a :app:`Pyramid` :term:`renderer` factory to the
- current configuration state.
-
- The ``name`` argument is the renderer name. Use ``None`` to
- represent the default renderer (a renderer which will be used for all
- views unless they name another renderer specifically).
-
- The ``factory`` argument is Python reference to an
- implementation of a :term:`renderer` factory or a
- :term:`dotted Python name` to same.
-
- Note that this function must be called *before* any
- ``add_view`` invocation that names the renderer name as an
- argument. As a result, it's usually a better idea to pass
- globally used renderers into the ``Configurator`` constructor
- in the sequence of renderers passed as ``renderer`` than it is
- to use this method.
- """
- factory = self.maybe_dotted(factory)
- # if name is None or the empty string, we're trying to register
- # a default renderer, but registerUtility is too dumb to accept None
- # as a name
- if not name:
- name = ''
- # we need to register renderers eagerly because they are used during
- # view configuration
- self.registry.registerUtility(factory, IRendererFactory, name=name)
- self._action((IRendererFactory, name), None)
-
- @config_method
- def override_resource(self, to_override, override_with, _override=None):
- """ Add a :app:`Pyramid` resource override to the current
- configuration state.
-
- ``to_override`` is a :term:`resource specification` to the
- resource being overridden.
-
- ``override_with`` is a :term:`resource specification` to the
- resource that is performing the override.
-
- See :ref:`resources_chapter` for more
- information about resource overrides."""
- if to_override == override_with:
- raise ConfigurationError('You cannot override a resource with '
- 'itself')
-
- package = to_override
- path = ''
- if ':' in to_override:
- package, path = to_override.split(':', 1)
-
- override_package = override_with
- override_prefix = ''
- if ':' in override_with:
- override_package, override_prefix = override_with.split(':', 1)
-
- if path and path.endswith('/'):
- if override_prefix and (not override_prefix.endswith('/')):
- raise ConfigurationError(
- 'A directory cannot be overridden with a file (put a '
- 'slash at the end of override_with if necessary)')
-
- if override_prefix and override_prefix.endswith('/'):
- if path and (not path.endswith('/')):
- raise ConfigurationError(
- 'A file cannot be overridden with a directory (put a '
- 'slash at the end of to_override if necessary)')
-
- override = _override or self._override # test jig
- def register():
- __import__(package)
- __import__(override_package)
- from_package = sys.modules[package]
- to_package = sys.modules[override_package]
- override(from_package, path, to_package, override_prefix)
- self._action(None, register)
-
- def set_forbidden_view(self, view=None, attr=None, renderer=None,
- wrapper=None):
- """ Add a default forbidden view to the current configuration
- state.
-
- .. warning:: This method has been deprecated in :app:`Pyramid`
- 1.0. *Do not use it for new development; it should only be
- used to support older code bases which depend upon it.* See
- :ref:`changing_the_forbidden_view` to see how a forbidden
- view should be registered in new projects.
-
- The ``view`` argument should be a :term:`view callable` or a
- :term:`dotted Python name` which refers to a view callable.
-
- The ``attr`` argument should be the attribute of the view
- callable used to retrieve the response (see the ``add_view``
- method's ``attr`` argument for a description).
-
- The ``renderer`` argument should be the name of (or path to) a
- :term:`renderer` used to generate a response for this view
- (see the
- :meth:`pyramid.configuration.Configurator.add_view`
- method's ``renderer`` argument for information about how a
- configurator relates to a renderer).
-
- The ``wrapper`` argument should be the name of another view
- which will wrap this view when rendered (see the ``add_view``
- method's ``wrapper`` argument for a description)."""
- if renderer is not None and not isinstance(renderer, dict):
- renderer = {'name':renderer, 'package':self.package}
- view = self._derive_view(view, attr=attr, renderer=renderer)
- def bwcompat_view(context, request):
- context = getattr(request, 'context', None)
- return view(context, request)
- return self.add_view(bwcompat_view, context=Forbidden, wrapper=wrapper)
-
- def set_notfound_view(self, view=None, attr=None, renderer=None,
- wrapper=None):
- """ Add a default not found view to the current configuration
- state.
-
- .. warning:: This method has been deprecated in
- :app:`Pyramid` 1.0. *Do not use it for new development;
- it should only be used to support older code bases which
- depend upon it.* See :ref:`changing_the_notfound_view` to
- see how a not found view should be registered in new
- projects.
-
- The ``view`` argument should be a :term:`view callable` or a
- :term:`dotted Python name` which refers to a view callable.
-
- The ``attr`` argument should be the attribute of the view
- callable used to retrieve the response (see the ``add_view``
- method's ``attr`` argument for a description).
-
- The ``renderer`` argument should be the name of (or path to) a
- :term:`renderer` used to generate a response for this view
- (see the
- :meth:`pyramid.configuration.Configurator.add_view`
- method's ``renderer`` argument for information about how a
- configurator relates to a renderer).
-
- The ``wrapper`` argument should be the name of another view
- which will wrap this view when rendered (see the ``add_view``
- method's ``wrapper`` argument for a description).
- """
- if renderer is not None and not isinstance(renderer, dict):
- renderer = {'name':renderer, 'package':self.package}
- view = self._derive_view(view, attr=attr, renderer=renderer)
- def bwcompat_view(context, request):
- context = getattr(request, 'context', None)
- return view(context, request)
- return self.add_view(bwcompat_view, context=NotFound, wrapper=wrapper)
-
- @config_method
- def set_request_factory(self, factory):
- """ The object passed as ``factory`` should be an object (or a
- :term:`dotted Python name` which refers to an object) which
- will be used by the :app:`Pyramid` router to create all
- request objects. This factory object must have the same
- methods and attributes as the
- :class:`pyramid.request.Request` class (particularly
- ``__call__``, and ``blank``).
-
- .. note:: Using the :meth:``request_factory`` argument to the
- :class:`pyramid.configuration.Configurator` constructor
- can be used to achieve the same purpose.
- """
- factory = self.maybe_dotted(factory)
- def register():
- self.registry.registerUtility(factory, IRequestFactory)
- self._action(IRequestFactory, register)
-
- @config_method
- def set_renderer_globals_factory(self, factory):
- """ The object passed as ``factory`` should be an callable (or
- a :term:`dotted Python name` which refers to an callable) that
- will be used by the :app:`Pyramid` rendering machinery as a
- renderers global factory (see :ref:`adding_renderer_globals`).
-
- The ``factory`` callable must accept a single argument named
- ``system`` (which will be a dictionary) and it must return a
- dictionary. When an application uses a renderer, the
- factory's return dictionary will be merged into the ``system``
- dictionary, and therefore will be made available to the code
- which uses the renderer.
-
- .. note:: Using the :meth:`renderer_globals_factory`
- argument to the
- :class:`pyramid.configuration.Configurator` constructor
- can be used to achieve the same purpose.
- """
- factory = self.maybe_dotted(factory)
- def register():
- self.registry.registerUtility(factory, IRendererGlobalsFactory)
- self._action(IRendererGlobalsFactory, register)
-
- @config_method
- def set_locale_negotiator(self, negotiator):
- """
- Set the :term:`locale negotiator` for this application. The
- :term:`locale negotiator` is a callable which accepts a
- :term:`request` object and which returns a :term:`locale
- name`. The ``negotiator`` argument should be the locale
- negotiator implementation or a :term:`dotted Python name`
- which refers to such an implementation.
-
- Later calls to this method override earlier calls; there can
- be only one locale negotiator active at a time within an
- application. See :ref:`activating_translation` for more
- information.
-
- .. note:: Using the ``locale_negotiator`` argument to the
- :class:`pyramid.configuration.Configurator` constructor
- can be used to achieve the same purpose.
- """
- negotiator = self.maybe_dotted(negotiator)
- def register():
- self.registry.registerUtility(negotiator, ILocaleNegotiator)
- self._action(ILocaleNegotiator, register)
-
- @config_method
- def set_default_permission(self, permission):
- """
- Set the default permission to be used by all subsequent
- :term:`view configuration` registrations. ``permission``
- should be a :term:`permission` string to be used as the
- default permission. An example of a permission
- string:``'view'``. Adding a default permission makes it
- unnecessary to protect each view configuration with an
- explicit permission, unless your application policy requires
- some exception for a particular view.
-
- If a default permission is *not* set, views represented by
- view configuration registrations which do not explicitly
- declare a permission will be executable by entirely anonymous
- users (any authorization policy is ignored).
-
- Later calls to this method override earlier calls; there can
- be only one default permission active at a time within an
- application.
-
- See also :ref:`setting_a_default_permission`.
-
- .. note:: Using the ``default_permission`` argument to the
- :class:`pyramid.configuration.Configurator` constructor
- can be used to achieve the same purpose.
- """
- # default permission used during view registration
- self.registry.registerUtility(permission, IDefaultPermission)
- self._action(IDefaultPermission, None)
-
- @config_method
- def set_session_factory(self, session_factory):
- """
- Configure the application with a :term:`session factory`. If
- this method is called, the ``session_factory`` argument must
- be a session factory callable.
- """
- def register():
- self.registry.registerUtility(session_factory, ISessionFactory)
- self._action(ISessionFactory, register)
-
- @config_method
- def add_translation_dirs(self, *specs):
- """ Add one or more :term:`translation directory` paths to the
- current configuration state. The ``specs`` argument is a
- sequence that may contain absolute directory paths
- (e.g. ``/usr/share/locale``) or :term:`resource specification`
- names naming a directory path (e.g. ``some.package:locale``)
- or a combination of the two.
-
- Example:
-
- .. code-block:: python
-
- add_translations_dirs('/usr/share/locale', 'some.package:locale')
-
- """
- for spec in specs:
-
- package_name, filename = self._split_spec(spec)
- if package_name is None: # absolute filename
- directory = filename
- else:
- __import__(package_name)
- package = sys.modules[package_name]
- directory = os.path.join(package_path(package), filename)
-
- if not os.path.isdir(os.path.realpath(directory)):
- raise ConfigurationError('"%s" is not a directory' % directory)
-
- tdirs = self.registry.queryUtility(ITranslationDirectories)
- if tdirs is None:
- tdirs = []
- self.registry.registerUtility(tdirs, ITranslationDirectories)
-
- tdirs.insert(0, directory)
- # XXX no action?
-
- if specs:
-
- # We actually only need an IChameleonTranslate function
- # utility to be registered zero or one times. We register the
- # same function once for each added translation directory,
- # which does too much work, but has the same effect.
-
- def translator(msg):
- request = get_current_request()
- localizer = get_localizer(request)
- return localizer.translate(msg)
-
- ctranslate = ChameleonTranslate(translator)
- self.registry.registerUtility(ctranslate, IChameleonTranslate)
-
- def add_static_view(self, name, path, **kw):
- """ Add a view used to render static resources such as images
- and CSS files.
-
- The ``name`` argument is a string representing :term:`view
- name` of the view which is registered. It may alternately be
- a *url prefix*.
-
- 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:`resource specification`.
-
- The ``cache_max_age`` keyword argument is input to set the
- ``Expires`` and ``Cache-Control`` headers for static resources
- 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
- ``__no_permission_required__``. The
- ``__no_permission_required__`` string is 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 resources
- seldom need protection from viewing.
-
- *Usage*
-
- The ``add_static_view`` function is typically used in
- conjunction with the :func:`pyramid.url.static_url`
- function. ``add_static_view`` adds a view which renders a
- static resource when some URL is visited;
- :func:`pyramid.url.static_url` generates a URL to that
- resource.
-
- The ``name`` argument to ``add_static_view`` is usually a
- :term:`view name`. When this is the case, the
- :func:`pyramid.url.static_url` API will generate a URL
- which points to a Pyramid view, which will serve up a set of
- resources 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 :func:`pyramid.url.static_url`:
-
- .. code-block:: python
-
- static_url('mypackage:images/logo.png', request)
-
- When ``add_static_view`` is called with a ``name`` argument
- that represents a simple view name, as it is above, subsequent
- calls to :func:`pyramid.url.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 resources to be
- served from an external webserver. This happens when the
- ``name`` argument is a URL (detected as any string with a
- slash in it). In this mode, the ``name`` is used as the URL
- prefix when generating a URL using
- :func:`pyramid.url.static_url`. 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
- :func:`pyramid.url.static_url` for that static view will be
- prefixed with ``http://example.com/images``:
-
- .. code-block:: python
-
- static_url('mypackage:images/logo.png', request)
-
- When ``add_static_view`` is called with a ``name`` argument
- that is the URL prefix ``http://example.com/images``,
- subsequent calls to :func:`pyramid.url.static_url` with
- paths that start with the ``path`` argument passed to
- ``add_static_view`` will generate a URL something like
- ``http://example.com/logo.png``. The external webserver
- listening on ``example.com`` must be itself configured to
- respond properly to such a request.
-
- See :ref:`static_resources_section` for more information.
- """
- spec = self._make_spec(path)
- info = self.registry.queryUtility(IStaticURLInfo)
- if info is None:
- info = StaticURLInfo(self)
- self.registry.registerUtility(info, IStaticURLInfo)
-
- info.add(name, spec, **kw)
-
- # testing API
- def testing_securitypolicy(self, userid=None, groupids=(),
- permissive=True):
- """Unit/integration testing helper: Registers a pair of faux
- :app:`Pyramid` security policies: a :term:`authentication
- policy` and a :term:`authorization policy`.
-
- The behavior of the registered :term:`authorization policy`
- depends on the ``permissive`` argument. If ``permissive`` is
- true, a permissive :term:`authorization policy` is registered;
- this policy allows all access. If ``permissive`` is false, a
- nonpermissive :term:`authorization policy` is registered; this
- policy denies all access.
-
- The behavior of the registered :term:`authentication policy`
- depends on the values provided for the ``userid`` and
- ``groupids`` argument. The authentication policy will return
- the userid identifier implied by the ``userid`` argument and
- the group ids implied by the ``groupids`` argument when the
- :func:`pyramid.security.authenticated_userid` or
- :func:`pyramid.security.effective_principals` APIs are
- used.
-
- This function is most useful when testing code that uses
- the APIs named :func:`pyramid.security.has_permission`,
- :func:`pyramid.security.authenticated_userid`,
- :func:`pyramid.security.effective_principals`, and
- :func:`pyramid.security.principals_allowed_by_permission`.
- """
- from pyramid.testing import DummySecurityPolicy
- policy = DummySecurityPolicy(userid, groupids, permissive)
- self.registry.registerUtility(policy, IAuthorizationPolicy)
- self.registry.registerUtility(policy, IAuthenticationPolicy)
-
- def testing_models(self, models):
- """Unit/integration testing helper: registers a dictionary of
- :term:`model` objects that can be resolved via the
- :func:`pyramid.traversal.find_model` API.
-
- The :func:`pyramid.traversal.find_model` API is called with
- a path as one of its arguments. If the dictionary you
- register when calling this method contains that path as a
- string key (e.g. ``/foo/bar`` or ``foo/bar``), the
- corresponding value will be returned to ``find_model`` (and
- thus to your code) when
- :func:`pyramid.traversal.find_model` is called with an
- equivalent path string or tuple.
- """
- class DummyTraverserFactory:
- def __init__(self, context):
- self.context = context
-
- def __call__(self, request):
- path = request['PATH_INFO']
- ob = models[path]
- traversed = traversal_path(path)
- return {'context':ob, 'view_name':'','subpath':(),
- 'traversed':traversed, 'virtual_root':ob,
- 'virtual_root_path':(), 'root':ob}
- self.registry.registerAdapter(DummyTraverserFactory, (Interface,),
- ITraverser)
- return models
-
- def testing_add_subscriber(self, event_iface=None):
- """Unit/integration testing helper: Registers a
- :term:`subscriber` which listens for events of the type
- ``event_iface``. This method returns a list object which is
- appended to by the subscriber whenever an event is captured.
-
- When an event is dispatched that matches the value implied by
- the ``event_iface`` argument, that event will be appended to
- the list. You can then compare the values in the list to
- expected event notifications. This method is useful when
- testing code that wants to call
- :meth:`pyramid.registry.Registry.notify`,
- :func:`zope.component.event.dispatch` or
- :func:`zope.component.event.objectEventNotify`.
-
- The default value of ``event_iface`` (``None``) implies a
- subscriber registered for *any* kind of event.
- """
- event_iface = self.maybe_dotted(event_iface)
- L = []
- def subscriber(*event):
- L.extend(event)
- self.add_subscriber(subscriber, event_iface)
- return L
-
- def testing_add_renderer(self, path, renderer=None):
- """Unit/integration testing helper: register a renderer at
- ``path`` (usually a relative filename ala ``templates/foo.pt``
- or a resource specification) and return the renderer object.
- If the ``renderer`` argument is None, a 'dummy' renderer will
- be used. This function is useful when testing code that calls
- the :func:`pyramid.renderers.render` function or
- :func:`pyramid.renderers.render_to_response` function or
- any other ``render_*`` or ``get_*`` API of the
- :mod:`pyramid.renderers` module.
-
- Note that calling this method for with a ``path`` argument
- representing a renderer factory type (e.g. for ``foo.pt``
- usually implies the ``chameleon_zpt`` renderer factory)
- clobbers any existing renderer factory registered for that
- type.
-
- .. note:: This method is also available under the alias
- ``testing_add_template`` (an older name for it).
-
- """
- from pyramid.testing import DummyRendererFactory
- helper = RendererHelper(name=path, registry=self.registry)
- factory = self.registry.queryUtility(IRendererFactory, name=helper.type)
- if not isinstance(factory, DummyRendererFactory):
- factory = DummyRendererFactory(helper.type, factory)
- self.registry.registerUtility(factory, IRendererFactory,
- name=helper.type)
-
- from pyramid.testing import DummyTemplateRenderer
- if renderer is None:
- renderer = DummyTemplateRenderer()
- factory.add(path, renderer)
- return renderer
+from zope.deprecation import deprecated
- testing_add_template = testing_add_renderer
+deprecated(
+ 'ConfigurationError',
+ 'pyramid.configuration.ConfigurationError is deprecated as of '
+ 'Pyramid 1.0. Use ``pyramid.config.ConfigurationError`` instead.')
-class Configurator(Config):
+class Configurator(BaseConfigurator):
def __init__(self,
registry=None,
package=None,
@@ -2295,11 +26,10 @@ class Configurator(Config):
default_permission=None,
session_factory=None,
autocommit=True,
- context=None,
):
if package is None:
package = caller_package()
- Config.__init__(
+ BaseConfigurator.__init__(
self,
registry=registry,
package=package,
@@ -2315,665 +45,10 @@ class Configurator(Config):
default_permission=default_permission,
session_factory=session_factory,
autocommit=autocommit,
- context=context,
)
deprecated(
'Configurator',
- '(pyramid.configuration.Configurator is deprecated as of Pyramid 1.0. Use'
- '``pyramid.configuration.Config`` with ``autocommit=True`` instead.) ')
-
-def _make_predicates(xhr=None, request_method=None, path_info=None,
- request_param=None, header=None, accept=None,
- containment=None, request_type=None,
- traverse=None, custom=()):
-
- # PREDICATES
- # ----------
- #
- # Given an argument list, a predicate list is computed.
- # Predicates are added to a predicate list in (presumed)
- # computation expense order. All predicates associated with a
- # view or route must evaluate true for the view or route to
- # "match" during a request. Elsewhere in the code, we evaluate
- # predicates using a generator expression. The fastest predicate
- # should be evaluated first, then the next fastest, and so on, as
- # if one returns false, the remainder of the predicates won't need
- # to be evaluated.
- #
- # While we compute predicates, we also compute a predicate hash
- # (aka phash) that can be used by a caller to identify identical
- # predicate lists.
- #
- # ORDERING
- # --------
- #
- # A "order" is computed for the predicate list. An order is
- # a scoring.
- #
- # Each predicate is associated with a weight value, which is a
- # multiple of 2. The weight of a predicate symbolizes the
- # relative potential "importance" of the predicate to all other
- # predicates. A larger weight indicates greater importance.
- #
- # All weights for a given predicate list are bitwise ORed together
- # to create a "score"; this score is then subtracted from
- # MAX_ORDER and divided by an integer representing the number of
- # predicates+1 to determine the order.
- #
- # The order represents the ordering in which a "multiview" ( a
- # collection of views that share the same context/request/name
- # triad but differ in other ways via predicates) will attempt to
- # call its set of views. Views with lower orders will be tried
- # first. The intent is to a) ensure that views with more
- # predicates are always evaluated before views with fewer
- # predicates and b) to ensure a stable call ordering of views that
- # share the same number of predicates. Views which do not have
- # any predicates get an order of MAX_ORDER, meaning that they will
- # be tried very last.
-
- predicates = []
- weights = []
- h = md5()
-
- if xhr:
- def xhr_predicate(context, request):
- return request.is_xhr
- weights.append(1 << 1)
- predicates.append(xhr_predicate)
- h.update('xhr:%r' % bool(xhr))
-
- if request_method is not None:
- def request_method_predicate(context, request):
- return request.method == request_method
- weights.append(1 << 2)
- predicates.append(request_method_predicate)
- h.update('request_method:%r' % request_method)
-
- if path_info is not None:
- try:
- path_info_val = re.compile(path_info)
- except re.error, why:
- raise ConfigurationError(why[0])
- def path_info_predicate(context, request):
- return path_info_val.match(request.path_info) is not None
- weights.append(1 << 3)
- predicates.append(path_info_predicate)
- h.update('path_info:%r' % path_info)
-
- if request_param is not None:
- request_param_val = None
- if '=' in request_param:
- request_param, request_param_val = request_param.split('=', 1)
- def request_param_predicate(context, request):
- if request_param_val is None:
- return request_param in request.params
- return request.params.get(request_param) == request_param_val
- weights.append(1 << 4)
- predicates.append(request_param_predicate)
- h.update('request_param:%r=%r' % (request_param, request_param_val))
-
- if header is not None:
- header_name = header
- header_val = None
- if ':' in header:
- header_name, header_val = header.split(':', 1)
- try:
- header_val = re.compile(header_val)
- except re.error, why:
- raise ConfigurationError(why[0])
- def header_predicate(context, request):
- if header_val is None:
- return header_name in request.headers
- val = request.headers.get(header_name)
- if val is None:
- return False
- return header_val.match(val) is not None
- weights.append(1 << 5)
- predicates.append(header_predicate)
- h.update('header:%r=%r' % (header_name, header_val))
-
- if accept is not None:
- def accept_predicate(context, request):
- return accept in request.accept
- weights.append(1 << 6)
- predicates.append(accept_predicate)
- h.update('accept:%r' % accept)
-
- if containment is not None:
- def containment_predicate(context, request):
- return find_interface(context, containment) is not None
- weights.append(1 << 7)
- predicates.append(containment_predicate)
- h.update('containment:%r' % hash(containment))
-
- if request_type is not None:
- def request_type_predicate(context, request):
- return request_type.providedBy(request)
- weights.append(1 << 8)
- predicates.append(request_type_predicate)
- h.update('request_type:%r' % hash(request_type))
-
- if traverse is not None:
- # ``traverse`` can only be used as a *route* "predicate"; it
- # adds 'traverse' to the matchdict if it's specified in the
- # routing args. This causes the ModelGraphTraverser to use
- # the resolved traverse pattern as the traversal path.
- from pyramid.urldispatch import _compile_route
- _, tgenerate = _compile_route(traverse)
- def traverse_predicate(context, request):
- if 'traverse' in context:
- return True
- m = context['match']
- tvalue = tgenerate(m)
- m['traverse'] = traversal_path(tvalue)
- return True
- # This isn't actually a predicate, it's just a infodict
- # modifier that injects ``traverse`` into the matchdict. As a
- # result, the ``traverse_predicate`` function above always
- # returns True, and we don't need to update the hash or attach
- # a weight to it
- predicates.append(traverse_predicate)
-
- if custom:
- for num, predicate in enumerate(custom):
- predicates.append(predicate)
- # using hash() here rather than id() is intentional: we
- # want to allow custom predicates that are part of
- # frameworks to be able to define custom __hash__
- # functions for custom predicates, so that the hash output
- # of predicate instances which are "logically the same"
- # may compare equal.
- h.update('custom%s:%r' % (num, hash(predicate)))
- weights.append(1 << 10)
-
- score = 0
- for bit in weights:
- score = score | bit
- order = (MAX_ORDER - score) / (len(predicates) + 1)
- phash = h.hexdigest()
- return order, predicates, phash
-
-class MultiView(object):
- implements(IMultiView)
-
- def __init__(self, name):
- self.name = name
- self.media_views = {}
- self.views = []
- self.accepts = []
-
- 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()
- else:
- subset = self.media_views.setdefault(accept, [])
- subset.append((order, view, phash))
- subset.sort()
- 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)
-
-def decorate_view(wrapped_view, original_view):
- if wrapped_view is original_view:
- return False
- wrapped_view.__module__ = original_view.__module__
- wrapped_view.__doc__ = original_view.__doc__
- try:
- wrapped_view.__name__ = original_view.__name__
- except AttributeError:
- wrapped_view.__name__ = repr(original_view)
- try:
- wrapped_view.__permitted__ = original_view.__permitted__
- except AttributeError:
- pass
- try:
- wrapped_view.__call_permissive__ = original_view.__call_permissive__
- except AttributeError:
- pass
- try:
- wrapped_view.__predicated__ = original_view.__predicated__
- except AttributeError:
- pass
- try:
- wrapped_view.__accept__ = original_view.__accept__
- except AttributeError:
- pass
- try:
- wrapped_view.__order__ = original_view.__order__
- except AttributeError:
- pass
- return True
-
-def requestonly(class_or_callable, attr=None):
- """ Return true of the class or callable accepts only a request argument,
- as opposed to something that accepts context, request """
- if attr is None:
- attr = '__call__'
- if inspect.isfunction(class_or_callable):
- fn = class_or_callable
- elif inspect.isclass(class_or_callable):
- try:
- fn = class_or_callable.__init__
- except AttributeError:
- return False
- else:
- try:
- fn = getattr(class_or_callable, attr)
- except AttributeError:
- return False
-
- try:
- argspec = inspect.getargspec(fn)
- except TypeError:
- return False
-
- args = argspec[0]
- defaults = argspec[3]
-
- if hasattr(fn, 'im_func'):
- # it's an instance method
- if not args:
- return False
- args = args[1:]
- if not args:
- return False
-
- if len(args) == 1:
- return True
-
- elif args[0] == 'request':
- if len(args) - len(defaults) == 1:
- return True
-
- return False
-
-def is_response(ob):
- if ( hasattr(ob, 'app_iter') and hasattr(ob, 'headerlist') and
- hasattr(ob, 'status') ):
- return True
- return False
-
-def _map_view(view, registry, attr=None, renderer=None):
- wrapped_view = view
-
- helper = None
-
- if renderer is not None:
- helper = RendererHelper(renderer['name'],
- package=renderer['package'],
- registry=registry)
-
- if inspect.isclass(view):
- # If the object we've located is a class, turn it into a
- # function that operates like a Zope view (when it's invoked,
- # construct an instance using 'context' and 'request' as
- # position arguments, then immediately invoke the __call__
- # method of the instance with no arguments; __call__ should
- # return an IResponse).
- if requestonly(view, attr):
- # its __init__ accepts only a single request argument,
- # instead of both context and request
- def _class_requestonly_view(context, request):
- inst = view(request)
- if attr is None:
- response = inst()
- else:
- response = getattr(inst, attr)()
- if helper is not None:
- if not is_response(response):
- system = {
- 'view':inst,
- 'renderer_name':renderer['name'], # b/c
- 'renderer_info':renderer,
- 'context':context,
- 'request':request
- }
- response = helper.render_to_response(response, system,
- request=request)
- return response
- wrapped_view = _class_requestonly_view
- else:
- # its __init__ accepts both context and request
- def _class_view(context, request):
- inst = view(context, request)
- if attr is None:
- response = inst()
- else:
- response = getattr(inst, attr)()
- if helper is not None:
- if not is_response(response):
- system = {'view':inst,
- 'renderer_name':renderer['name'], # b/c
- 'renderer_info':renderer,
- 'context':context,
- 'request':request
- }
- response = helper.render_to_response(response, system,
- request=request)
- return response
- wrapped_view = _class_view
-
- elif requestonly(view, attr):
- # its __call__ accepts only a single request argument,
- # instead of both context and request
- def _requestonly_view(context, request):
- if attr is None:
- response = view(request)
- else:
- response = getattr(view, attr)(request)
-
- if helper is not None:
- if not is_response(response):
- system = {
- 'view':view,
- 'renderer_name':renderer['name'],
- 'renderer_info':renderer,
- 'context':context,
- 'request':request
- }
- response = helper.render_to_response(response, system,
- request=request)
- return response
- wrapped_view = _requestonly_view
-
- elif attr:
- def _attr_view(context, request):
- response = getattr(view, attr)(context, request)
- if helper is not None:
- if not is_response(response):
- system = {
- 'view':view,
- 'renderer_name':renderer['name'],
- 'renderer_info':renderer,
- 'context':context,
- 'request':request
- }
- response = helper.render_to_response(response, system,
- request=request)
- return response
- wrapped_view = _attr_view
-
- elif helper is not None:
- def _rendered_view(context, request):
- response = view(context, request)
- if not is_response(response):
- system = {
- 'view':view,
- 'renderer_name':renderer['name'], # b/c
- 'renderer_info':renderer,
- 'context':context,
- 'request':request
- }
- response = helper.render_to_response(response, system,
- request=request)
- return response
- wrapped_view = _rendered_view
-
- decorate_view(wrapped_view, view)
- return wrapped_view
-
-def _owrap_view(view, viewname, wrapper_viewname):
- if not wrapper_viewname:
- return view
- def _owrapped_view(context, request):
- response = view(context, request)
- request.wrapped_response = response
- request.wrapped_body = response.body
- request.wrapped_view = view
- wrapped_response = render_view_to_response(context, request,
- wrapper_viewname)
- if wrapped_response is None:
- raise ValueError(
- 'No wrapper view named %r found when executing view '
- 'named %r' % (wrapper_viewname, viewname))
- return wrapped_response
- decorate_view(_owrapped_view, view)
- return _owrapped_view
-
-def _predicate_wrap(view, predicates):
- if not predicates:
- return view
- def predicate_wrapper(context, request):
- if all((predicate(context, request) for predicate in predicates)):
- return view(context, request)
- raise PredicateMismatch('predicate mismatch for view %s' % view)
- def checker(context, request):
- return all((predicate(context, request) for predicate in
- predicates))
- predicate_wrapper.__predicated__ = checker
- decorate_view(predicate_wrapper, view)
- return predicate_wrapper
-
-def _secure_view(view, permission, authn_policy, authz_policy):
- if permission == '__no_permission_required__':
- # allow views registered within configurations that have a
- # default permission to explicitly override the default
- # permission, replacing it with no permission at all
- permission = None
-
- wrapped_view = view
- if authn_policy and authz_policy and (permission is not None):
- def _secured_view(context, request):
- principals = authn_policy.effective_principals(request)
- if authz_policy.permits(context, principals, permission):
- return view(context, request)
- msg = getattr(request, 'authdebug_message',
- 'Unauthorized: %s failed permission check' % view)
- raise Forbidden(msg)
- _secured_view.__call_permissive__ = view
- def _permitted(context, request):
- principals = authn_policy.effective_principals(request)
- return authz_policy.permits(context, principals, permission)
- _secured_view.__permitted__ = _permitted
- wrapped_view = _secured_view
- decorate_view(wrapped_view, view)
-
- return wrapped_view
-
-def _authdebug_view(view, permission, authn_policy, authz_policy, settings,
- logger):
- wrapped_view = view
- if settings and settings.get('debug_authorization', False):
- def _authdebug_view(context, request):
- view_name = getattr(request, 'view_name', None)
-
- if authn_policy and authz_policy:
- if permission is None:
- msg = 'Allowed (no permission registered)'
- else:
- principals = authn_policy.effective_principals(request)
- msg = str(authz_policy.permits(context, principals,
- permission))
- else:
- msg = 'Allowed (no authorization policy in use)'
-
- view_name = getattr(request, 'view_name', None)
- url = getattr(request, 'url', None)
- msg = ('debug_authorization of url %s (view name %r against '
- 'context %r): %s' % (url, view_name, context, msg))
- logger and logger.debug(msg)
- if request is not None:
- request.authdebug_message = msg
- return view(context, request)
-
- wrapped_view = _authdebug_view
- decorate_view(wrapped_view, view)
-
- return wrapped_view
-
-def _attr_wrap(view, accept, order, phash):
- # this is a little silly but we don't want to decorate the original
- # function with attributes that indicate accept, order, and phash,
- # so we use a wrapper
- if (accept is None) and (order == MAX_ORDER) and (phash == DEFAULT_PHASH):
- return view # defaults
- def attr_view(context, request):
- return view(context, request)
- attr_view.__accept__ = accept
- attr_view.__order__ = order
- attr_view.__phash__ = phash
- decorate_view(attr_view, view)
- return attr_view
-
-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)))
- )
-
-# note that ``options`` is a b/w compat alias for ``settings`` and
-# ``Configurator`` is a testing dep inj
-def make_app(root_factory, package=None, filename='configure.zcml',
- settings=None, options=None, Configurator=Config):
- """ Return a Router object, representing a fully configured
- :app:`Pyramid` WSGI application.
-
- .. warning:: Use of this function is deprecated as of
- :app:`Pyramid` 1.0. You should instead use a
- :class:`pyramid.configuration.Configurator` instance to
- perform startup configuration as shown in
- :ref:`configuration_narr`.
-
- ``root_factory`` must be a callable that accepts a :term:`request`
- object and which returns a traversal root object. The traversal
- root returned by the root factory is the *default* traversal root;
- it can be overridden on a per-view basis. ``root_factory`` may be
- ``None``, in which case a 'default default' traversal root is
- used.
-
- ``package`` is a Python :term:`package` or module representing the
- application's package. It is optional, defaulting to ``None``.
- ``package`` may be ``None``. If ``package`` is ``None``, the
- ``filename`` passed or the value in the ``options`` dictionary
- named ``configure_zcml`` must be a) absolute pathname to a
- :term:`ZCML` file that represents the application's configuration
- *or* b) a :term:`resource specification` to a :term:`ZCML` file in
- the form ``dotted.package.name:relative/file/path.zcml``.
-
- ``filename`` is the filesystem path to a ZCML file (optionally
- relative to the package path) that should be parsed to create the
- application registry. It defaults to ``configure.zcml``. It can
- also be a ;term:`resource specification` in the form
- ``dotted_package_name:relative/file/path.zcml``. Note that if any
- value for ``configure_zcml`` is passed within the ``settings``
- dictionary, the value passed as ``filename`` will be ignored,
- replaced with the ``configure_zcml`` value.
-
- ``settings``, if used, should be a dictionary containing runtime
- settings (e.g. the key/value pairs in an app section of a
- PasteDeploy file), with each key representing the option and the
- key's value representing the specific option value,
- e.g. ``{'reload_templates':True}``. Note that the keyword
- parameter ``options`` is a backwards compatibility alias for the
- ``settings`` keyword parameter.
- """
- settings = settings or options or {}
- zcml_file = settings.get('configure_zcml', filename)
- config = Configurator(package=package, settings=settings,
- root_factory=root_factory)
- config.hook_zca()
- config.begin()
- config.load_zcml(zcml_file)
- config.end()
- return config.make_wsgi_app()
-
-class ActionPredicate(object):
- action_name = 'action'
- def __init__(self, action):
- self.action = action
- try:
- self.action_re = re.compile(action + '$')
- except (re.error, TypeError), why:
- raise ConfigurationError(why[0])
-
- def __call__(self, context, request):
- matchdict = request.matchdict
- if matchdict is None:
- return False
- action = matchdict.get(self.action_name)
- if action is None:
- return False
- return bool(self.action_re.match(action))
-
- def __hash__(self):
- # allow this predicate's phash to be compared as equal to
- # others that share the same action name
- return hash(self.action)
-
-class PyramidConfigurationMachine(ConfigurationMachine):
- autocommit = False
-
- def processSpec(self, spec):
- """Check whether a callable needs to be processed. The ``spec``
- refers to a unique identifier for the callable.
-
- Return True if processing is needed and False otherwise. If
- the callable needs to be processed, it will be marked as
- processed, assuming that the caller will procces the callable if
- it needs to be processed.
- """
- if spec in self._seen_files:
- return False
- self._seen_files.add(spec)
- return True
+ 'pyramid.configuration.Configurator is deprecated as of Pyramid 1.0. Use'
+ '``pyramid.config.Configurator`` with ``autocommit=True`` instead.')
-def context_base(context):
- while 1:
- newcontext = getattr(context, 'context', None)
- if newcontext is None:
- return context
- context = newcontext
-
diff --git a/pyramid/router.py b/pyramid/router.py
index 972c05b62..ca2f0adc5 100644
--- a/pyramid/router.py
+++ b/pyramid/router.py
@@ -1,6 +1,8 @@
from zope.interface import implements
from zope.interface import providedBy
+from zope.deprecation import deprecated
+
from pyramid.interfaces import IDebugLogger
from pyramid.interfaces import IExceptionViewClassifier
from pyramid.interfaces import IRequest
@@ -22,10 +24,7 @@ from pyramid.threadlocal import manager
from pyramid.traversal import DefaultRootFactory
from pyramid.traversal import ModelGraphTraverser
-from pyramid.configuration import make_app # b/c
-
-make_app # prevent PyFlakes from complaining
-
+from pyramid.config import Configurator # b/c
class Router(object):
implements(IRouter)
@@ -188,3 +187,65 @@ class Router(object):
+# note that ``options`` is a b/w compat alias for ``settings`` and
+# ``Configurator`` is a testing dep inj
+def make_app(root_factory, package=None, filename='configure.zcml',
+ settings=None, options=None, Configurator=Configurator):
+ """ Return a Router object, representing a fully configured
+ :app:`Pyramid` WSGI application.
+
+ .. warning:: Use of this function is deprecated as of
+ :app:`Pyramid` 1.0. You should instead use a
+ :class:`pyramid.config.Configurator` instance to
+ perform startup configuration as shown in
+ :ref:`configuration_narr`.
+
+ ``root_factory`` must be a callable that accepts a :term:`request`
+ object and which returns a traversal root object. The traversal
+ root returned by the root factory is the *default* traversal root;
+ it can be overridden on a per-view basis. ``root_factory`` may be
+ ``None``, in which case a 'default default' traversal root is
+ used.
+
+ ``package`` is a Python :term:`package` or module representing the
+ application's package. It is optional, defaulting to ``None``.
+ ``package`` may be ``None``. If ``package`` is ``None``, the
+ ``filename`` passed or the value in the ``options`` dictionary
+ named ``configure_zcml`` must be a) absolute pathname to a
+ :term:`ZCML` file that represents the application's configuration
+ *or* b) a :term:`resource specification` to a :term:`ZCML` file in
+ the form ``dotted.package.name:relative/file/path.zcml``.
+
+ ``filename`` is the filesystem path to a ZCML file (optionally
+ relative to the package path) that should be parsed to create the
+ application registry. It defaults to ``configure.zcml``. It can
+ also be a ;term:`resource specification` in the form
+ ``dotted_package_name:relative/file/path.zcml``. Note that if any
+ value for ``configure_zcml`` is passed within the ``settings``
+ dictionary, the value passed as ``filename`` will be ignored,
+ replaced with the ``configure_zcml`` value.
+
+ ``settings``, if used, should be a dictionary containing runtime
+ settings (e.g. the key/value pairs in an app section of a
+ PasteDeploy file), with each key representing the option and the
+ key's value representing the specific option value,
+ e.g. ``{'reload_templates':True}``. Note that the keyword
+ parameter ``options`` is a backwards compatibility alias for the
+ ``settings`` keyword parameter.
+ """
+ settings = settings or options or {}
+ zcml_file = settings.get('configure_zcml', filename)
+ config = Configurator(package=package, settings=settings,
+ root_factory=root_factory, autocommit=True)
+ config.hook_zca()
+ config.begin()
+ config.load_zcml(zcml_file)
+ config.end()
+ return config.make_wsgi_app()
+
+
+deprecated(
+ 'make_app',
+ 'pyramid.router.make_app is deprecated as of Pyramid 1.0. Use '
+ 'an instance of ``pyramid.config.Configurator`` to configure your '
+ 'application instead.')
diff --git a/pyramid/testing.py b/pyramid/testing.py
index e6f6c5cab..b584c3b73 100644
--- a/pyramid/testing.py
+++ b/pyramid/testing.py
@@ -12,7 +12,7 @@ from pyramid.interfaces import ISecuredView
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
-from pyramid.configuration import Config
+from pyramid.config import Configurator
from pyramid.exceptions import Forbidden
from pyramid.response import Response
from pyramid.registry import Registry
@@ -56,7 +56,7 @@ def registerDummySecurityPolicy(userid=None, groupids=(), permissive=True):
method in your unit and integration tests.
"""
registry = get_current_registry()
- config = Config(registry=registry)
+ config = Configurator(registry=registry)
result = config.testing_securitypolicy(userid=userid, groupids=groupids,
permissive=permissive)
config.commit()
@@ -80,7 +80,7 @@ def registerModels(models):
method in your unit and integration tests.
"""
registry = get_current_registry()
- config = Config(registry=registry)
+ config = Configurator(registry=registry)
result = config.testing_models(models)
config.commit()
return result
@@ -108,7 +108,7 @@ def registerEventListener(event_iface=None):
method in your unit and integration tests.
"""
registry = get_current_registry()
- config = Config(registry=registry)
+ config = Configurator(registry=registry)
result = config.testing_add_subscriber(event_iface)
config.commit()
return result
@@ -130,7 +130,7 @@ def registerTemplateRenderer(path, renderer=None):
"""
registry = get_current_registry()
- config = Config(registry=registry)
+ config = Configurator(registry=registry)
result = config.testing_add_template(path, renderer)
config.commit()
return result
@@ -256,7 +256,7 @@ def registerSubscriber(subscriber, iface=Interface):
method in your unit and integration tests.
"""
registry = get_current_registry()
- config = Config(registry)
+ config = Configurator(registry)
result = config.add_subscriber(subscriber, iface=iface)
config.commit()
return result
@@ -279,7 +279,7 @@ def registerRoute(pattern, name, factory=None):
method in your unit and integration tests.
"""
reg = get_current_registry()
- config = Config(registry=reg)
+ config = Configurator(registry=reg)
result = config.add_route(name, pattern, factory=factory)
config.commit()
return result
@@ -307,7 +307,7 @@ def registerSettings(dictarg=None, **kw):
method in your unit and integration tests.
"""
registry = get_current_registry()
- config = Config(registry=registry)
+ config = Configurator(registry=registry)
config.add_settings(dictarg, **kw)
class DummyRootFactory(object):
@@ -630,14 +630,14 @@ def setUp(registry=None, request=None, hook_zca=True, autocommit=True):
manager.clear()
if registry is None:
registry = Registry('testing')
- config = Config(registry=registry, autocommit=autocommit)
+ config = Configurator(registry=registry, autocommit=autocommit)
if hasattr(registry, 'registerUtility'):
# Sometimes nose calls us with a non-registry object because
# it thinks this function is module test setup. Likewise,
# someone may be passing us an esoteric "dummy" registry, and
# the below won't succeed if it doesn't have a registerUtility
# method.
- from pyramid.configuration import DEFAULT_RENDERERS
+ from pyramid.config import DEFAULT_RENDERERS
for name, renderer in DEFAULT_RENDERERS:
# Cause the default renderers to be registered because
# in-the-wild test code relies on being able to call
diff --git a/pyramid/tests/test_config.py b/pyramid/tests/test_config.py
new file mode 100644
index 000000000..2a41f1504
--- /dev/null
+++ b/pyramid/tests/test_config.py
@@ -0,0 +1,4573 @@
+import unittest
+
+from pyramid import testing
+
+try:
+ import __pypy__
+except:
+ __pypy__ = None
+
+class ConfiguratorTests(unittest.TestCase):
+ def _makeOne(self, *arg, **kw):
+ from pyramid.config import Configurator
+ return Configurator(*arg, **kw)
+
+ def _registerRenderer(self, config, name='.txt'):
+ from pyramid.interfaces import IRendererFactory
+ from pyramid.interfaces import ITemplateRenderer
+ from zope.interface import implements
+ class Renderer:
+ implements(ITemplateRenderer)
+ def __init__(self, info):
+ self.__class__.info = info
+ def __call__(self, *arg):
+ return 'Hello!'
+ config.registry.registerUtility(Renderer, IRendererFactory, name=name)
+ return Renderer
+
+ def _getViewCallable(self, config, ctx_iface=None, request_iface=None,
+ name='', exception_view=False):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ if exception_view:
+ classifier = IExceptionViewClassifier
+ else:
+ classifier = IViewClassifier
+ if ctx_iface is None:
+ ctx_iface = Interface
+ if request_iface is None:
+ request_iface = IRequest
+ return config.registry.adapters.lookup(
+ (classifier, request_iface, ctx_iface), IView, name=name,
+ default=None)
+
+ def _getRouteRequestIface(self, config, name):
+ from pyramid.interfaces import IRouteRequest
+ iface = config.registry.getUtility(IRouteRequest, name)
+ return iface
+
+ def _assertNotFound(self, wrapper, *arg):
+ from pyramid.exceptions import NotFound
+ self.assertRaises(NotFound, wrapper, *arg)
+
+ def _registerEventListener(self, config, event_iface=None):
+ if event_iface is None: # pragma: no cover
+ from zope.interface import Interface
+ event_iface = Interface
+ L = []
+ def subscriber(*event):
+ L.extend(event)
+ config.registry.registerHandler(subscriber, (event_iface,))
+ return L
+
+ def _registerLogger(self, config):
+ from pyramid.interfaces import IDebugLogger
+ logger = DummyLogger()
+ config.registry.registerUtility(logger, IDebugLogger)
+ return logger
+
+ def _makeRequest(self, config):
+ request = DummyRequest()
+ request.registry = config.registry
+ return request
+
+ def _registerSecurityPolicy(self, config, permissive):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ policy = DummySecurityPolicy(permissive)
+ config.registry.registerUtility(policy, IAuthenticationPolicy)
+ config.registry.registerUtility(policy, IAuthorizationPolicy)
+
+ def _registerSettings(self, config, **settings):
+ config.registry.settings = settings
+
+ def test_ctor_no_registry(self):
+ import sys
+ from pyramid.interfaces import ISettings
+ from pyramid.config import Configurator
+ from pyramid.interfaces import IRendererFactory
+ config = Configurator()
+ this_pkg = sys.modules['pyramid.tests']
+ self.failUnless(config.registry.getUtility(ISettings))
+ self.assertEqual(config.package, this_pkg)
+ self.failUnless(config.registry.getUtility(IRendererFactory, 'json'))
+ self.failUnless(config.registry.getUtility(IRendererFactory, 'string'))
+ if not __pypy__:
+ self.failUnless(config.registry.getUtility(IRendererFactory, '.pt'))
+ self.failUnless(config.registry.getUtility(IRendererFactory,'.txt'))
+ self.failUnless(config.registry.getUtility(IRendererFactory, '.mak'))
+ self.failUnless(config.registry.getUtility(IRendererFactory, '.mako'))
+
+ def test_begin(self):
+ from pyramid.config import Configurator
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ config.begin()
+ self.assertEqual(manager.pushed,
+ {'registry':config.registry, 'request':None})
+ self.assertEqual(manager.popped, False)
+
+ def test_begin_with_request(self):
+ from pyramid.config import Configurator
+ config = Configurator()
+ request = object()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ config.begin(request=request)
+ self.assertEqual(manager.pushed,
+ {'registry':config.registry, 'request':request})
+ self.assertEqual(manager.popped, False)
+
+ def test_end(self):
+ from pyramid.config import Configurator
+ config = Configurator()
+ manager = DummyThreadLocalManager()
+ config.manager = manager
+ config.end()
+ self.assertEqual(manager.pushed, None)
+ self.assertEqual(manager.popped, True)
+
+ def test_ctor_with_package_registry(self):
+ import sys
+ from pyramid.config import Configurator
+ pkg = sys.modules['pyramid']
+ config = Configurator(package=pkg)
+ self.assertEqual(config.package, pkg)
+
+ def test_ctor_noreg_custom_settings(self):
+ from pyramid.interfaces import ISettings
+ settings = {'reload_templates':True,
+ 'mysetting':True}
+ config = self._makeOne(settings=settings)
+ settings = config.registry.getUtility(ISettings)
+ self.assertEqual(settings['reload_templates'], True)
+ self.assertEqual(settings['debug_authorization'], False)
+ self.assertEqual(settings['mysetting'], True)
+
+ def test_ctor_noreg_debug_logger_None_default(self):
+ from pyramid.interfaces import IDebugLogger
+ config = self._makeOne()
+ logger = config.registry.getUtility(IDebugLogger)
+ self.assertEqual(logger.name, 'pyramid.debug')
+
+ def test_ctor_noreg_debug_logger_non_None(self):
+ from pyramid.interfaces import IDebugLogger
+ logger = object()
+ config = self._makeOne(debug_logger=logger)
+ result = config.registry.getUtility(IDebugLogger)
+ self.assertEqual(logger, result)
+
+ def test_ctor_authentication_policy(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ policy = object()
+ config = self._makeOne(authentication_policy=policy)
+ result = config.registry.getUtility(IAuthenticationPolicy)
+ self.assertEqual(policy, result)
+
+ def test_ctor_authorization_policy_only(self):
+ from pyramid.exceptions import ConfigurationError
+ policy = object()
+ self.assertRaises(ConfigurationError,
+ self._makeOne, authorization_policy=policy)
+
+ def test_ctor_no_root_factory(self):
+ from pyramid.interfaces import IRootFactory
+ config = self._makeOne()
+ self.failUnless(config.registry.getUtility(IRootFactory))
+
+ def test_ctor_alternate_renderers(self):
+ from pyramid.interfaces import IRendererFactory
+ renderer = object()
+ config = self._makeOne(renderers=[('yeah', renderer)])
+ self.assertEqual(config.registry.getUtility(IRendererFactory, 'yeah'),
+ renderer)
+
+ def test_ctor_default_permission(self):
+ from pyramid.interfaces import IDefaultPermission
+ config = self._makeOne(default_permission='view')
+ self.assertEqual(config.registry.getUtility(IDefaultPermission), 'view')
+
+ def test_ctor_session_factory(self):
+ from pyramid.interfaces import ISessionFactory
+ config = self._makeOne(session_factory='factory')
+ self.assertEqual(config.registry.getUtility(ISessionFactory), 'factory')
+
+ def test_with_package_module(self):
+ from pyramid.tests import test_configuration
+ import pyramid.tests
+ config = self._makeOne()
+ newconfig = config.with_package(test_configuration)
+ self.assertEqual(newconfig.package, pyramid.tests)
+
+ def test_with_package_package(self):
+ import pyramid.tests
+ config = self._makeOne()
+ newconfig = config.with_package(pyramid.tests)
+ self.assertEqual(newconfig.package, pyramid.tests)
+
+ def test_maybe_dotted_string_success(self):
+ import pyramid.tests
+ config = self._makeOne()
+ result = config.maybe_dotted('pyramid.tests')
+ self.assertEqual(result, pyramid.tests)
+
+ def test_maybe_dotted_string_fail(self):
+ config = self._makeOne()
+ self.assertRaises(ImportError,
+ config.maybe_dotted, 'cant.be.found')
+
+ def test_maybe_dotted_notstring_success(self):
+ import pyramid.tests
+ config = self._makeOne()
+ result = config.maybe_dotted(pyramid.tests)
+ self.assertEqual(result, pyramid.tests)
+
+ def test_absolute_resource_spec_already_absolute(self):
+ import pyramid.tests
+ config = self._makeOne(package=pyramid.tests)
+ result = config.absolute_resource_spec('already:absolute')
+ self.assertEqual(result, 'already:absolute')
+
+ def test_absolute_resource_spec_notastring(self):
+ import pyramid.tests
+ config = self._makeOne(package=pyramid.tests)
+ result = config.absolute_resource_spec(None)
+ self.assertEqual(result, None)
+
+ def test_absolute_resource_spec_relative(self):
+ import pyramid.tests
+ config = self._makeOne(package=pyramid.tests)
+ result = config.absolute_resource_spec('templates')
+ self.assertEqual(result, 'pyramid.tests:templates')
+
+ def test_setup_registry_fixed(self):
+ class DummyRegistry(object):
+ def subscribers(self, events, name):
+ self.events = events
+ return events
+ def registerUtility(self, *arg, **kw):
+ pass
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ config.add_view = lambda *arg, **kw: False
+ config.setup_registry()
+ self.assertEqual(reg.has_listeners, True)
+ self.assertEqual(reg.notify(1), None)
+ self.assertEqual(reg.events, (1,))
+
+ def test_setup_registry_registers_default_exceptionresponse_view(self):
+ from pyramid.interfaces import IExceptionResponse
+ from pyramid.view import default_exceptionresponse_view
+ class DummyRegistry(object):
+ def registerUtility(self, *arg, **kw):
+ pass
+ reg = DummyRegistry()
+ config = self._makeOne(reg)
+ views = []
+ config.add_view = lambda *arg, **kw: views.append((arg, kw))
+ config.setup_registry()
+ self.assertEqual(views[0], ((default_exceptionresponse_view,),
+ {'context':IExceptionResponse}))
+
+ def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.exceptions import NotFound
+ from pyramid.registry import Registry
+ reg = Registry()
+ config = self._makeOne(reg, autocommit=True)
+ config.setup_registry() # registers IExceptionResponse default view
+ def myview(context, request):
+ return 'OK'
+ config.add_view(myview, context=NotFound)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
+ request_iface=IRequest)
+ result = view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_setup_registry_custom_settings(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ISettings
+ settings = {'reload_templates':True,
+ 'mysetting':True}
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(settings=settings)
+ settings = reg.getUtility(ISettings)
+ self.assertEqual(settings['reload_templates'], True)
+ self.assertEqual(settings['debug_authorization'], False)
+ self.assertEqual(settings['mysetting'], True)
+
+ def test_setup_registry_debug_logger_None_default(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry()
+ logger = reg.getUtility(IDebugLogger)
+ self.assertEqual(logger.name, 'pyramid.debug')
+
+ def test_setup_registry_debug_logger_non_None(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+ logger = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(debug_logger=logger)
+ result = reg.getUtility(IDebugLogger)
+ self.assertEqual(logger, result)
+
+ def test_setup_registry_debug_logger_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDebugLogger
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(debug_logger='pyramid.tests')
+ result = reg.getUtility(IDebugLogger)
+ import pyramid.tests
+ self.assertEqual(result, pyramid.tests)
+
+ def test_setup_registry_authentication_policy(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthenticationPolicy
+ policy = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(authentication_policy=policy)
+ result = reg.getUtility(IAuthenticationPolicy)
+ self.assertEqual(policy, result)
+
+ def test_setup_registry_authentication_policy_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthenticationPolicy
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(authentication_policy='pyramid.tests')
+ result = reg.getUtility(IAuthenticationPolicy)
+ import pyramid.tests
+ self.assertEqual(result, pyramid.tests)
+
+ def test_setup_registry_authorization_policy_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IAuthorizationPolicy
+ reg = Registry()
+ config = self._makeOne(reg)
+ dummy = object()
+ config.setup_registry(authentication_policy=dummy,
+ authorization_policy='pyramid.tests')
+ result = reg.getUtility(IAuthorizationPolicy)
+ import pyramid.tests
+ self.assertEqual(result, pyramid.tests)
+
+ def test_setup_registry_authorization_policy_only(self):
+ from pyramid.registry import Registry
+ from pyramid.exceptions import ConfigurationError
+ policy = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config = self.assertRaises(ConfigurationError,
+ config.setup_registry,
+ authorization_policy=policy)
+
+ def test_setup_registry_default_root_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRootFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry()
+ self.failUnless(reg.getUtility(IRootFactory))
+
+ def test_setup_registry_dottedname_root_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRootFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ import pyramid.tests
+ config.setup_registry(root_factory='pyramid.tests')
+ self.assertEqual(reg.getUtility(IRootFactory), pyramid.tests)
+
+ def test_setup_registry_locale_negotiator_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ILocaleNegotiator
+ reg = Registry()
+ config = self._makeOne(reg)
+ import pyramid.tests
+ config.setup_registry(locale_negotiator='pyramid.tests')
+ utility = reg.getUtility(ILocaleNegotiator)
+ self.assertEqual(utility, pyramid.tests)
+
+ def test_setup_registry_locale_negotiator(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ILocaleNegotiator
+ reg = Registry()
+ config = self._makeOne(reg)
+ negotiator = object()
+ config.setup_registry(locale_negotiator=negotiator)
+ utility = reg.getUtility(ILocaleNegotiator)
+ self.assertEqual(utility, negotiator)
+
+ def test_setup_registry_request_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRequestFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ factory = object()
+ config.setup_registry(request_factory=factory)
+ utility = reg.getUtility(IRequestFactory)
+ self.assertEqual(utility, factory)
+
+ def test_setup_registry_request_factory_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRequestFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ import pyramid.tests
+ config.setup_registry(request_factory='pyramid.tests')
+ utility = reg.getUtility(IRequestFactory)
+ self.assertEqual(utility, pyramid.tests)
+
+ def test_setup_registry_renderer_globals_factory(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererGlobalsFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ factory = object()
+ config.setup_registry(renderer_globals_factory=factory)
+ utility = reg.getUtility(IRendererGlobalsFactory)
+ self.assertEqual(utility, factory)
+
+ def test_setup_registry_renderer_globals_factory_dottedname(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererGlobalsFactory
+ reg = Registry()
+ config = self._makeOne(reg)
+ import pyramid.tests
+ config.setup_registry(renderer_globals_factory='pyramid.tests')
+ utility = reg.getUtility(IRendererGlobalsFactory)
+ self.assertEqual(utility, pyramid.tests)
+
+ def test_setup_registry_alternate_renderers(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IRendererFactory
+ renderer = object()
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(renderers=[('yeah', renderer)])
+ self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'),
+ renderer)
+
+ def test_setup_registry_default_permission(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import IDefaultPermission
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.setup_registry(default_permission='view')
+ self.assertEqual(reg.getUtility(IDefaultPermission), 'view')
+
+ def test_get_settings_nosettings(self):
+ from pyramid.registry import Registry
+ reg = Registry()
+ config = self._makeOne(reg)
+ self.assertEqual(config.get_settings(), None)
+
+ def test_get_settings_withsettings(self):
+ settings = {'a':1}
+ config = self._makeOne()
+ config.registry.settings = settings
+ self.assertEqual(config.get_settings(), settings)
+
+ def test_add_settings_settings_already_registered(self):
+ from pyramid.registry import Registry
+ reg = Registry()
+ config = self._makeOne(reg)
+ config._set_settings({'a':1})
+ config.add_settings({'b':2})
+ settings = reg.settings
+ self.assertEqual(settings['a'], 1)
+ self.assertEqual(settings['b'], 2)
+
+ def test_add_settings_settings_not_yet_registered(self):
+ from pyramid.registry import Registry
+ from pyramid.interfaces import ISettings
+ reg = Registry()
+ config = self._makeOne(reg)
+ config.add_settings({'a':1})
+ settings = reg.getUtility(ISettings)
+ self.assertEqual(settings['a'], 1)
+
+ def test_add_subscriber_defaults(self):
+ from zope.interface import implements
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ class Event:
+ implements(IEvent)
+ L = []
+ def subscriber(event):
+ L.append(event)
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber)
+ event = Event()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 2)
+
+ def test_add_subscriber_iface_specified(self):
+ from zope.interface import implements
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ class Event:
+ implements(IEvent)
+ L = []
+ def subscriber(event):
+ L.append(event)
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber, IEvent)
+ event = Event()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_add_subscriber_dottednames(self):
+ import pyramid.tests
+ from pyramid.interfaces import INewRequest
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber('pyramid.tests',
+ 'pyramid.interfaces.INewRequest')
+ handlers = list(config.registry.registeredHandlers())
+ self.assertEqual(len(handlers), 1)
+ handler = handlers[0]
+ self.assertEqual(handler.handler, pyramid.tests)
+ self.assertEqual(handler.required, (INewRequest,))
+
+ def test_add_object_event_subscriber(self):
+ from zope.interface import implements
+ from zope.interface import Interface
+ class IEvent(Interface):
+ pass
+ class Event:
+ object = 'foo'
+ implements(IEvent)
+ event = Event()
+ L = []
+ def subscriber(object, event):
+ L.append(event)
+ config = self._makeOne(autocommit=True)
+ config.add_subscriber(subscriber, (Interface, IEvent))
+ config.registry.subscribers((event.object, event), None)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.subscribers((event.object, IDummy), None)
+ self.assertEqual(len(L), 1)
+
+ def test_make_wsgi_app(self):
+ from pyramid.router import Router
+ from pyramid.interfaces import IApplicationCreated
+ manager = DummyThreadLocalManager()
+ config = self._makeOne()
+ subscriber = self._registerEventListener(config, IApplicationCreated)
+ config.manager = manager
+ app = config.make_wsgi_app()
+ self.assertEqual(app.__class__, Router)
+ self.assertEqual(manager.pushed['registry'], config.registry)
+ self.assertEqual(manager.pushed['request'], None)
+ self.failUnless(manager.popped)
+ self.assertEqual(len(subscriber), 1)
+ self.failUnless(IApplicationCreated.providedBy(subscriber[0]))
+
+ def test_load_zcml_default(self):
+ import pyramid.tests.fixtureapp
+ config = self._makeOne(package=pyramid.tests.fixtureapp,
+ autocommit=True)
+ registry = config.load_zcml()
+ from pyramid.tests.fixtureapp.models import IFixture
+ self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
+
+ def test_load_zcml_routesapp(self):
+ from pyramid.interfaces import IRoutesMapper
+ config = self._makeOne(autocommit=True)
+ config.load_zcml('pyramid.tests.routesapp:configure.zcml')
+ self.failUnless(config.registry.getUtility(IRoutesMapper))
+
+ def test_load_zcml_fixtureapp(self):
+ from pyramid.tests.fixtureapp.models import IFixture
+ config = self._makeOne(autocommit=True)
+ config.load_zcml('pyramid.tests.fixtureapp:configure.zcml')
+ self.failUnless(config.registry.queryUtility(IFixture)) # only in c.zcml
+
+ def test_load_zcml_as_relative_filename(self):
+ import pyramid.tests.fixtureapp
+ config = self._makeOne(package=pyramid.tests.fixtureapp,
+ autocommit=True)
+ registry = config.load_zcml('configure.zcml')
+ from pyramid.tests.fixtureapp.models import IFixture
+ self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
+
+ def test_load_zcml_as_absolute_filename(self):
+ import os
+ import pyramid.tests.fixtureapp
+ config = self._makeOne(package=pyramid.tests.fixtureapp,
+ autocommit=True)
+ dn = os.path.dirname(pyramid.tests.fixtureapp.__file__)
+ c_z = os.path.join(dn, 'configure.zcml')
+ registry = config.load_zcml(c_z)
+ from pyramid.tests.fixtureapp.models import IFixture
+ self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
+
+ def test_load_zcml_lock_and_unlock(self):
+ config = self._makeOne(autocommit=True)
+ dummylock = DummyLock()
+ config.load_zcml(
+ 'pyramid.tests.fixtureapp:configure.zcml',
+ lock=dummylock)
+ self.assertEqual(dummylock.acquired, True)
+ self.assertEqual(dummylock.released, True)
+
+ def test_include_with_dotted_name(self):
+ from pyramid import tests
+ config = self._makeOne()
+ context_before = config._make_context()
+ config._ctx = context_before
+ config.include('pyramid.tests.test_config.dummy_include')
+ context_after = config._ctx
+ actions = context_after.actions
+ self.assertEqual(len(actions), 1)
+ self.assertEqual(
+ context_after.actions[0][:3],
+ ('discrim', None, tests),
+ )
+ self.assertEqual(context_after.basepath, None)
+ self.assertEqual(context_after.includepath, ())
+ self.failUnless(context_after is context_before)
+
+ def test_include_with_python_callable(self):
+ from pyramid import tests
+ config = self._makeOne()
+ context_before = config._make_context()
+ config._ctx = context_before
+ config.include(dummy_include)
+ context_after = config._ctx
+ actions = context_after.actions
+ self.assertEqual(len(actions), 1)
+ self.assertEqual(
+ actions[0][:3],
+ ('discrim', None, tests),
+ )
+ self.assertEqual(context_after.basepath, None)
+ self.assertEqual(context_after.includepath, ())
+ self.failUnless(context_after is context_before)
+
+ def test_add_view_view_callable_None_no_renderer(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne(autocommit=True)
+ self.assertRaises(ConfigurationError, config.add_view)
+
+ def test_add_view_with_request_type_and_route_name(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ self.assertRaises(ConfigurationError, config.add_view, view, '', None,
+ None, True, True)
+
+ def test_add_view_with_request_type(self):
+ from zope.interface import directlyProvides
+ from pyramid.interfaces import IRequest
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view,
+ request_type='pyramid.interfaces.IRequest')
+ wrapper = self._getViewCallable(config)
+ request = DummyRequest()
+ self._assertNotFound(wrapper, None, request)
+ directlyProvides(request, IRequest)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_view_callable_None_with_renderer(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config, name='dummy')
+ config.add_view(renderer='dummy')
+ view = self._getViewCallable(config)
+ self.failUnless('Hello!' in view(None, None).body)
+
+ def test_add_view_wrapped_view_is_decorated(self):
+ def view(request): # request-only wrapper
+ """ """
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ self.assertEqual(wrapper.__module__, view.__module__)
+ self.assertEqual(wrapper.__name__, view.__name__)
+ self.assertEqual(wrapper.__doc__, view.__doc__)
+
+ def test_add_view_view_callable_dottedname(self):
+ config = self._makeOne(autocommit=True)
+ config.add_view(view='pyramid.tests.test_config.dummy_view')
+ wrapper = self._getViewCallable(config)
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_with_function_callable(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_function_callable_requestonly(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_instance(self):
+ class AView:
+ def __call__(self, context, request):
+ """ """
+ return 'OK'
+ view = AView()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_instance_requestonly(self):
+ class AView:
+ def __call__(self, request):
+ """ """
+ return 'OK'
+ view = AView()
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_oldstyle_class(self):
+ class view:
+ def __init__(self, context, request):
+ self.context = context
+ self.request = request
+
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, request):
+ self.request = request
+
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ result = wrapper(None, None)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_context_as_class(self):
+ from zope.interface import implementedBy
+ view = lambda *arg: 'OK'
+ class Foo:
+ pass
+ config = self._makeOne(autocommit=True)
+ config.add_view(context=Foo, view=view)
+ foo = implementedBy(Foo)
+ wrapper = self._getViewCallable(config, foo)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_as_iface(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(context=IDummy, view=view)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_as_dottedname(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(context='pyramid.tests.test_config.IDummy',
+ view=view)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for__as_dottedname(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(for_='pyramid.tests.test_config.IDummy',
+ view=view)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for_as_class(self):
+ # ``for_`` is older spelling for ``context``
+ from zope.interface import implementedBy
+ view = lambda *arg: 'OK'
+ class Foo:
+ pass
+ config = self._makeOne(autocommit=True)
+ config.add_view(for_=Foo, view=view)
+ foo = implementedBy(Foo)
+ wrapper = self._getViewCallable(config, foo)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_for_as_iface(self):
+ # ``for_`` is older spelling for ``context``
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(for_=IDummy, view=view)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_context_trumps_for(self):
+ # ``for_`` is older spelling for ``context``
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ class Foo:
+ pass
+ config.add_view(context=IDummy, for_=Foo, view=view)
+ wrapper = self._getViewCallable(config, IDummy)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_register_secured_view(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IViewClassifier
+ view = lambda *arg: 'OK'
+ view.__call_permissive__ = view
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view)
+ wrapper = config.registry.adapters.lookup(
+ (IViewClassifier, IRequest, Interface),
+ ISecuredView, name='', default=None)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_exception_register_secured_view(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ view = lambda *arg: 'OK'
+ view.__call_permissive__ = view
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, context=RuntimeError)
+ wrapper = config.registry.adapters.lookup(
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='', default=None)
+ self.assertEqual(wrapper, view)
+
+ def test_add_view_same_phash_overrides_existing_single_view(self):
+ from pyramid.compat import md5
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ phash = md5()
+ phash.update('xhr:True')
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = phash.hexdigest()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview, xhr=True)
+ wrapper = self._getViewCallable(config)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_same_phash_overrides_existing_single_view(self):
+ from pyramid.compat import md5
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+ phash = md5()
+ phash.update('xhr:True')
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = phash.hexdigest()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview, xhr=True, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_default_phash_overrides_no_phash(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview)
+ wrapper = self._getViewCallable(config)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_default_phash_overrides_no_phash(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_default_phash_overrides_default_phash(self):
+ from pyramid.config import DEFAULT_PHASH
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = DEFAULT_PHASH
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview)
+ wrapper = self._getViewCallable(config)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_default_phash_overrides_default_phash(self):
+ from pyramid.config import DEFAULT_PHASH
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'NOT OK'
+ view.__phash__ = DEFAULT_PHASH
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ def newview(context, request):
+ return 'OK'
+ config.add_view(view=newview, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failIf(IMultiView.providedBy(wrapper))
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_multiview_replaces_existing_view(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_exc_multiview_replaces_existing_view(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IExceptionViewClassifier
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IMultiView
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.add_view(view=view, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_multiview_replaces_existing_securedview(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface),
+ ISecuredView, name='')
+ config.add_view(view=view)
+ wrapper = self._getViewCallable(config)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_exc_multiview_replaces_existing_securedview(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import ISecuredView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ view = lambda *arg: 'OK'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ ISecuredView, name='')
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ ISecuredView, name='')
+ config.add_view(view=view, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_view_with_accept_multiview_replaces_existing_view(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ def view(context, request):
+ return 'OK'
+ def view2(context, request):
+ return 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ config.add_view(view=view2, accept='text/html')
+ wrapper = self._getViewCallable(config)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK2')
+
+ def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ def view(context, request):
+ return 'OK'
+ def view2(context, request):
+ return 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.add_view(view=view2, accept='text/html', context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/html')
+ self.assertEqual(wrapper(None, request), 'OK2')
+
+ def test_add_view_multiview_replaces_existing_view_with___accept__(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ def view(context, request):
+ return 'OK'
+ def view2(context, request):
+ return 'OK2'
+ view.__accept__ = 'text/html'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface), IView, name='')
+ config.add_view(view=view2)
+ wrapper = self._getViewCallable(config)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK2')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ def view(context, request):
+ return 'OK'
+ def view2(context, request):
+ return 'OK2'
+ view.__accept__ = 'text/html'
+ view.__phash__ = 'abc'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IView, name='')
+ config.add_view(view=view2, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual(len(wrapper.views), 1)
+ self.assertEqual(len(wrapper.media_views), 1)
+ self.assertEqual(wrapper(None, None), 'OK2')
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_multiview_replaces_multiview(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ view = DummyMultiView()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Interface),
+ IMultiView, name='')
+ view2 = lambda *arg: 'OK2'
+ config.add_view(view=view2)
+ wrapper = self._getViewCallable(config)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
+ self.assertEqual(wrapper(None, None), 'OK1')
+
+ def test_add_view_exc_multiview_replaces_multiview(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ view = DummyMultiView()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view,
+ (IViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView, name='')
+ config.registry.registerAdapter(
+ view,
+ (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
+ IMultiView, name='')
+ view2 = lambda *arg: 'OK2'
+ config.add_view(view=view2, context=RuntimeError)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
+ self.failUnless(IMultiView.providedBy(wrapper))
+ self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
+ self.assertEqual(wrapper(None, None), 'OK1')
+
+ def test_add_view_multiview_context_superclass_then_subclass(self):
+ from zope.interface import Interface
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ class ISuper(Interface):
+ pass
+ class ISub(ISuper):
+ pass
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, ISuper), IView, name='')
+ config.add_view(view=view2, for_=ISub)
+ wrapper = self._getViewCallable(config, ISuper, IRequest)
+ self.failIf(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK')
+ wrapper = self._getViewCallable(config, ISub, IRequest)
+ self.failIf(IMultiView.providedBy(wrapper))
+ self.assertEqual(wrapper(None, None), 'OK2')
+
+ def test_add_view_multiview_exception_superclass_then_subclass(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IMultiView
+ from pyramid.interfaces import IViewClassifier
+ from pyramid.interfaces import IExceptionViewClassifier
+ class Super(Exception):
+ pass
+ class Sub(Super):
+ pass
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'OK2'
+ config = self._makeOne(autocommit=True)
+ config.registry.registerAdapter(
+ view, (IViewClassifier, IRequest, Super), IView, name='')
+ config.registry.registerAdapter(
+ view, (IExceptionViewClassifier, IRequest, Super), IView, name='')
+ config.add_view(view=view2, for_=Sub)
+ wrapper = self._getViewCallable(
+ config, implementedBy(Super), IRequest)
+ wrapper_exc_view = self._getViewCallable(
+ config, implementedBy(Super), IRequest, exception_view=True)
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.failIf(IMultiView.providedBy(wrapper_exc_view))
+ self.assertEqual(wrapper_exc_view(None, None), 'OK')
+ wrapper = self._getViewCallable(
+ config, implementedBy(Sub), IRequest)
+ wrapper_exc_view = self._getViewCallable(
+ config, implementedBy(Sub), IRequest, exception_view=True)
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.failIf(IMultiView.providedBy(wrapper_exc_view))
+ self.assertEqual(wrapper_exc_view(None, None), 'OK2')
+
+ def test_add_view_multiview_call_ordering(self):
+ from zope.interface import directlyProvides
+ def view1(context, request): return 'view1'
+ def view2(context, request): return 'view2'
+ def view3(context, request): return 'view3'
+ def view4(context, request): return 'view4'
+ def view5(context, request): return 'view5'
+ def view6(context, request): return 'view6'
+ def view7(context, request): return 'view7'
+ def view8(context, request): return 'view8'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view1)
+ config.add_view(view=view2, request_method='POST')
+ config.add_view(view=view3,request_param='param')
+ config.add_view(view=view4, containment=IDummy)
+ config.add_view(view=view5, request_method='POST',request_param='param')
+ config.add_view(view=view6, request_method='POST', containment=IDummy)
+ config.add_view(view=view7, request_param='param', containment=IDummy)
+ config.add_view(view=view8, request_method='POST',request_param='param',
+ containment=IDummy)
+
+
+ wrapper = self._getViewCallable(config)
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {}
+ self.assertEqual(wrapper(ctx, request), 'view1')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.params = {}
+ request.method = 'POST'
+ self.assertEqual(wrapper(ctx, request), 'view2')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.params = {'param':'1'}
+ request.method = 'GET'
+ self.assertEqual(wrapper(ctx, request), 'view3')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {}
+ self.assertEqual(wrapper(ctx, request), 'view4')
+
+ ctx = DummyContext()
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {'param':'1'}
+ self.assertEqual(wrapper(ctx, request), 'view5')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.params = {}
+ request.method = 'POST'
+ self.assertEqual(wrapper(ctx, request), 'view6')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.params = {'param':'1'}
+ self.assertEqual(wrapper(ctx, request), 'view7')
+
+ ctx = DummyContext()
+ directlyProvides(ctx, IDummy)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ request.params = {'param':'1'}
+ self.assertEqual(wrapper(ctx, request), 'view8')
+
+ def test_add_view_with_template_renderer(self):
+ import pyramid.tests
+ from pyramid.interfaces import ISettings
+ class view(object):
+ def __init__(self, context, request):
+ self.request = request
+ self.context = context
+
+ def __call__(self):
+ return {'a':'1'}
+ config = self._makeOne(autocommit=True)
+ renderer = self._registerRenderer(config)
+ fixture = 'pyramid.tests:fixtures/minimal.txt'
+ config.add_view(view=view, renderer=fixture)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result.body, 'Hello!')
+ settings = config.registry.queryUtility(ISettings)
+ result = renderer.info
+ self.assertEqual(result.registry, config.registry)
+ self.assertEqual(result.type, '.txt')
+ self.assertEqual(result.package, pyramid.tests)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_add_view_with_template_renderer_no_callable(self):
+ import pyramid.tests
+ from pyramid.interfaces import ISettings
+ config = self._makeOne(autocommit=True)
+ renderer = self._registerRenderer(config)
+ fixture = 'pyramid.tests:fixtures/minimal.txt'
+ config.add_view(view=None, renderer=fixture)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ result = wrapper(None, request)
+ self.assertEqual(result.body, 'Hello!')
+ settings = config.registry.queryUtility(ISettings)
+ result = renderer.info
+ self.assertEqual(result.registry, config.registry)
+ self.assertEqual(result.type, '.txt')
+ self.assertEqual(result.package, pyramid.tests)
+ self.assertEqual(result.name, fixture)
+ self.assertEqual(result.settings, settings)
+
+ def test_add_view_with_request_type_as_iface(self):
+ from zope.interface import directlyProvides
+ def view(context, request):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(request_type=IDummy, view=view)
+ wrapper = self._getViewCallable(config, None)
+ request = self._makeRequest(config)
+ directlyProvides(request, IDummy)
+ result = wrapper(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_add_view_with_request_type_as_noniface(self):
+ from pyramid.exceptions import ConfigurationError
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError,
+ config.add_view, view, '', None, None, object)
+
+ def test_add_view_with_route_name(self):
+ from zope.component import ComponentLookupError
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, route_name='foo')
+ self.assertEqual(len(config.registry.deferred_route_views), 1)
+ infos = config.registry.deferred_route_views['foo']
+ self.assertEqual(len(infos), 1)
+ info = infos[0]
+ self.assertEqual(info['route_name'], 'foo')
+ self.assertEqual(info['view'], view)
+ self.assertRaises(ComponentLookupError,
+ self._getRouteRequestIface, config, 'foo')
+ wrapper = self._getViewCallable(config, None)
+ self.assertEqual(wrapper, None)
+ config.add_route('foo', '/a/b')
+ request_iface = self._getRouteRequestIface(config, 'foo')
+ self.failIfEqual(request_iface, None)
+ wrapper = self._getViewCallable(config, request_iface=request_iface)
+ self.failIfEqual(wrapper, None)
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_deferred_route_views_retains_custom_predicates(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, route_name='foo', custom_predicates=('123',))
+ self.assertEqual(len(config.registry.deferred_route_views), 1)
+ infos = config.registry.deferred_route_views['foo']
+ self.assertEqual(len(infos), 1)
+ info = infos[0]
+ self.assertEqual(info['route_name'], 'foo')
+ self.assertEqual(info['custom_predicates'], ('123',))
+
+ def test_add_view_with_route_name_exception(self):
+ from zope.interface import implementedBy
+ from zope.component import ComponentLookupError
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, route_name='foo', context=RuntimeError)
+ self.assertEqual(len(config.registry.deferred_route_views), 1)
+ infos = config.registry.deferred_route_views['foo']
+ self.assertEqual(len(infos), 1)
+ info = infos[0]
+ self.assertEqual(info['route_name'], 'foo')
+ self.assertEqual(info['view'], view)
+ self.assertRaises(ComponentLookupError,
+ self._getRouteRequestIface, config, 'foo')
+ wrapper_exc_view = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError),
+ exception_view=True)
+ self.assertEqual(wrapper_exc_view, None)
+ config.add_route('foo', '/a/b')
+ request_iface = self._getRouteRequestIface(config, 'foo')
+ self.failIfEqual(request_iface, None)
+ wrapper_exc_view = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError),
+ request_iface=request_iface, exception_view=True)
+ self.failIfEqual(wrapper_exc_view, None)
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError),
+ request_iface=request_iface)
+ self.assertEqual(wrapper_exc_view, wrapper)
+ self.assertEqual(wrapper_exc_view(None, None), 'OK')
+
+ def test_add_view_with_request_method_true(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_method='POST')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_method_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_method='POST')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_request_param_noval_true(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc':''}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_param_noval_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_request_param_val_true(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc=123')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc':'123'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_request_param_val_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_param='abc=123')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.params = {'abc':''}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_xhr_true(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, xhr=True)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_xhr_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, xhr=True)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.is_xhr = False
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_badregex(self):
+ from pyramid.exceptions import ConfigurationError
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError,
+ config.add_view, view=view, header='Host:a\\')
+
+ def test_add_view_with_header_noval_match(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header='Host')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host':'whatever'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_header_noval_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header='Host')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'NotHost':'whatever'}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_val_match(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host':'1'}
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_header_val_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'Host':'abc'}
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_header_val_missing(self):
+ from pyramid.exceptions import NotFound
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, header=r'Host:\d')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.headers = {'NoHost':'1'}
+ self.assertRaises(NotFound, wrapper, None, request)
+
+ def test_add_view_with_accept_match(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, accept='text/xml')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.accept = ['text/xml']
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_accept_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, accept='text/xml')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.accept = ['text/html']
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_containment_true(self):
+ from zope.interface import directlyProvides
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, containment=IDummy)
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ self.assertEqual(wrapper(context, None), 'OK')
+
+ def test_add_view_with_containment_false(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, containment=IDummy)
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ self._assertNotFound(wrapper, context, None)
+
+ def test_add_view_with_containment_dottedname(self):
+ from zope.interface import directlyProvides
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(
+ view=view,
+ containment='pyramid.tests.test_config.IDummy')
+ wrapper = self._getViewCallable(config)
+ context = DummyContext()
+ directlyProvides(context, IDummy)
+ self.assertEqual(wrapper(context, None), 'OK')
+
+ def test_add_view_with_path_info_badregex(self):
+ from pyramid.exceptions import ConfigurationError
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError,
+ config.add_view, view=view, path_info='\\')
+
+ def test_add_view_with_path_info_match(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, path_info='/foo')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.path_info = '/foo'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_path_info_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, path_info='/foo')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.path_info = '/'
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_with_custom_predicates_match(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ def pred1(context, request):
+ return True
+ def pred2(context, request):
+ return True
+ predicates = (pred1, pred2)
+ config.add_view(view=view, custom_predicates=predicates)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_with_custom_predicates_nomatch(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne(autocommit=True)
+ def pred1(context, request):
+ return True
+ def pred2(context, request):
+ return False
+ predicates = (pred1, pred2)
+ config.add_view(view=view, custom_predicates=predicates)
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self._assertNotFound(wrapper, None, request)
+
+ def test_add_view_custom_predicate_bests_standard_predicate(self):
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ def pred1(context, request):
+ return True
+ config.add_view(view=view, custom_predicates=(pred1,))
+ config.add_view(view=view2, request_method='GET')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):
+ view = lambda *arg: 'OK'
+ view2 = lambda *arg: 'NOT OK'
+ config = self._makeOne(autocommit=True)
+ config.add_view(view=view, request_method='GET', xhr=True)
+ config.add_view(view=view2, request_method='GET')
+ wrapper = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ request.is_xhr = True
+ self.assertEqual(wrapper(None, request), 'OK')
+
+ def test_add_view_same_predicates(self):
+ from zope.configuration.config import ConfigurationConflictError
+ view2 = lambda *arg: 'second'
+ view1 = lambda *arg: 'first'
+ config = self._makeOne()
+ config.add_view(view=view1)
+ config.add_view(view=view2)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_add_view_with_permission(self):
+ view1 = lambda *arg: 'OK'
+ outerself = self
+ class DummyPolicy(object):
+ def effective_principals(self, r):
+ outerself.assertEqual(r, request)
+ return ['abc']
+ def permits(self, context, principals, permission):
+ outerself.assertEqual(context, None)
+ outerself.assertEqual(principals, ['abc'])
+ outerself.assertEqual(permission, 'view')
+ return True
+ policy = DummyPolicy()
+ config = self._makeOne(authorization_policy=policy,
+ authentication_policy=policy,
+ autocommit=True)
+ config.add_view(view=view1, permission='view')
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_default_permission_no_explicit_permission(self):
+ view1 = lambda *arg: 'OK'
+ outerself = self
+ class DummyPolicy(object):
+ def effective_principals(self, r):
+ outerself.assertEqual(r, request)
+ return ['abc']
+ def permits(self, context, principals, permission):
+ outerself.assertEqual(context, None)
+ outerself.assertEqual(principals, ['abc'])
+ outerself.assertEqual(permission, 'view')
+ return True
+ policy = DummyPolicy()
+ config = self._makeOne(authorization_policy=policy,
+ authentication_policy=policy,
+ default_permission='view',
+ autocommit=True)
+ config.add_view(view=view1)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_view_with_no_default_permission_no_explicit_permission(self):
+ view1 = lambda *arg: 'OK'
+ class DummyPolicy(object): pass # wont be called
+ policy = DummyPolicy()
+ config = self._makeOne(authorization_policy=policy,
+ authentication_policy=policy,
+ autocommit=True)
+ config.add_view(view=view1)
+ view = self._getViewCallable(config)
+ request = self._makeRequest(config)
+ self.assertEqual(view(None, request), 'OK')
+
+ def test_add_handler_action_in_route_pattern(self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_handler('name', '/:action', DummyHandler)
+ self._assertRoute(config, 'name', '/:action', 0)
+ self.assertEqual(len(views), 2)
+
+ view = views[0]
+ preds = view['custom_predicates']
+ self.assertEqual(len(preds), 1)
+ pred = preds[0]
+ request = DummyRequest()
+ self.assertEqual(pred(None, request), False)
+ request.matchdict = {'action':'action1'}
+ self.assertEqual(pred(None, request), True)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['attr'], 'action1')
+ self.assertEqual(view['view'], DummyHandler)
+
+ view = views[1]
+ preds = view['custom_predicates']
+ self.assertEqual(len(preds), 1)
+ pred = preds[0]
+ request = DummyRequest()
+ self.assertEqual(pred(None, request), False)
+ request.matchdict = {'action':'action2'}
+ self.assertEqual(pred(None, request), True)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['attr'], 'action2')
+ self.assertEqual(view['view'], DummyHandler)
+
+ def test_add_handler_with_view_overridden_autoexpose_None(self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw) # pragma: no cover
+ config.add_view = dummy_add_view
+ class MyView(DummyHandler):
+ __autoexpose__ = None
+ config.add_handler('name', '/:action', MyView)
+ self._assertRoute(config, 'name', '/:action', 0)
+ self.assertEqual(len(views), 0)
+
+ def test_add_handler_with_view_overridden_autoexpose_broken_regex1(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ def dummy_add_view(**kw):
+ """ """
+ config.add_view = dummy_add_view
+ class MyView(DummyHandler):
+ __autoexpose__ = 1
+ self.assertRaises(ConfigurationError, config.add_handler,
+ 'name', '/{action}', MyView)
+
+ def test_add_handler_with_view_overridden_autoexpose_broken_regex2(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ def dummy_add_view(**kw):
+ """ """
+ config.add_view = dummy_add_view
+ class MyView(DummyHandler):
+ __autoexpose__ = 'a\\'
+ self.assertRaises(ConfigurationError, config.add_handler,
+ 'name', '/{action}', MyView)
+
+ def test_add_handler_with_view_method_has_expose_config(self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ class MyView(object):
+ def action(self): # pragma: no cover
+ return 'response'
+ action.__exposed__ = [{'custom_predicates':(1,)}]
+ config.add_handler('name', '/:action', MyView)
+ self._assertRoute(config, 'name', '/:action', 0)
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ preds = view['custom_predicates']
+ self.assertEqual(len(preds), 2)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['attr'], 'action')
+ self.assertEqual(view['view'], MyView)
+
+ def test_add_handler_with_view_method_has_expose_config_with_action(self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ class MyView(object):
+ def action(self): # pragma: no cover
+ return 'response'
+ action.__exposed__ = [{'name':'action3000'}]
+ config.add_handler('name', '/:action', MyView)
+ self._assertRoute(config, 'name', '/:action', 0)
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ preds = view['custom_predicates']
+ self.assertEqual(len(preds), 1)
+ pred = preds[0]
+ request = DummyRequest()
+ self.assertEqual(pred(None, request), False)
+ request.matchdict = {'action':'action3000'}
+ self.assertEqual(pred(None, request), True)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['attr'], 'action')
+ self.assertEqual(view['view'], MyView)
+
+ def test_add_handler_with_view_method_has_expose_config_with_action_regex(
+ self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ class MyView(object):
+ def action(self): # pragma: no cover
+ return 'response'
+ action.__exposed__ = [{'name':'^action3000$'}]
+ config.add_handler('name', '/:action', MyView)
+ self._assertRoute(config, 'name', '/:action', 0)
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ preds = view['custom_predicates']
+ self.assertEqual(len(preds), 1)
+ pred = preds[0]
+ request = DummyRequest()
+ self.assertEqual(pred(None, request), False)
+ request.matchdict = {'action':'action3000'}
+ self.assertEqual(pred(None, request), True)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['attr'], 'action')
+ self.assertEqual(view['view'], MyView)
+
+ def test_add_handler_doesnt_mutate_expose_dict(self):
+ config = self._makeOne(autocommit=True)
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ exposed = [{'name':'^action3000$'}]
+ class MyView(object):
+ def action(self): # pragma: no cover
+ return 'response'
+ action.__exposed__ = exposed
+ config.add_handler('name', '/{action}', MyView)
+ self.assertEqual(exposed[0], {'name':'^action3000$'}) # not mutated
+
+ def test_add_handler_with_action_and_action_in_path(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_handler,
+ 'name', '/{action}', DummyHandler, action='abc')
+
+ def test_add_handler_with_explicit_action(self):
+ config = self._makeOne(autocommit=True)
+ class DummyHandler(object):
+ def index(self): pass
+ index.__exposed__ = [{'a':'1'}]
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_handler('name', '/abc', DummyHandler, action='index')
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ self.assertEqual(view['a'], '1')
+ self.assertEqual(view['attr'], 'index')
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['view'], DummyHandler)
+
+ def test_add_handler_with_implicit_action(self):
+ config = self._makeOne(autocommit=True)
+ class DummyHandler(object):
+ def __call__(self): pass
+ __call__.__exposed__ = [{'a':'1'}]
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_handler('name', '/abc', DummyHandler)
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ self.assertEqual(view['a'], '1')
+ self.assertEqual(view['attr'], None)
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['view'], DummyHandler)
+
+ def test_add_handler_with_multiple_action(self):
+ config = self._makeOne(autocommit=True)
+ class DummyHandler(object):
+ def index(self): pass
+ def create(self): pass
+ create.__exposed__ = [{'name': 'index'}]
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_handler('name', '/abc', DummyHandler, action='index')
+ self.assertEqual(len(views), 2)
+ view = views[0]
+ self.assertEqual(view['attr'], 'create')
+ self.assertEqual(view['route_name'], 'name')
+ self.assertEqual(view['view'], DummyHandler)
+ view = views[1]
+ self.assertEqual(view['attr'], 'index')
+
+ def test_add_handler_string(self):
+ import pyramid
+ views = []
+ config = self._makeOne(autocommit=True)
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_handler('name', '/abc', 'pyramid')
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ self.assertEqual(view['view'], pyramid)
+
+ def test_add_handler_pattern_None_no_previous_route(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_handler,
+ 'name', None, 'pyramid')
+
+ def test_add_handler_pattern_None_with_previous_route(self):
+ import pyramid
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', ':def')
+ views = []
+ def dummy_add_view(**kw):
+ views.append(kw)
+ config.add_view = dummy_add_view
+ config.add_route = None # shouldn't be called
+ config.add_handler('name', None, 'pyramid')
+ self.assertEqual(len(views), 1)
+ view = views[0]
+ self.assertEqual(view['view'], pyramid)
+
+
+ def _assertRoute(self, config, name, path, num_predicates=0):
+ from pyramid.interfaces import IRoutesMapper
+ mapper = config.registry.getUtility(IRoutesMapper)
+ routes = mapper.get_routes()
+ route = routes[0]
+ self.assertEqual(len(routes), 1)
+ self.assertEqual(route.name, name)
+ self.assertEqual(route.path, path)
+ self.assertEqual(len(routes[0].predicates), num_predicates)
+ return route
+
+ def test_get_routes_mapper_not_yet_registered(self):
+ config = self._makeOne()
+ mapper = config.get_routes_mapper()
+ self.assertEqual(mapper.routelist, [])
+
+ def test_get_routes_mapper_already_registered(self):
+ from pyramid.interfaces import IRoutesMapper
+ config = self._makeOne()
+ mapper = object()
+ config.registry.registerUtility(mapper, IRoutesMapper)
+ result = config.get_routes_mapper()
+ self.assertEqual(result, mapper)
+
+ def test_add_route_defaults(self):
+ config = self._makeOne(autocommit=True)
+ route = config.add_route('name', 'path')
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(route.name, 'name')
+
+ def test_add_route_with_factory(self):
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ route = config.add_route('name', 'path', factory=factory)
+ self.assertEqual(route.factory, factory)
+
+ def test_add_route_with_factory_dottedname(self):
+ config = self._makeOne(autocommit=True)
+ route = config.add_route(
+ 'name', 'path',
+ factory='pyramid.tests.test_config.dummyfactory')
+ self.assertEqual(route.factory, dummyfactory)
+
+ def test_add_route_with_xhr(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', xhr=True)
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.is_xhr = True
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.is_xhr = False
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_request_method(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', request_method='GET')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.method = 'GET'
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_path_info(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', path_info='/foo')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.path_info = '/foo'
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.path_info = '/'
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_request_param(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', request_param='abc')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.params = {'abc':'123'}
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.params = {}
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_custom_predicates(self):
+ config = self._makeOne(autocommit=True)
+ def pred1(context, request): pass
+ def pred2(context, request): pass
+ config.add_route('name', 'path', custom_predicates=(pred1, pred2))
+ route = self._assertRoute(config, 'name', 'path', 2)
+ self.assertEqual(route.predicates, [pred1, pred2])
+
+ def test_add_route_with_header(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', header='Host')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.headers = {'Host':'example.com'}
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.headers = {}
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_accept(self):
+ config = self._makeOne(autocommit=True)
+ config.add_route('name', 'path', accept='text/xml')
+ route = self._assertRoute(config, 'name', 'path', 1)
+ predicate = route.predicates[0]
+ request = self._makeRequest(config)
+ request.accept = ['text/xml']
+ self.assertEqual(predicate(None, request), True)
+ request = self._makeRequest(config)
+ request.accept = ['text/html']
+ self.assertEqual(predicate(None, request), False)
+
+ def test_add_route_with_view(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+
+ def test_add_route_with_view_context(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_context=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_exception(self):
+ from zope.interface import implementedBy
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_context=RuntimeError)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=implementedBy(RuntimeError),
+ request_iface=request_type, exception_view=True)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(
+ config, ctx_iface=IOther,
+ request_iface=request_type, exception_view=True)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_for(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_for=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_for_(self):
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, for_=IDummy)
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, IDummy, request_type)
+ self.assertEqual(wrapper(None, None), 'OK')
+ self._assertRoute(config, 'name', 'path')
+ wrapper = self._getViewCallable(config, IOther, request_type)
+ self.assertEqual(wrapper, None)
+
+ def test_add_route_with_view_renderer(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view,
+ view_renderer='fixtures/minimal.txt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(wrapper(None, None).body, 'Hello!')
+
+ def test_add_route_with_view_attr(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ class View(object):
+ def __init__(self, context, request):
+ pass
+ def alt(self):
+ return 'OK'
+ config.add_route('name', 'path', view=View, view_attr='alt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(wrapper(None, None), 'OK')
+
+ def test_add_route_with_view_renderer_alias(self):
+ config = self._makeOne(autocommit=True)
+ self._registerRenderer(config)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view,
+ renderer='fixtures/minimal.txt')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(wrapper(None, None).body, 'Hello!')
+
+ def test_add_route_with_view_permission(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = lambda *arg: None
+ config.registry.registerUtility(policy, IAuthenticationPolicy)
+ config.registry.registerUtility(policy, IAuthorizationPolicy)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, view_permission='edit')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.failUnless(hasattr(wrapper, '__call_permissive__'))
+
+ def test_add_route_with_view_permission_alias(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = lambda *arg: None
+ config.registry.registerUtility(policy, IAuthenticationPolicy)
+ config.registry.registerUtility(policy, IAuthorizationPolicy)
+ view = lambda *arg: 'OK'
+ config.add_route('name', 'path', view=view, permission='edit')
+ request_type = self._getRouteRequestIface(config, 'name')
+ wrapper = self._getViewCallable(config, None, request_type)
+ self._assertRoute(config, 'name', 'path')
+ self.failUnless(hasattr(wrapper, '__call_permissive__'))
+
+ def test_add_route_no_pattern_with_path(self):
+ config = self._makeOne(autocommit=True)
+ route = config.add_route('name', path='path')
+ self._assertRoute(config, 'name', 'path')
+ self.assertEqual(route.name, 'name')
+
+ def test_add_route_no_path_no_pattern(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.add_route, 'name')
+
+ def test_add_route_with_pregenerator(self):
+ config = self._makeOne(autocommit=True)
+ route = config.add_route('name', 'pattern', pregenerator='123')
+ self.assertEqual(route.pregenerator, '123')
+
+ def test__override_not_yet_registered(self):
+ from pyramid.interfaces import IPackageOverrides
+ package = DummyPackage('package')
+ opackage = DummyPackage('opackage')
+ config = self._makeOne()
+ config._override(package, 'path', opackage, 'oprefix',
+ PackageOverrides=DummyOverrides)
+ overrides = config.registry.queryUtility(IPackageOverrides,
+ name='package')
+ self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
+ self.assertEqual(overrides.package, package)
+
+ def test__override_already_registered(self):
+ from pyramid.interfaces import IPackageOverrides
+ package = DummyPackage('package')
+ opackage = DummyPackage('opackage')
+ overrides = DummyOverrides(package)
+ config = self._makeOne()
+ config.registry.registerUtility(overrides, IPackageOverrides,
+ name='package')
+ config._override(package, 'path', opackage, 'oprefix',
+ PackageOverrides=DummyOverrides)
+ self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
+ self.assertEqual(overrides.package, package)
+
+ def test_add_static_here_no_utility_registered(self):
+ from pyramid.static import PackageURLParser
+ from zope.interface import implementedBy
+ from pyramid.static import StaticURLInfo
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ config = self._makeOne(autocommit=True)
+ config.add_static_view('static', 'fixtures/static')
+ request_type = self._getRouteRequestIface(config, 'static/')
+ route = self._assertRoute(config, 'static/', 'static/*subpath')
+ self.assertEqual(route.factory.__class__, type(lambda x: x))
+ iface = implementedBy(StaticURLInfo)
+ wrapped = config.registry.adapters.lookup(
+ (IViewClassifier, request_type, iface), IView, name='')
+ request = self._makeRequest(config)
+ self.assertEqual(wrapped(None, request).__class__, PackageURLParser)
+
+ def test_add_static_view_package_relative(self):
+ from pyramid.interfaces import IStaticURLInfo
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ config.add_static_view('static', 'pyramid.tests:fixtures/static')
+ self.assertEqual(info.added,
+ [('static', 'pyramid.tests:fixtures/static', {})])
+
+ def test_add_static_view_package_here_relative(self):
+ from pyramid.interfaces import IStaticURLInfo
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ config.add_static_view('static', 'fixtures/static')
+ self.assertEqual(info.added,
+ [('static', 'pyramid.tests:fixtures/static', {})])
+
+ def test_add_static_view_absolute(self):
+ import os
+ from pyramid.interfaces import IStaticURLInfo
+ info = DummyStaticURLInfo()
+ config = self._makeOne(autocommit=True)
+ config.registry.registerUtility(info, IStaticURLInfo)
+ here = os.path.dirname(__file__)
+ static_path = os.path.join(here, 'fixtures', 'static')
+ config.add_static_view('static', static_path)
+ self.assertEqual(info.added,
+ [('static', static_path, {})])
+
+ def test_set_notfound_view(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.exceptions import NotFound
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: arg
+ config.set_notfound_view(view)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
+ request_iface=IRequest)
+ result = view(None, request)
+ self.assertEqual(result, (None, request))
+
+ def test_set_notfound_view_request_has_context(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.exceptions import NotFound
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: arg
+ config.set_notfound_view(view)
+ request = self._makeRequest(config)
+ request.context = 'abc'
+ view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
+ request_iface=IRequest)
+ result = view(None, request)
+ self.assertEqual(result, ('abc', request))
+
+ def test_set_forbidden_view(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.exceptions import Forbidden
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: 'OK'
+ config.set_forbidden_view(view)
+ request = self._makeRequest(config)
+ view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden),
+ request_iface=IRequest)
+ result = view(None, request)
+ self.assertEqual(result, 'OK')
+
+ def test_set_forbidden_view_request_has_context(self):
+ from zope.interface import implementedBy
+ from pyramid.interfaces import IRequest
+ from pyramid.exceptions import Forbidden
+ config = self._makeOne(autocommit=True)
+ view = lambda *arg: arg
+ config.set_forbidden_view(view)
+ request = self._makeRequest(config)
+ request.context = 'abc'
+ view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden),
+ request_iface=IRequest)
+ result = view(None, request)
+ self.assertEqual(result, ('abc', request))
+
+ def test__set_authentication_policy(self):
+ from pyramid.interfaces import IAuthenticationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = object()
+ config._set_authentication_policy(policy)
+ self.assertEqual(
+ config.registry.getUtility(IAuthenticationPolicy), policy)
+
+ def test__set_authorization_policy(self):
+ from pyramid.interfaces import IAuthorizationPolicy
+ config = self._makeOne(autocommit=True)
+ policy = object()
+ config._set_authorization_policy(policy)
+ self.assertEqual(
+ config.registry.getUtility(IAuthorizationPolicy), policy)
+
+ def test_set_locale_negotiator(self):
+ from pyramid.interfaces import ILocaleNegotiator
+ config = self._makeOne(autocommit=True)
+ def negotiator(request): pass
+ config.set_locale_negotiator(negotiator)
+ self.assertEqual(config.registry.getUtility(ILocaleNegotiator),
+ negotiator)
+
+ def test_set_locale_negotiator_dottedname(self):
+ from pyramid.interfaces import ILocaleNegotiator
+ config = self._makeOne(autocommit=True)
+ config.set_locale_negotiator(
+ 'pyramid.tests.test_config.dummyfactory')
+ self.assertEqual(config.registry.getUtility(ILocaleNegotiator),
+ dummyfactory)
+
+ def test_set_request_factory(self):
+ from pyramid.interfaces import IRequestFactory
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ config.set_request_factory(factory)
+ self.assertEqual(config.registry.getUtility(IRequestFactory), factory)
+
+ def test_set_request_factory_dottedname(self):
+ from pyramid.interfaces import IRequestFactory
+ config = self._makeOne(autocommit=True)
+ config.set_request_factory(
+ 'pyramid.tests.test_config.dummyfactory')
+ self.assertEqual(config.registry.getUtility(IRequestFactory),
+ dummyfactory)
+
+ def test_set_renderer_globals_factory(self):
+ from pyramid.interfaces import IRendererGlobalsFactory
+ config = self._makeOne(autocommit=True)
+ factory = object()
+ config.set_renderer_globals_factory(factory)
+ self.assertEqual(config.registry.getUtility(IRendererGlobalsFactory),
+ factory)
+
+ def test_set_renderer_globals_factory_dottedname(self):
+ from pyramid.interfaces import IRendererGlobalsFactory
+ config = self._makeOne(autocommit=True)
+ config.set_renderer_globals_factory(
+ 'pyramid.tests.test_config.dummyfactory')
+ self.assertEqual(config.registry.getUtility(IRendererGlobalsFactory),
+ dummyfactory)
+
+ def test_set_default_permission(self):
+ from pyramid.interfaces import IDefaultPermission
+ config = self._makeOne(autocommit=True)
+ config.set_default_permission('view')
+ self.assertEqual(config.registry.getUtility(IDefaultPermission),
+ 'view')
+
+ def test_set_session_factory(self):
+ from pyramid.interfaces import ISessionFactory
+ config = self._makeOne(autocommit=True)
+ config.set_session_factory('factory')
+ self.assertEqual(config.registry.getUtility(ISessionFactory),
+ 'factory')
+
+ def test_add_translation_dirs_missing_dir(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError,
+ config.add_translation_dirs,
+ '/wont/exist/on/my/system')
+
+ def test_add_translation_dirs_resource_spec(self):
+ import os
+ from pyramid.interfaces import ITranslationDirectories
+ config = self._makeOne(autocommit=True)
+ config.add_translation_dirs('pyramid.tests.localeapp:locale')
+ here = os.path.dirname(__file__)
+ locale = os.path.join(here, 'localeapp', 'locale')
+ self.assertEqual(config.registry.getUtility(ITranslationDirectories),
+ [locale])
+
+ def test_add_translation_dirs_registers_chameleon_translate(self):
+ from pyramid.interfaces import IChameleonTranslate
+ from pyramid.threadlocal import manager
+ request = DummyRequest()
+ config = self._makeOne(autocommit=True)
+ manager.push({'request':request, 'registry':config.registry})
+ try:
+ config.add_translation_dirs('pyramid.tests.localeapp:locale')
+ translate = config.registry.getUtility(IChameleonTranslate)
+ self.assertEqual(translate('Approve'), u'Approve')
+ finally:
+ manager.pop()
+
+ def test_add_translation_dirs_abspath(self):
+ import os
+ from pyramid.interfaces import ITranslationDirectories
+ config = self._makeOne(autocommit=True)
+ here = os.path.dirname(__file__)
+ locale = os.path.join(here, 'localeapp', 'locale')
+ config.add_translation_dirs(locale)
+ self.assertEqual(config.registry.getUtility(ITranslationDirectories),
+ [locale])
+
+ def test_derive_view_function(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ result = config.derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_dottedname(self):
+ config = self._makeOne()
+ result = config.derive_view(
+ 'pyramid.tests.test_config.dummy_view')
+ self.failIf(result is dummy_view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_with_renderer(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ class moo(object):
+ def __init__(self, *arg, **kw):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'moo'
+ config.add_renderer('moo', moo)
+ result = config.derive_view(view, renderer='moo')
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'moo')
+
+ def test_derive_view_with_default_renderer_no_explicit_renderer(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ class moo(object):
+ def __init__(self, *arg, **kw):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'moo'
+ config.add_renderer(None, moo)
+ result = config.derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'moo')
+
+ def test_derive_view_with_default_renderer_with_explicit_renderer(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne(autocommit=True)
+ class moo(object): pass
+ class foo(object):
+ def __init__(self, *arg, **kw):
+ pass
+ def __call__(self, *arg, **kw):
+ return 'foo'
+ config.add_renderer(None, moo)
+ config.add_renderer('foo', foo)
+ result = config.derive_view(view, renderer='foo')
+ self.failIf(result is view)
+ self.assertEqual(result(None, None).body, 'foo')
+
+ def test_derive_view_class_without_attr(self):
+ class View(object):
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config.derive_view(View)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test_derive_view_class_with_attr(self):
+ class View(object):
+ def __init__(self, request):
+ pass
+ def another(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config.derive_view(View, attr='another')
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(view(None, None), 'OK')
+
+ def test__derive_view_as_function_requestonly(self):
+ def view(request):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_newstyle_class_context_and_request(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_newstyle_class_requestonly(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_oldstyle_class_context_and_request(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_instance_context_and_request(self):
+ class View:
+ def __call__(self, context, request):
+ return 'OK'
+ view = View()
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failUnless(result is view)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_as_instance_requestonly(self):
+ class View:
+ def __call__(self, request):
+ return 'OK'
+ view = View()
+ config = self._makeOne()
+ result = config._derive_view(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.failUnless('instance' in result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__derive_view_with_debug_authorization_no_authpol(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger(config)
+ result = config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed "
+ "(no authorization policy in use)")
+
+ def test__derive_view_with_debug_authorization_no_permission(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ self._registerSecurityPolicy(config, True)
+ logger = self._registerLogger(config)
+ result = config._derive_view(view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): Allowed ("
+ "no permission registered)")
+
+ def test__derive_view_debug_auth_permission_authpol_permitted(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config, debug_authorization=True,
+ reload_templates=True)
+ logger = self._registerLogger(config)
+ self._registerSecurityPolicy(config, True)
+ result = config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__, view)
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): True")
+
+ def test__derive_view_debug_auth_permission_authpol_denied(self):
+ from pyramid.exceptions import Forbidden
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger(config)
+ self._registerSecurityPolicy(config, False)
+ result = config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result.__call_permissive__, view)
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertRaises(Forbidden, result, None, request)
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False")
+
+ def test__derive_view_debug_auth_permission_authpol_denied2(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ self._registerLogger(config)
+ self._registerSecurityPolicy(config, False)
+ result = config._derive_view(view, permission='view')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ permitted = result.__permitted__(None, None)
+ self.assertEqual(permitted, False)
+
+ def test__derive_view_debug_auth_permission_authpol_overridden(self):
+ view = lambda *arg: 'OK'
+ config = self._makeOne()
+ self._registerSettings(config,
+ debug_authorization=True, reload_templates=True)
+ logger = self._registerLogger(config)
+ self._registerSecurityPolicy(config, False)
+ result = config._derive_view(view,
+ permission='__no_permission_required__')
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.failIf(hasattr(result, '__call_permissive__'))
+ request = self._makeRequest(config)
+ request.view_name = 'view_name'
+ request.url = 'url'
+ self.assertEqual(result(None, request), 'OK')
+ self.assertEqual(len(logger.messages), 1)
+ self.assertEqual(logger.messages[0],
+ "debug_authorization of url url (view name "
+ "'view_name' against context None): False")
+
+ def test__derive_view_with_predicates_all(self):
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ config = self._makeOne()
+ result = config._derive_view(view, predicates=[predicate1, predicate2])
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ next = result(None, None)
+ self.assertEqual(next, 'OK')
+ self.assertEqual(predicates, [True, True])
+
+ def test__derive_view_with_predicates_checker(self):
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return True
+ config = self._makeOne()
+ result = config._derive_view(view, predicates=[predicate1, predicate2])
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ next = result.__predicated__(None, None)
+ self.assertEqual(next, True)
+ self.assertEqual(predicates, [True, True])
+
+ def test__derive_view_with_predicates_notall(self):
+ from pyramid.exceptions import NotFound
+ view = lambda *arg: 'OK'
+ predicates = []
+ def predicate1(context, request):
+ predicates.append(True)
+ return True
+ def predicate2(context, request):
+ predicates.append(True)
+ return False
+ config = self._makeOne()
+ result = config._derive_view(view, predicates=[predicate1, predicate2])
+ request = self._makeRequest(config)
+ request.method = 'POST'
+ self.assertRaises(NotFound, result, None, None)
+ self.assertEqual(predicates, [True, True])
+
+ def test__derive_view_with_wrapper_viewname(self):
+ from webob import Response
+ from pyramid.interfaces import IView
+ from pyramid.interfaces import IViewClassifier
+ inner_response = Response('OK')
+ def inner_view(context, request):
+ return inner_response
+ def outer_view(context, request):
+ self.assertEqual(request.wrapped_response, inner_response)
+ self.assertEqual(request.wrapped_body, inner_response.body)
+ self.assertEqual(request.wrapped_view, inner_view)
+ return Response('outer ' + request.wrapped_body)
+ config = self._makeOne()
+ config.registry.registerAdapter(
+ outer_view, (IViewClassifier, None, None), IView, 'owrap')
+ result = config._derive_view(inner_view, viewname='inner',
+ wrapper_viewname='owrap')
+ self.failIf(result is inner_view)
+ self.assertEqual(inner_view.__module__, result.__module__)
+ self.assertEqual(inner_view.__doc__, result.__doc__)
+ request = self._makeRequest(config)
+ request.registry = config.registry
+ response = result(None, request)
+ self.assertEqual(response.body, 'outer OK')
+
+ def test__derive_view_with_wrapper_viewname_notfound(self):
+ from webob import Response
+ inner_response = Response('OK')
+ def inner_view(context, request):
+ return inner_response
+ config = self._makeOne()
+ request = self._makeRequest(config)
+ request.registry = config.registry
+ wrapped = config._derive_view(
+ inner_view, viewname='inner', wrapper_viewname='owrap')
+ self.assertRaises(ValueError, wrapped, None, request)
+
+ def test_override_resource_samename(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_resource,'a', 'a')
+
+ def test_override_resource_directory_with_file(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_resource,
+ 'a:foo/', 'a:foo.pt')
+
+ def test_override_resource_file_with_directory(self):
+ from pyramid.exceptions import ConfigurationError
+ config = self._makeOne()
+ self.assertRaises(ConfigurationError, config.override_resource,
+ 'a:foo.pt', 'a:foo/')
+
+ def test_override_resource_success(self):
+ config = self._makeOne(autocommit=True)
+ override = DummyUnderOverride()
+ config.override_resource(
+ 'pyramid.tests.fixtureapp:templates/foo.pt',
+ 'pyramid.tests.fixtureapp.subpackage:templates/bar.pt',
+ _override=override)
+ from pyramid.tests import fixtureapp
+ from pyramid.tests.fixtureapp import subpackage
+ self.assertEqual(override.package, fixtureapp)
+ self.assertEqual(override.path, 'templates/foo.pt')
+ self.assertEqual(override.override_package, subpackage)
+ self.assertEqual(override.override_prefix, 'templates/bar.pt')
+
+ def test_add_renderer(self):
+ from pyramid.interfaces import IRendererFactory
+ config = self._makeOne(autocommit=True)
+ renderer = object()
+ config.add_renderer('name', renderer)
+ self.assertEqual(config.registry.getUtility(IRendererFactory, 'name'),
+ renderer)
+
+ def test_add_renderer_dottedname_factory(self):
+ from pyramid.interfaces import IRendererFactory
+ config = self._makeOne(autocommit=True)
+ import pyramid.tests
+ config.add_renderer('name', 'pyramid.tests')
+ self.assertEqual(config.registry.getUtility(IRendererFactory, 'name'),
+ pyramid.tests)
+
+ def test_scan_integration(self):
+ import os
+ from zope.interface import alsoProvides
+ from pyramid.interfaces import IRequest
+ from pyramid.view import render_view_to_response
+ import pyramid.tests.grokkedapp as package
+ config = self._makeOne(autocommit=True)
+ config.scan(package)
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ alsoProvides(req, IRequest)
+ req.registry = config.registry
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked_post')
+
+ result= render_view_to_response(ctx, req, 'grokked_class')
+ self.assertEqual(result, 'grokked_class')
+
+ result= render_view_to_response(ctx, req, 'grokked_instance')
+ self.assertEqual(result, 'grokked_instance')
+
+ result= render_view_to_response(ctx, req, 'oldstyle_grokked_class')
+ self.assertEqual(result, 'oldstyle_grokked_class')
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked')
+
+ req.method = 'POST'
+ result = render_view_to_response(ctx, req, 'another')
+ self.assertEqual(result, 'another_grokked_post')
+
+ result= render_view_to_response(ctx, req, 'another_grokked_class')
+ self.assertEqual(result, 'another_grokked_class')
+
+ result= render_view_to_response(ctx, req, 'another_grokked_instance')
+ self.assertEqual(result, 'another_grokked_instance')
+
+ result= render_view_to_response(ctx, req,
+ 'another_oldstyle_grokked_class')
+ self.assertEqual(result, 'another_oldstyle_grokked_class')
+
+ result = render_view_to_response(ctx, req, 'stacked1')
+ self.assertEqual(result, 'stacked')
+
+ result = render_view_to_response(ctx, req, 'stacked2')
+ self.assertEqual(result, 'stacked')
+
+ result = render_view_to_response(ctx, req, 'another_stacked1')
+ self.assertEqual(result, 'another_stacked')
+
+ result = render_view_to_response(ctx, req, 'another_stacked2')
+ self.assertEqual(result, 'another_stacked')
+
+ result = render_view_to_response(ctx, req, 'stacked_class1')
+ self.assertEqual(result, 'stacked_class')
+
+ result = render_view_to_response(ctx, req, 'stacked_class2')
+ self.assertEqual(result, 'stacked_class')
+
+ result = render_view_to_response(ctx, req, 'another_stacked_class1')
+ self.assertEqual(result, 'another_stacked_class')
+
+ result = render_view_to_response(ctx, req, 'another_stacked_class2')
+ self.assertEqual(result, 'another_stacked_class')
+
+ if not os.name.startswith('java'):
+ # on Jython, a class without an __init__ apparently accepts
+ # any number of arguments without raising a TypeError.
+
+ self.assertRaises(TypeError,
+ render_view_to_response, ctx, req, 'basemethod')
+
+ result = render_view_to_response(ctx, req, 'method1')
+ self.assertEqual(result, 'method1')
+
+ result = render_view_to_response(ctx, req, 'method2')
+ self.assertEqual(result, 'method2')
+
+ result = render_view_to_response(ctx, req, 'stacked_method1')
+ self.assertEqual(result, 'stacked_method')
+
+ result = render_view_to_response(ctx, req, 'stacked_method2')
+ self.assertEqual(result, 'stacked_method')
+
+ result = render_view_to_response(ctx, req, 'subpackage_init')
+ self.assertEqual(result, 'subpackage_init')
+
+ result = render_view_to_response(ctx, req, 'subpackage_notinit')
+ self.assertEqual(result, 'subpackage_notinit')
+
+ result = render_view_to_response(ctx, req, 'subsubpackage_init')
+ self.assertEqual(result, 'subsubpackage_init')
+
+ result = render_view_to_response(ctx, req, 'pod_notinit')
+ self.assertEqual(result, None)
+
+ def test_scan_integration_dottedname_package(self):
+ from zope.interface import alsoProvides
+ from pyramid.interfaces import IRequest
+ from pyramid.view import render_view_to_response
+ config = self._makeOne(autocommit=True)
+ config.scan('pyramid.tests.grokkedapp')
+
+ ctx = DummyContext()
+ req = DummyRequest()
+ alsoProvides(req, IRequest)
+ req.registry = config.registry
+
+ req.method = 'GET'
+ result = render_view_to_response(ctx, req, '')
+ self.assertEqual(result, 'grokked')
+
+ def test_testing_securitypolicy(self):
+ from pyramid.testing import DummySecurityPolicy
+ config = self._makeOne(autocommit=True)
+ config.testing_securitypolicy('user', ('group1', 'group2'),
+ permissive=False)
+ from pyramid.interfaces import IAuthenticationPolicy
+ from pyramid.interfaces import IAuthorizationPolicy
+ ut = config.registry.getUtility(IAuthenticationPolicy)
+ self.failUnless(isinstance(ut, DummySecurityPolicy))
+ ut = config.registry.getUtility(IAuthorizationPolicy)
+ self.assertEqual(ut.userid, 'user')
+ self.assertEqual(ut.groupids, ('group1', 'group2'))
+ self.assertEqual(ut.permissive, False)
+
+ def test_testing_models(self):
+ from pyramid.traversal import find_model
+ from pyramid.interfaces import ITraverser
+ ob1 = object()
+ ob2 = object()
+ models = {'/ob1':ob1, '/ob2':ob2}
+ config = self._makeOne(autocommit=True)
+ config.testing_models(models)
+ adapter = config.registry.getAdapter(None, ITraverser)
+ result = adapter({'PATH_INFO':'/ob1'})
+ self.assertEqual(result['context'], ob1)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (u'ob1',))
+ self.assertEqual(result['virtual_root'], ob1)
+ self.assertEqual(result['virtual_root_path'], ())
+ result = adapter({'PATH_INFO':'/ob2'})
+ self.assertEqual(result['context'], ob2)
+ self.assertEqual(result['view_name'], '')
+ self.assertEqual(result['subpath'], ())
+ self.assertEqual(result['traversed'], (u'ob2',))
+ self.assertEqual(result['virtual_root'], ob2)
+ self.assertEqual(result['virtual_root_path'], ())
+ self.assertRaises(KeyError, adapter, {'PATH_INFO':'/ob3'})
+ try:
+ config.begin()
+ self.assertEqual(find_model(None, '/ob1'), ob1)
+ finally:
+ config.end()
+
+ def test_testing_add_subscriber_single(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber(IDummy)
+ event = DummyEvent()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_testing_add_subscriber_dottedname(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber(
+ 'pyramid.tests.test_config.IDummy')
+ event = DummyEvent()
+ config.registry.notify(event)
+ self.assertEqual(len(L), 1)
+ self.assertEqual(L[0], event)
+ config.registry.notify(object())
+ self.assertEqual(len(L), 1)
+
+ def test_testing_add_subscriber_multiple(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber((Interface, IDummy))
+ event = DummyEvent()
+ event.object = 'foo'
+ # the below is the equivalent of z.c.event.objectEventNotify(event)
+ config.registry.subscribers((event.object, event), None)
+ self.assertEqual(len(L), 2)
+ self.assertEqual(L[0], 'foo')
+ self.assertEqual(L[1], event)
+
+ def test_testing_add_subscriber_defaults(self):
+ config = self._makeOne(autocommit=True)
+ L = config.testing_add_subscriber()
+ event = object()
+ config.registry.notify(event)
+ self.assertEqual(L[-1], event)
+ event2 = object()
+ config.registry.notify(event2)
+ self.assertEqual(L[-1], event2)
+
+ def test_hook_zca(self):
+ from pyramid.threadlocal import get_current_registry
+ gsm = DummyGetSiteManager()
+ config = self._makeOne()
+ config.hook_zca(getSiteManager=gsm)
+ self.assertEqual(gsm.hook, get_current_registry)
+
+ def test_unhook_zca(self):
+ gsm = DummyGetSiteManager()
+ config = self._makeOne()
+ config.unhook_zca(getSiteManager=gsm)
+ self.assertEqual(gsm.unhooked, True)
+
+ def test_testing_add_renderer(self):
+ config = self._makeOne(autocommit=True)
+ renderer = config.testing_add_renderer('templates/foo.pt')
+ from pyramid.testing import DummyTemplateRenderer
+ self.failUnless(isinstance(renderer, DummyTemplateRenderer))
+ from pyramid.renderers import render_to_response
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ render_to_response(
+ 'templates/foo.pt', {'foo':1, 'bar':2}, request=request)
+ renderer.assert_(foo=1)
+ renderer.assert_(bar=2)
+ renderer.assert_(request=request)
+
+ def test_testing_add_renderer_explicitrenderer(self):
+ config = self._makeOne(autocommit=True)
+ class E(Exception): pass
+ def renderer(kw, system):
+ self.assertEqual(kw, {'foo':1, 'bar':2})
+ raise E
+ renderer = config.testing_add_renderer('templates/foo.pt', renderer)
+ from pyramid.renderers import render_to_response
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ try:
+ render_to_response(
+ 'templates/foo.pt', {'foo':1, 'bar':2}, request=request)
+ except E:
+ pass
+ else: # pragma: no cover
+ raise AssertionError
+
+ def test_testing_add_template(self):
+ config = self._makeOne(autocommit=True)
+ renderer = config.testing_add_template('templates/foo.pt')
+ from pyramid.testing import DummyTemplateRenderer
+ self.failUnless(isinstance(renderer, DummyTemplateRenderer))
+ from pyramid.renderers import render_to_response
+ # must provide request to pass in registry (this is a functest)
+ request = DummyRequest()
+ request.registry = config.registry
+ render_to_response('templates/foo.pt', dict(foo=1, bar=2),
+ request=request)
+ renderer.assert_(foo=1)
+ renderer.assert_(bar=2)
+ renderer.assert_(request=request)
+
+ def test_commit_conflict_simple(self):
+ from zope.configuration.config import ConfigurationConflictError
+ config = self._makeOne()
+ def view1(request): pass
+ def view2(request): pass
+ config.add_view(view1)
+ config.add_view(view2)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_commit_conflict_resolved_with_include(self):
+ config = self._makeOne()
+ def view1(request): pass
+ def view2(request): pass
+ def includeme(config):
+ config.add_view(view2)
+ config.add_view(view1)
+ config.include(includeme)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view1')
+
+ def test_commit_conflict_with_two_includes(self):
+ from zope.configuration.config import ConfigurationConflictError
+ config = self._makeOne()
+ def view1(request): pass
+ def view2(request): pass
+ def includeme1(config):
+ config.add_view(view1)
+ def includeme2(config):
+ config.add_view(view2)
+ config.include(includeme1)
+ config.include(includeme2)
+ self.assertRaises(ConfigurationConflictError, config.commit)
+
+ def test_commit_conflict_resolved_with_two_includes_and_local(self):
+ config = self._makeOne()
+ def view1(request): pass
+ def view2(request): pass
+ def view3(request): pass
+ def includeme1(config):
+ config.add_view(view1)
+ def includeme2(config):
+ config.add_view(view2)
+ config.include(includeme1)
+ config.include(includeme2)
+ config.add_view(view3)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view3')
+
+ def test_autocommit_no_conflicts(self):
+ config = self._makeOne(autocommit=True)
+ def view1(request): pass
+ def view2(request): pass
+ def view3(request): pass
+ config.add_view(view1)
+ config.add_view(view2)
+ config.add_view(view3)
+ config.commit()
+ registeredview = self._getViewCallable(config)
+ self.assertEqual(registeredview.__name__, 'view3')
+
+class Test__map_view(unittest.TestCase):
+ def setUp(self):
+ from pyramid.registry import Registry
+ self.registry = Registry()
+ testing.setUp(registry=self.registry)
+
+ def tearDown(self):
+ del self.registry
+ testing.tearDown()
+
+ def _registerRenderer(self, typ='.txt'):
+ from pyramid.interfaces import IRendererFactory
+ from pyramid.interfaces import ITemplateRenderer
+ from zope.interface import implements
+ class Renderer:
+ implements(ITemplateRenderer)
+ spec = 'abc' + typ
+ def __init__(self, path):
+ self.__class__.path = path
+ def __call__(self, *arg):
+ return 'Hello!'
+ self.registry.registerUtility(Renderer, IRendererFactory, name=typ)
+ return Renderer
+
+ def _makeRequest(self):
+ request = DummyRequest()
+ request.registry = self.registry
+ return request
+
+ def _callFUT(self, view, **kw):
+ from pyramid.config import _map_view
+ return _map_view(view, self.registry, **kw)
+
+ def test__map_view_as_function_context_and_request(self):
+ def view(context, request):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failUnless(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_function_with_attr(self):
+ def view(context, request):
+ """ """
+ result = self._callFUT(view, attr='__name__')
+ self.failIf(result is view)
+ self.assertRaises(TypeError, result, None, None)
+
+ def test__map_view_as_function_with_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ view = lambda *arg: 'OK'
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='__name__', renderer=info)
+ self.failIf(result is view)
+ self.assertRaises(TypeError, result, None, None)
+
+ def test__map_view_as_function_requestonly(self):
+ def view(request):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_function_requestonly_with_attr(self):
+ def view(request):
+ """ """
+ result = self._callFUT(view, attr='__name__')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertRaises(TypeError, result, None, None)
+
+ def test__map_view_as_newstyle_class_context_and_request(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_newstyle_class_context_and_request_with_attr(self):
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return 'OK'
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_newstyle_class_context_and_request_attr_and_renderer(
+ self):
+ renderer = self._registerRenderer()
+ class view(object):
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_as_newstyle_class_requestonly(self):
+ class view(object):
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_newstyle_class_requestonly_with_attr(self):
+ class view(object):
+ def __init__(self, request):
+ pass
+ def index(self):
+ return 'OK'
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_newstyle_class_requestonly_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ class view(object):
+ def __init__(self, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_as_oldstyle_class_context_and_request(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_oldstyle_class_context_and_request_with_attr(self):
+ class view:
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return 'OK'
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_oldstyle_cls_context_request_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ class view:
+ def __init__(self, context, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_as_oldstyle_class_requestonly(self):
+ class view:
+ def __init__(self, request):
+ pass
+ def __call__(self):
+ return 'OK'
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_oldstyle_class_requestonly_with_attr(self):
+ class view:
+ def __init__(self, request):
+ pass
+ def index(self):
+ return 'OK'
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_oldstyle_class_requestonly_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ class view:
+ def __init__(self, request):
+ pass
+ def index(self):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.assertEqual(view.__name__, result.__name__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_as_instance_context_and_request(self):
+ class View:
+ def __call__(self, context, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(view)
+ self.failUnless(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_instance_context_and_request_and_attr(self):
+ class View:
+ def index(self, context, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_instance_context_and_request_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ class View:
+ def index(self, context, request):
+ return {'a':'1'}
+ view = View()
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_as_instance_requestonly(self):
+ class View:
+ def __call__(self, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(view)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.failUnless('instance' in result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_instance_requestonly_with_attr(self):
+ class View:
+ def index(self, request):
+ return 'OK'
+ view = View()
+ result = self._callFUT(view, attr='index')
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.failUnless('instance' in result.__name__)
+ self.assertEqual(result(None, None), 'OK')
+
+ def test__map_view_as_instance_requestonly_with_attr_and_renderer(self):
+ renderer = self._registerRenderer()
+ class View:
+ def index(self, request):
+ return {'a':'1'}
+ view = View()
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, attr='index', renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ self.failUnless('instance' in result.__name__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_rendereronly(self):
+ renderer = self._registerRenderer()
+ def view(context, request):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+ def test__map_view_with_registry(self):
+ renderer = self._registerRenderer()
+ def view(context, request):
+ return {'a':'1'}
+ info = {'name':renderer.spec, 'package':None}
+ result = self._callFUT(view, renderer=info)
+ self.failIf(result is view)
+ self.assertEqual(view.__module__, result.__module__)
+ self.assertEqual(view.__doc__, result.__doc__)
+ request = self._makeRequest()
+ self.assertEqual(result(None, request).body, 'Hello!')
+
+class Test_decorate_view(unittest.TestCase):
+ def _callFUT(self, wrapped, original):
+ from pyramid.config import decorate_view
+ return decorate_view(wrapped, original)
+
+ def test_it_same(self):
+ def view(context, request):
+ """ """
+ result = self._callFUT(view, view)
+ self.assertEqual(result, False)
+
+ def test_it_different(self):
+ class DummyView1:
+ """ 1 """
+ __name__ = '1'
+ __module__ = '1'
+ def __call__(self, context, request):
+ """ """
+ def __call_permissive__(self, context, reuqest):
+ """ """
+ def __predicated__(self, context, reuqest):
+ """ """
+ def __permitted__(self, context, request):
+ """ """
+ class DummyView2:
+ """ 2 """
+ __name__ = '2'
+ __module__ = '2'
+ def __call__(self, context, request):
+ """ """
+ def __call_permissive__(self, context, reuqest):
+ """ """
+ def __predicated__(self, context, reuqest):
+ """ """
+ def __permitted__(self, context, request):
+ """ """
+ view1 = DummyView1()
+ view2 = DummyView2()
+ result = self._callFUT(view1, view2)
+ self.assertEqual(result, True)
+ self.failUnless(view1.__doc__ is view2.__doc__)
+ self.failUnless(view1.__module__ is view2.__module__)
+ self.failUnless(view1.__name__ is view2.__name__)
+ self.failUnless(view1.__call_permissive__.im_func is
+ view2.__call_permissive__.im_func)
+ self.failUnless(view1.__permitted__.im_func is
+ view2.__permitted__.im_func)
+ self.failUnless(view1.__predicated__.im_func is
+ view2.__predicated__.im_func)
+
+class Test__make_predicates(unittest.TestCase):
+ def _callFUT(self, **kw):
+ from pyramid.config import _make_predicates
+ return _make_predicates(**kw)
+
+ def test_ordering_xhr_and_request_method_trump_only_containment(self):
+ order1, _, _ = self._callFUT(xhr=True, request_method='GET')
+ order2, _, _ = self._callFUT(containment=True)
+ self.failUnless(order1 < order2)
+
+ def test_ordering_number_of_predicates(self):
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ custom=('a',)
+ )
+ order2, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ custom=('a',)
+ )
+ order3, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ containment='containment',
+ request_type='request_type',
+ )
+ order4, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ containment='containment',
+ )
+ order5, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ accept='accept',
+ )
+ order6, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ header='header',
+ )
+ order7, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ request_param='param',
+ )
+ order8, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ )
+ order9, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ )
+ order10, _, _ = self._callFUT(
+ xhr='xhr',
+ )
+ order11, _, _ = self._callFUT(
+ )
+ self.assertEqual(order1, order2)
+ self.failUnless(order3 > order2)
+ self.failUnless(order4 > order3)
+ self.failUnless(order5 > order4)
+ self.failUnless(order6 > order5)
+ self.failUnless(order7 > order6)
+ self.failUnless(order8 > order7)
+ self.failUnless(order9 > order8)
+ self.failUnless(order10 > order9)
+ self.failUnless(order11 > order10)
+
+ def test_ordering_importance_of_predicates(self):
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ )
+ order2, _, _ = self._callFUT(
+ request_method='request_method',
+ )
+ order3, _, _ = self._callFUT(
+ path_info='path_info',
+ )
+ order4, _, _ = self._callFUT(
+ request_param='param',
+ )
+ order5, _, _ = self._callFUT(
+ header='header',
+ )
+ order6, _, _ = self._callFUT(
+ accept='accept',
+ )
+ order7, _, _ = self._callFUT(
+ containment='containment',
+ )
+ order8, _, _ = self._callFUT(
+ request_type='request_type',
+ )
+ order9, _, _ = self._callFUT(
+ custom=('a',),
+ )
+ self.failUnless(order1 > order2)
+ self.failUnless(order2 > order3)
+ self.failUnless(order3 > order4)
+ self.failUnless(order4 > order5)
+ self.failUnless(order5 > order6)
+ self.failUnless(order6 > order7)
+ self.failUnless(order7 > order8)
+ self.failUnless(order8 > order9)
+
+ def test_ordering_importance_and_number(self):
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ )
+ order2, _, _ = self._callFUT(
+ custom=('a',),
+ )
+ self.failUnless(order1 < order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ )
+ order2, _, _ = self._callFUT(
+ request_method='request_method',
+ custom=('a',),
+ )
+ self.failUnless(order1 > order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ )
+ order2, _, _ = self._callFUT(
+ request_method='request_method',
+ custom=('a',),
+ )
+ self.failUnless(order1 < order2)
+
+ order1, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ path_info='path_info',
+ )
+ order2, _, _ = self._callFUT(
+ xhr='xhr',
+ request_method='request_method',
+ custom=('a',),
+ )
+ self.failUnless(order1 > order2)
+
+ def test_different_custom_predicates_with_same_hash(self):
+ class PredicateWithHash(object):
+ def __hash__(self):
+ return 1
+ a = PredicateWithHash()
+ b = PredicateWithHash()
+ _, _, a_phash = self._callFUT(custom=(a,))
+ _, _, b_phash = self._callFUT(custom=(b,))
+ self.assertEqual(a_phash, b_phash)
+
+ def test_traverse_has_remainder_already(self):
+ order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
+ self.assertEqual(len(predicates), 1)
+ pred = predicates[0]
+ info = {'traverse':'abc'}
+ request = DummyRequest()
+ result = pred(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(info, {'traverse':'abc'})
+
+ def test_traverse_matches(self):
+ order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
+ self.assertEqual(len(predicates), 1)
+ pred = predicates[0]
+ info = {'match':{'a':'a', 'b':'b'}}
+ request = DummyRequest()
+ result = pred(info, request)
+ self.assertEqual(result, True)
+ self.assertEqual(info, {'match':
+ {'a':'a', 'b':'b', 'traverse':('1', 'a', 'b')}})
+
+class TestMultiView(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config import MultiView
+ return MultiView
+
+ def _makeOne(self, name='name'):
+ return self._getTargetClass()(name)
+
+ def test_class_implements_ISecuredView(self):
+ from zope.interface.verify import verifyClass
+ from pyramid.interfaces import ISecuredView
+ verifyClass(ISecuredView, self._getTargetClass())
+
+ def test_instance_implements_ISecuredView(self):
+ from zope.interface.verify import verifyObject
+ from pyramid.interfaces import ISecuredView
+ verifyObject(ISecuredView, self._makeOne())
+
+ def test_add(self):
+ mv = self._makeOne()
+ mv.add('view', 100)
+ self.assertEqual(mv.views, [(100, 'view', None)])
+ mv.add('view2', 99)
+ self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
+ mv.add('view3', 100, 'text/html')
+ self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])
+ mv.add('view4', 99, 'text/html')
+ self.assertEqual(mv.media_views['text/html'],
+ [(99, 'view4', None), (100, 'view3', None)])
+ mv.add('view5', 100, 'text/xml')
+ self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])
+ self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))
+ self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
+ mv.add('view6', 98, 'text/*')
+ self.assertEqual(mv.views, [(98, 'view6', None),
+ (99, 'view2', None),
+ (100, 'view', None)])
+
+ def test_add_with_phash(self):
+ mv = self._makeOne()
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(mv.views, [(100, 'view', 'abc')])
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(mv.views, [(100, 'view', 'abc')])
+ mv.add('view', 100, phash='def')
+ self.assertEqual(mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')])
+ mv.add('view', 100, phash='abc')
+ self.assertEqual(mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')])
+
+ def test_get_views_request_has_no_accept(self):
+ request = DummyRequest()
+ mv = self._makeOne()
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_get_views_no_self_accepts(self):
+ request = DummyRequest()
+ request.accept = True
+ mv = self._makeOne()
+ mv.accepts = []
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_get_views(self):
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html')
+ mv = self._makeOne()
+ mv.accepts = ['text/html']
+ mv.views = [(99, lambda *arg: None)]
+ html_views = [(98, lambda *arg: None)]
+ mv.media_views['text/html'] = html_views
+ self.assertEqual(mv.get_views(request), html_views + mv.views)
+
+ def test_get_views_best_match_returns_None(self):
+ request = DummyRequest()
+ request.accept = DummyAccept(None)
+ mv = self._makeOne()
+ mv.accepts = ['text/html']
+ mv.views = [(99, lambda *arg: None)]
+ self.assertEqual(mv.get_views(request), mv.views)
+
+ def test_match_not_found(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.match, context, request)
+
+ def test_match_predicate_fails(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ view.__predicated__ = lambda *arg: False
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.match, context, request)
+
+ def test_match_predicate_succeeds(self):
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ view.__predicated__ = lambda *arg: True
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ result = mv.match(context, request)
+ self.assertEqual(result, view)
+
+ def test_permitted_no_views(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv.__permitted__, context, request)
+
+ def test_permitted_no_match_with__permitted__(self):
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ mv.views = [(100, view, None)]
+ self.assertEqual(mv.__permitted__(None, None), True)
+
+ def test_permitted(self):
+ mv = self._makeOne()
+ def view(context, request):
+ """ """
+ def permitted(context, request):
+ return False
+ view.__permitted__ = permitted
+ mv.views = [(100, view, None)]
+ context = DummyContext()
+ request = DummyRequest()
+ result = mv.__permitted__(context, request)
+ self.assertEqual(result, False)
+
+ def test__call__not_found(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv, context, request)
+
+ def test___call__intermediate_not_found(self):
+ from pyramid.exceptions import PredicateMismatch
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view1(context, request):
+ raise PredicateMismatch
+ def view2(context, request):
+ return expected_response
+ mv.views = [(100, view1, None), (99, view2, None)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ def view1(context, request):
+ raise NotFound
+ def view2(context, request):
+ """ """
+ mv.views = [(100, view1, None), (99, view2, None)]
+ self.assertRaises(NotFound, mv, context, request)
+
+ def test___call__(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, view, None)]
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call_permissive__not_found(self):
+ from pyramid.exceptions import NotFound
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ self.assertRaises(NotFound, mv, context, request)
+
+ def test___call_permissive_has_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ """ """
+ def permissive(context, request):
+ return expected_response
+ view.__call_permissive__ = permissive
+ mv.views = [(100, view, None)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test___call_permissive_has_no_call_permissive(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.view_name = ''
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, view, None)]
+ response = mv.__call_permissive__(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call__with_accept_match(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.accept = DummyAccept('text/html', 'text/xml')
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, None)]
+ mv.media_views['text/xml'] = [(100, view, None)]
+ mv.accepts = ['text/xml']
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+ def test__call__with_accept_miss(self):
+ mv = self._makeOne()
+ context = DummyContext()
+ request = DummyRequest()
+ request.accept = DummyAccept('text/plain', 'text/html')
+ expected_response = DummyResponse()
+ def view(context, request):
+ return expected_response
+ mv.views = [(100, view, None)]
+ mv.media_views['text/xml'] = [(100, None, None)]
+ mv.accepts = ['text/xml']
+ response = mv(context, request)
+ self.assertEqual(response, expected_response)
+
+
+class TestRequestOnly(unittest.TestCase):
+ def _callFUT(self, arg):
+ from pyramid.config import requestonly
+ return requestonly(arg)
+
+ def test_newstyle_class_no_init(self):
+ class foo(object):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_toomanyargs(self):
+ class foo(object):
+ def __init__(self, context, request):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_onearg_named_request(self):
+ class foo(object):
+ def __init__(self, request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_onearg_named_somethingelse(self):
+ class foo(object):
+ def __init__(self, req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo(object):
+ def __init__(self, context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_newstyle_class_init_defaultargs_firstname_request(self):
+ class foo(object):
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_newstyle_class_init_noargs(self):
+ class foo(object):
+ def __init__():
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_no_init(self):
+ class foo:
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_toomanyargs(self):
+ class foo:
+ def __init__(self, context, request):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_request(self):
+ class foo:
+ def __init__(self, request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_onearg_named_somethingelse(self):
+ class foo:
+ def __init__(self, req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
+ class foo:
+ def __init__(self, context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_oldstyle_class_init_defaultargs_firstname_request(self):
+ class foo:
+ def __init__(self, request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo), True)
+
+ def test_oldstyle_class_init_noargs(self):
+ class foo:
+ def __init__():
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_toomanyargs(self):
+ def foo(context, request):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_onearg_named_request(self):
+ def foo(request):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_onearg_named_somethingelse(self):
+ def foo(req):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_not_request(self):
+ def foo(context, request=None):
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_function_defaultargs_firstname_request(self):
+ def foo(request, foo=1, bar=2):
+ """ """
+ self.assertTrue(self._callFUT(foo))
+
+ def test_function_noargs(self):
+ def foo():
+ """ """
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_toomanyargs(self):
+ class Foo:
+ def __call__(self, context, request):
+ """ """
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_request(self):
+ class Foo:
+ def __call__(self, request):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_onearg_named_somethingelse(self):
+ class Foo:
+ def __call__(self, req):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_not_request(self):
+ class Foo:
+ def __call__(self, context, request=None):
+ """ """
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+ def test_instance_defaultargs_firstname_request(self):
+ class Foo:
+ def __call__(self, request, foo=1, bar=2):
+ """ """
+ foo = Foo()
+ self.assertTrue(self._callFUT(foo), True)
+
+ def test_instance_nocall(self):
+ class Foo: pass
+ foo = Foo()
+ self.assertFalse(self._callFUT(foo))
+
+class Test_isexception(unittest.TestCase):
+ def _callFUT(self, ob):
+ from pyramid.config import isexception
+ return isexception(ob)
+
+ def test_is_exception_instance(self):
+ class E(Exception):
+ pass
+ e = E()
+ self.assertEqual(self._callFUT(e), True)
+
+ def test_is_exception_class(self):
+ class E(Exception):
+ pass
+ self.assertEqual(self._callFUT(E), True)
+
+ def test_is_IException(self):
+ from pyramid.interfaces import IException
+ self.assertEqual(self._callFUT(IException), True)
+
+ def test_is_IException_subinterface(self):
+ from pyramid.interfaces import IException
+ class ISubException(IException):
+ pass
+ self.assertEqual(self._callFUT(ISubException), True)
+
+class TestActionPredicate(unittest.TestCase):
+ def _getTargetClass(self):
+ from pyramid.config import ActionPredicate
+ return ActionPredicate
+
+ def _makeOne(self, action='myaction'):
+ return self._getTargetClass()(action)
+
+ def test_bad_action_regex_string(self):
+ from pyramid.exceptions import ConfigurationError
+ cls = self._getTargetClass()
+ self.assertRaises(ConfigurationError, cls, '[a-z')
+
+ def test_bad_action_regex_None(self):
+ from pyramid.exceptions import ConfigurationError
+ cls = self._getTargetClass()
+ self.assertRaises(ConfigurationError, cls, None)
+
+ def test___call__no_matchdict(self):
+ pred = self._makeOne()
+ request = DummyRequest()
+ self.assertEqual(pred(None, request), False)
+
+ def test___call__no_action_in_matchdict(self):
+ pred = self._makeOne()
+ request = DummyRequest()
+ request.matchdict = {}
+ self.assertEqual(pred(None, request), False)
+
+ def test___call__action_does_not_match(self):
+ pred = self._makeOne()
+ request = DummyRequest()
+ request.matchdict = {'action':'notmyaction'}
+ self.assertEqual(pred(None, request), False)
+
+ def test___call__action_matches(self):
+ pred = self._makeOne()
+ request = DummyRequest()
+ request.matchdict = {'action':'myaction'}
+ self.assertEqual(pred(None, request), True)
+
+ def test___hash__(self):
+ pred1 = self._makeOne()
+ pred2 = self._makeOne()
+ pred3 = self._makeOne(action='notthesame')
+ self.assertEqual(hash(pred1), hash(pred2))
+ self.assertNotEqual(hash(pred1), hash(pred3))
+ self.assertNotEqual(hash(pred2), hash(pred3))
+
+
+
+class DummyRequest:
+ subpath = ()
+ matchdict = None
+ def __init__(self):
+ self.environ = {'PATH_INFO':'/static'}
+ self.params = {}
+ self.cookies = {}
+ def copy(self):
+ return self
+ def get_response(self, app):
+ return app
+
+class DummyContext:
+ pass
+
+class DummyLock:
+ def acquire(self):
+ self.acquired = True
+
+ def release(self):
+ self.released = True
+
+class DummyPackage:
+ def __init__(self, name):
+ self.__name__ = name
+
+class DummyOverrides:
+ def __init__(self, package):
+ self.package = package
+ self.inserted = []
+
+ def insert(self, path, package, prefix):
+ self.inserted.append((path, package, prefix))
+
+class DummyUnderOverride:
+ def __call__(self, package, path, override_package, override_prefix,
+ _info=u''):
+ self.package = package
+ self.path = path
+ self.override_package = override_package
+ self.override_prefix = override_prefix
+
+from zope.interface import Interface
+class IDummy(Interface):
+ pass
+
+class IOther(Interface):
+ pass
+
+class DummyResponse:
+ status = '200 OK'
+ headerlist = ()
+ app_iter = ()
+ body = ''
+
+class DummyLogger:
+ def __init__(self):
+ self.messages = []
+ def info(self, msg):
+ self.messages.append(msg)
+ warn = info
+ debug = info
+
+class DummySecurityPolicy:
+ def __init__(self, permitted=True):
+ self.permitted = permitted
+
+ def effective_principals(self, request):
+ return []
+
+ def permits(self, context, principals, permission):
+ return self.permitted
+
+class DummyAccept(object):
+ def __init__(self, *matches):
+ self.matches = list(matches)
+
+ def best_match(self, offered):
+ if self.matches:
+ for match in self.matches:
+ if match in offered:
+ self.matches.remove(match)
+ return match
+ def __contains__(self, val):
+ return val in self.matches
+
+from zope.interface import implements
+from pyramid.interfaces import IMultiView
+class DummyMultiView:
+ implements(IMultiView)
+ def __init__(self):
+ self.views = []
+ self.name = 'name'
+ def add(self, view, order, accept=None, phash=None):
+ self.views.append((view, accept, phash))
+ def __call__(self, context, request):
+ return 'OK1'
+ def __permitted__(self, context, request):
+ """ """
+
+class DummyGetSiteManager(object):
+ def sethook(self, hook):
+ self.hook = hook
+ def reset(self):
+ self.unhooked = True
+
+class DummyThreadLocalManager(object):
+ pushed = None
+ popped = False
+ def push(self, d):
+ self.pushed = d
+ def pop(self):
+ self.popped = True
+
+class IFactory(Interface):
+ pass
+
+class DummyFactory(object):
+ implements(IFactory)
+ def __call__(self):
+ """ """
+
+class DummyEvent:
+ implements(IDummy)
+
+class DummyStaticURLInfo:
+ def __init__(self):
+ self.added = []
+
+ def add(self, name, spec, **kw):
+ self.added.append((name, spec, kw))
+
+def dummy_view(request):
+ return 'OK'
+
+def dummyfactory(request):
+ """ """
+
+class DummyHandler(object): # pragma: no cover
+ def __init__(self, request):
+ self.request = request
+
+ def action1(self):
+ return 'response 1'
+
+ def action2(self):
+ return 'response 2'
+
+def dummy_include(config):
+ config._action('discrim', None, config.package)
+
diff --git a/pyramid/tests/test_configuration.py b/pyramid/tests/test_configuration.py
index 1e3f74a7e..786c7539b 100644
--- a/pyramid/tests/test_configuration.py
+++ b/pyramid/tests/test_configuration.py
@@ -1,4641 +1,21 @@
import unittest
-from pyramid import testing
-
-try:
- import __pypy__
-except:
- __pypy__ = None
-
-class ConfigTests(unittest.TestCase):
- def _makeOne(self, *arg, **kw):
- from pyramid.configuration import Config
- return Config(*arg, **kw)
-
- def _registerRenderer(self, config, name='.txt'):
- from pyramid.interfaces import IRendererFactory
- from pyramid.interfaces import ITemplateRenderer
- from zope.interface import implements
- class Renderer:
- implements(ITemplateRenderer)
- def __init__(self, info):
- self.__class__.info = info
- def __call__(self, *arg):
- return 'Hello!'
- config.registry.registerUtility(Renderer, IRendererFactory, name=name)
- return Renderer
-
- def _getViewCallable(self, config, ctx_iface=None, request_iface=None,
- name='', exception_view=False):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- if exception_view:
- classifier = IExceptionViewClassifier
- else:
- classifier = IViewClassifier
- if ctx_iface is None:
- ctx_iface = Interface
- if request_iface is None:
- request_iface = IRequest
- return config.registry.adapters.lookup(
- (classifier, request_iface, ctx_iface), IView, name=name,
- default=None)
-
- def _getRouteRequestIface(self, config, name):
- from pyramid.interfaces import IRouteRequest
- iface = config.registry.getUtility(IRouteRequest, name)
- return iface
-
- def _assertNotFound(self, wrapper, *arg):
- from pyramid.exceptions import NotFound
- self.assertRaises(NotFound, wrapper, *arg)
-
- def _registerEventListener(self, config, event_iface=None):
- if event_iface is None: # pragma: no cover
- from zope.interface import Interface
- event_iface = Interface
- L = []
- def subscriber(*event):
- L.extend(event)
- config.registry.registerHandler(subscriber, (event_iface,))
- return L
-
- def _registerLogger(self, config):
- from pyramid.interfaces import IDebugLogger
- logger = DummyLogger()
- config.registry.registerUtility(logger, IDebugLogger)
- return logger
-
- def _makeRequest(self, config):
- request = DummyRequest()
- request.registry = config.registry
- return request
-
- def _registerSecurityPolicy(self, config, permissive):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- policy = DummySecurityPolicy(permissive)
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
-
- def _registerSettings(self, config, **settings):
- config.registry.settings = settings
-
- def test_ctor_no_registry(self):
- import sys
- from pyramid.interfaces import ISettings
- from pyramid.configuration import Config
- from pyramid.interfaces import IRendererFactory
- config = Config()
- this_pkg = sys.modules['pyramid.tests']
- self.failUnless(config.registry.getUtility(ISettings))
- self.assertEqual(config.package, this_pkg)
- self.failUnless(config.registry.getUtility(IRendererFactory, 'json'))
- self.failUnless(config.registry.getUtility(IRendererFactory, 'string'))
- if not __pypy__:
- self.failUnless(config.registry.getUtility(IRendererFactory, '.pt'))
- self.failUnless(config.registry.getUtility(IRendererFactory,'.txt'))
- self.failUnless(config.registry.getUtility(IRendererFactory, '.mak'))
- self.failUnless(config.registry.getUtility(IRendererFactory, '.mako'))
-
- def test_begin(self):
- from pyramid.configuration import Config
- config = Config()
- manager = DummyThreadLocalManager()
- config.manager = manager
- config.begin()
- self.assertEqual(manager.pushed,
- {'registry':config.registry, 'request':None})
- self.assertEqual(manager.popped, False)
-
- def test_begin_with_request(self):
- from pyramid.configuration import Config
- config = Config()
- request = object()
- manager = DummyThreadLocalManager()
- config.manager = manager
- config.begin(request=request)
- self.assertEqual(manager.pushed,
- {'registry':config.registry, 'request':request})
- self.assertEqual(manager.popped, False)
-
- def test_end(self):
- from pyramid.configuration import Config
- config = Config()
- manager = DummyThreadLocalManager()
- config.manager = manager
- config.end()
- self.assertEqual(manager.pushed, None)
- self.assertEqual(manager.popped, True)
-
- def test_ctor_with_package_registry(self):
- import sys
- from pyramid.configuration import Config
- pkg = sys.modules['pyramid']
- config = Config(package=pkg)
- self.assertEqual(config.package, pkg)
-
- def test_ctor_noreg_custom_settings(self):
- from pyramid.interfaces import ISettings
- settings = {'reload_templates':True,
- 'mysetting':True}
- config = self._makeOne(settings=settings)
- settings = config.registry.getUtility(ISettings)
- self.assertEqual(settings['reload_templates'], True)
- self.assertEqual(settings['debug_authorization'], False)
- self.assertEqual(settings['mysetting'], True)
-
- def test_ctor_noreg_debug_logger_None_default(self):
- from pyramid.interfaces import IDebugLogger
- config = self._makeOne()
- logger = config.registry.getUtility(IDebugLogger)
- self.assertEqual(logger.name, 'pyramid.debug')
-
- def test_ctor_noreg_debug_logger_non_None(self):
- from pyramid.interfaces import IDebugLogger
- logger = object()
- config = self._makeOne(debug_logger=logger)
- result = config.registry.getUtility(IDebugLogger)
- self.assertEqual(logger, result)
-
- def test_ctor_authentication_policy(self):
- from pyramid.interfaces import IAuthenticationPolicy
- policy = object()
- config = self._makeOne(authentication_policy=policy)
- result = config.registry.getUtility(IAuthenticationPolicy)
- self.assertEqual(policy, result)
-
- def test_ctor_authorization_policy_only(self):
- from pyramid.exceptions import ConfigurationError
- policy = object()
- self.assertRaises(ConfigurationError,
- self._makeOne, authorization_policy=policy)
-
- def test_ctor_no_root_factory(self):
- from pyramid.interfaces import IRootFactory
- config = self._makeOne()
- self.failUnless(config.registry.getUtility(IRootFactory))
-
- def test_ctor_alternate_renderers(self):
- from pyramid.interfaces import IRendererFactory
- renderer = object()
- config = self._makeOne(renderers=[('yeah', renderer)])
- self.assertEqual(config.registry.getUtility(IRendererFactory, 'yeah'),
- renderer)
-
- def test_ctor_default_permission(self):
- from pyramid.interfaces import IDefaultPermission
- config = self._makeOne(default_permission='view')
- self.assertEqual(config.registry.getUtility(IDefaultPermission), 'view')
-
- def test_ctor_session_factory(self):
- from pyramid.interfaces import ISessionFactory
- config = self._makeOne(session_factory='factory')
- self.assertEqual(config.registry.getUtility(ISessionFactory), 'factory')
-
- def test_with_package_module(self):
- from pyramid.tests import test_configuration
- import pyramid.tests
- config = self._makeOne()
- newconfig = config.with_package(test_configuration)
- self.assertEqual(newconfig.package, pyramid.tests)
-
- def test_with_package_package(self):
- import pyramid.tests
- config = self._makeOne()
- newconfig = config.with_package(pyramid.tests)
- self.assertEqual(newconfig.package, pyramid.tests)
-
- def test_maybe_dotted_string_success(self):
- import pyramid.tests
- config = self._makeOne()
- result = config.maybe_dotted('pyramid.tests')
- self.assertEqual(result, pyramid.tests)
-
- def test_maybe_dotted_string_fail(self):
- config = self._makeOne()
- self.assertRaises(ImportError,
- config.maybe_dotted, 'cant.be.found')
-
- def test_maybe_dotted_notstring_success(self):
- import pyramid.tests
- config = self._makeOne()
- result = config.maybe_dotted(pyramid.tests)
- self.assertEqual(result, pyramid.tests)
-
- def test_absolute_resource_spec_already_absolute(self):
- import pyramid.tests
- config = self._makeOne(package=pyramid.tests)
- result = config.absolute_resource_spec('already:absolute')
- self.assertEqual(result, 'already:absolute')
-
- def test_absolute_resource_spec_notastring(self):
- import pyramid.tests
- config = self._makeOne(package=pyramid.tests)
- result = config.absolute_resource_spec(None)
- self.assertEqual(result, None)
-
- def test_absolute_resource_spec_relative(self):
- import pyramid.tests
- config = self._makeOne(package=pyramid.tests)
- result = config.absolute_resource_spec('templates')
- self.assertEqual(result, 'pyramid.tests:templates')
-
- def test_setup_registry_fixed(self):
- class DummyRegistry(object):
- def subscribers(self, events, name):
- self.events = events
- return events
- def registerUtility(self, *arg, **kw):
- pass
- reg = DummyRegistry()
- config = self._makeOne(reg)
- config.add_view = lambda *arg, **kw: False
- config.setup_registry()
- self.assertEqual(reg.has_listeners, True)
- self.assertEqual(reg.notify(1), None)
- self.assertEqual(reg.events, (1,))
-
- def test_setup_registry_registers_default_exceptionresponse_view(self):
- from pyramid.interfaces import IExceptionResponse
- from pyramid.view import default_exceptionresponse_view
- class DummyRegistry(object):
- def registerUtility(self, *arg, **kw):
- pass
- reg = DummyRegistry()
- config = self._makeOne(reg)
- views = []
- config.add_view = lambda *arg, **kw: views.append((arg, kw))
- config.setup_registry()
- self.assertEqual(views[0], ((default_exceptionresponse_view,),
- {'context':IExceptionResponse}))
-
- def test_setup_registry_explicit_notfound_trumps_iexceptionresponse(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.exceptions import NotFound
- from pyramid.registry import Registry
- reg = Registry()
- config = self._makeOne(reg, autocommit=True)
- config.setup_registry() # registers IExceptionResponse default view
- def myview(context, request):
- return 'OK'
- config.add_view(myview, context=NotFound)
- request = self._makeRequest(config)
- view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
- request_iface=IRequest)
- result = view(None, request)
- self.assertEqual(result, 'OK')
-
- def test_setup_registry_custom_settings(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import ISettings
- settings = {'reload_templates':True,
- 'mysetting':True}
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(settings=settings)
- settings = reg.getUtility(ISettings)
- self.assertEqual(settings['reload_templates'], True)
- self.assertEqual(settings['debug_authorization'], False)
- self.assertEqual(settings['mysetting'], True)
-
- def test_setup_registry_debug_logger_None_default(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IDebugLogger
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry()
- logger = reg.getUtility(IDebugLogger)
- self.assertEqual(logger.name, 'pyramid.debug')
-
- def test_setup_registry_debug_logger_non_None(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IDebugLogger
- logger = object()
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(debug_logger=logger)
- result = reg.getUtility(IDebugLogger)
- self.assertEqual(logger, result)
-
- def test_setup_registry_debug_logger_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IDebugLogger
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(debug_logger='pyramid.tests')
- result = reg.getUtility(IDebugLogger)
- import pyramid.tests
- self.assertEqual(result, pyramid.tests)
-
- def test_setup_registry_authentication_policy(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IAuthenticationPolicy
- policy = object()
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(authentication_policy=policy)
- result = reg.getUtility(IAuthenticationPolicy)
- self.assertEqual(policy, result)
-
- def test_setup_registry_authentication_policy_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IAuthenticationPolicy
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(authentication_policy='pyramid.tests')
- result = reg.getUtility(IAuthenticationPolicy)
- import pyramid.tests
- self.assertEqual(result, pyramid.tests)
-
- def test_setup_registry_authorization_policy_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IAuthorizationPolicy
- reg = Registry()
- config = self._makeOne(reg)
- dummy = object()
- config.setup_registry(authentication_policy=dummy,
- authorization_policy='pyramid.tests')
- result = reg.getUtility(IAuthorizationPolicy)
- import pyramid.tests
- self.assertEqual(result, pyramid.tests)
-
- def test_setup_registry_authorization_policy_only(self):
- from pyramid.registry import Registry
- from pyramid.exceptions import ConfigurationError
- policy = object()
- reg = Registry()
- config = self._makeOne(reg)
- config = self.assertRaises(ConfigurationError,
- config.setup_registry,
- authorization_policy=policy)
-
- def test_setup_registry_default_root_factory(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRootFactory
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry()
- self.failUnless(reg.getUtility(IRootFactory))
-
- def test_setup_registry_dottedname_root_factory(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRootFactory
- reg = Registry()
- config = self._makeOne(reg)
- import pyramid.tests
- config.setup_registry(root_factory='pyramid.tests')
- self.assertEqual(reg.getUtility(IRootFactory), pyramid.tests)
-
- def test_setup_registry_locale_negotiator_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import ILocaleNegotiator
- reg = Registry()
- config = self._makeOne(reg)
- import pyramid.tests
- config.setup_registry(locale_negotiator='pyramid.tests')
- utility = reg.getUtility(ILocaleNegotiator)
- self.assertEqual(utility, pyramid.tests)
-
- def test_setup_registry_locale_negotiator(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import ILocaleNegotiator
- reg = Registry()
- config = self._makeOne(reg)
- negotiator = object()
- config.setup_registry(locale_negotiator=negotiator)
- utility = reg.getUtility(ILocaleNegotiator)
- self.assertEqual(utility, negotiator)
-
- def test_setup_registry_request_factory(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRequestFactory
- reg = Registry()
- config = self._makeOne(reg)
- factory = object()
- config.setup_registry(request_factory=factory)
- utility = reg.getUtility(IRequestFactory)
- self.assertEqual(utility, factory)
-
- def test_setup_registry_request_factory_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRequestFactory
- reg = Registry()
- config = self._makeOne(reg)
- import pyramid.tests
- config.setup_registry(request_factory='pyramid.tests')
- utility = reg.getUtility(IRequestFactory)
- self.assertEqual(utility, pyramid.tests)
-
- def test_setup_registry_renderer_globals_factory(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRendererGlobalsFactory
- reg = Registry()
- config = self._makeOne(reg)
- factory = object()
- config.setup_registry(renderer_globals_factory=factory)
- utility = reg.getUtility(IRendererGlobalsFactory)
- self.assertEqual(utility, factory)
-
- def test_setup_registry_renderer_globals_factory_dottedname(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRendererGlobalsFactory
- reg = Registry()
- config = self._makeOne(reg)
- import pyramid.tests
- config.setup_registry(renderer_globals_factory='pyramid.tests')
- utility = reg.getUtility(IRendererGlobalsFactory)
- self.assertEqual(utility, pyramid.tests)
-
- def test_setup_registry_alternate_renderers(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IRendererFactory
- renderer = object()
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(renderers=[('yeah', renderer)])
- self.assertEqual(reg.getUtility(IRendererFactory, 'yeah'),
- renderer)
-
- def test_setup_registry_default_permission(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import IDefaultPermission
- reg = Registry()
- config = self._makeOne(reg)
- config.setup_registry(default_permission='view')
- self.assertEqual(reg.getUtility(IDefaultPermission), 'view')
-
- def test_get_settings_nosettings(self):
- from pyramid.registry import Registry
- reg = Registry()
- config = self._makeOne(reg)
- self.assertEqual(config.get_settings(), None)
-
- def test_get_settings_withsettings(self):
- settings = {'a':1}
- config = self._makeOne()
- config.registry.settings = settings
- self.assertEqual(config.get_settings(), settings)
-
- def test_add_settings_settings_already_registered(self):
- from pyramid.registry import Registry
- reg = Registry()
- config = self._makeOne(reg)
- config._set_settings({'a':1})
- config.add_settings({'b':2})
- settings = reg.settings
- self.assertEqual(settings['a'], 1)
- self.assertEqual(settings['b'], 2)
-
- def test_add_settings_settings_not_yet_registered(self):
- from pyramid.registry import Registry
- from pyramid.interfaces import ISettings
- reg = Registry()
- config = self._makeOne(reg)
- config.add_settings({'a':1})
- settings = reg.getUtility(ISettings)
- self.assertEqual(settings['a'], 1)
-
- def test_add_subscriber_defaults(self):
- from zope.interface import implements
- from zope.interface import Interface
- class IEvent(Interface):
- pass
- class Event:
- implements(IEvent)
- L = []
- def subscriber(event):
- L.append(event)
- config = self._makeOne(autocommit=True)
- config.add_subscriber(subscriber)
- event = Event()
- config.registry.notify(event)
- self.assertEqual(len(L), 1)
- self.assertEqual(L[0], event)
- config.registry.notify(object())
- self.assertEqual(len(L), 2)
-
- def test_add_subscriber_iface_specified(self):
- from zope.interface import implements
- from zope.interface import Interface
- class IEvent(Interface):
- pass
- class Event:
- implements(IEvent)
- L = []
- def subscriber(event):
- L.append(event)
- config = self._makeOne(autocommit=True)
- config.add_subscriber(subscriber, IEvent)
- event = Event()
- config.registry.notify(event)
- self.assertEqual(len(L), 1)
- self.assertEqual(L[0], event)
- config.registry.notify(object())
- self.assertEqual(len(L), 1)
-
- def test_add_subscriber_dottednames(self):
- import pyramid.tests
- from pyramid.interfaces import INewRequest
- config = self._makeOne(autocommit=True)
- config.add_subscriber('pyramid.tests',
- 'pyramid.interfaces.INewRequest')
- handlers = list(config.registry.registeredHandlers())
- self.assertEqual(len(handlers), 1)
- handler = handlers[0]
- self.assertEqual(handler.handler, pyramid.tests)
- self.assertEqual(handler.required, (INewRequest,))
-
- def test_add_object_event_subscriber(self):
- from zope.interface import implements
- from zope.interface import Interface
- class IEvent(Interface):
- pass
- class Event:
- object = 'foo'
- implements(IEvent)
- event = Event()
- L = []
- def subscriber(object, event):
- L.append(event)
- config = self._makeOne(autocommit=True)
- config.add_subscriber(subscriber, (Interface, IEvent))
- config.registry.subscribers((event.object, event), None)
- self.assertEqual(len(L), 1)
- self.assertEqual(L[0], event)
- config.registry.subscribers((event.object, IDummy), None)
- self.assertEqual(len(L), 1)
-
- def test_make_wsgi_app(self):
- from pyramid.router import Router
- from pyramid.interfaces import IApplicationCreated
- manager = DummyThreadLocalManager()
- config = self._makeOne()
- subscriber = self._registerEventListener(config, IApplicationCreated)
- config.manager = manager
- app = config.make_wsgi_app()
- self.assertEqual(app.__class__, Router)
- self.assertEqual(manager.pushed['registry'], config.registry)
- self.assertEqual(manager.pushed['request'], None)
- self.failUnless(manager.popped)
- self.assertEqual(len(subscriber), 1)
- self.failUnless(IApplicationCreated.providedBy(subscriber[0]))
-
- def test_load_zcml_default(self):
- import pyramid.tests.fixtureapp
- config = self._makeOne(package=pyramid.tests.fixtureapp,
- autocommit=True)
- registry = config.load_zcml()
- from pyramid.tests.fixtureapp.models import IFixture
- self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
-
- def test_load_zcml_routesapp(self):
- from pyramid.interfaces import IRoutesMapper
- config = self._makeOne(autocommit=True)
- config.load_zcml('pyramid.tests.routesapp:configure.zcml')
- self.failUnless(config.registry.getUtility(IRoutesMapper))
-
- def test_load_zcml_fixtureapp(self):
- from pyramid.tests.fixtureapp.models import IFixture
- config = self._makeOne(autocommit=True)
- config.load_zcml('pyramid.tests.fixtureapp:configure.zcml')
- self.failUnless(config.registry.queryUtility(IFixture)) # only in c.zcml
-
- def test_load_zcml_as_relative_filename(self):
- import pyramid.tests.fixtureapp
- config = self._makeOne(package=pyramid.tests.fixtureapp,
- autocommit=True)
- registry = config.load_zcml('configure.zcml')
- from pyramid.tests.fixtureapp.models import IFixture
- self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
-
- def test_load_zcml_as_absolute_filename(self):
- import os
- import pyramid.tests.fixtureapp
- config = self._makeOne(package=pyramid.tests.fixtureapp,
- autocommit=True)
- dn = os.path.dirname(pyramid.tests.fixtureapp.__file__)
- c_z = os.path.join(dn, 'configure.zcml')
- registry = config.load_zcml(c_z)
- from pyramid.tests.fixtureapp.models import IFixture
- self.failUnless(registry.queryUtility(IFixture)) # only in c.zcml
-
- def test_load_zcml_lock_and_unlock(self):
- config = self._makeOne(autocommit=True)
- dummylock = DummyLock()
- config.load_zcml(
- 'pyramid.tests.fixtureapp:configure.zcml',
- lock=dummylock)
- self.assertEqual(dummylock.acquired, True)
- self.assertEqual(dummylock.released, True)
-
- def test_include_with_dotted_name(self):
- from pyramid import tests
- config = self._makeOne()
- context_before = config._make_context()
- config._ctx = context_before
- config.include('pyramid.tests.test_configuration.dummy_include')
- context_after = config._ctx
- actions = context_after.actions
- self.assertEqual(len(actions), 1)
- self.assertEqual(
- context_after.actions[0][:3],
- ('discrim', None, tests),
- )
- self.assertEqual(context_after.basepath, None)
- self.assertEqual(context_after.includepath, ())
- self.failUnless(context_after is context_before)
-
- def test_include_with_python_callable(self):
- from pyramid import tests
- config = self._makeOne()
- context_before = config._make_context()
- config._ctx = context_before
- config.include(dummy_include)
- context_after = config._ctx
- actions = context_after.actions
- self.assertEqual(len(actions), 1)
- self.assertEqual(
- actions[0][:3],
- ('discrim', None, tests),
- )
- self.assertEqual(context_after.basepath, None)
- self.assertEqual(context_after.includepath, ())
- self.failUnless(context_after is context_before)
-
- def test_add_view_view_callable_None_no_renderer(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne(autocommit=True)
- self.assertRaises(ConfigurationError, config.add_view)
-
- def test_add_view_with_request_type_and_route_name(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- self.assertRaises(ConfigurationError, config.add_view, view, '', None,
- None, True, True)
-
- def test_add_view_with_request_type(self):
- from zope.interface import directlyProvides
- from pyramid.interfaces import IRequest
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view,
- request_type='pyramid.interfaces.IRequest')
- wrapper = self._getViewCallable(config)
- request = DummyRequest()
- self._assertNotFound(wrapper, None, request)
- directlyProvides(request, IRequest)
- result = wrapper(None, request)
- self.assertEqual(result, 'OK')
-
- def test_add_view_view_callable_None_with_renderer(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config, name='dummy')
- config.add_view(renderer='dummy')
- view = self._getViewCallable(config)
- self.failUnless('Hello!' in view(None, None).body)
-
- def test_add_view_wrapped_view_is_decorated(self):
- def view(request): # request-only wrapper
- """ """
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- self.assertEqual(wrapper.__module__, view.__module__)
- self.assertEqual(wrapper.__name__, view.__name__)
- self.assertEqual(wrapper.__doc__, view.__doc__)
-
- def test_add_view_view_callable_dottedname(self):
- config = self._makeOne(autocommit=True)
- config.add_view(view='pyramid.tests.test_configuration.dummy_view')
- wrapper = self._getViewCallable(config)
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_view_with_function_callable(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_with_function_callable_requestonly(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_as_instance(self):
- class AView:
- def __call__(self, context, request):
- """ """
- return 'OK'
- view = AView()
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_as_instance_requestonly(self):
- class AView:
- def __call__(self, request):
- """ """
- return 'OK'
- view = AView()
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_as_oldstyle_class(self):
- class view:
- def __init__(self, context, request):
- self.context = context
- self.request = request
-
- def __call__(self):
- return 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_as_oldstyle_class_requestonly(self):
- class view:
- def __init__(self, request):
- self.request = request
-
- def __call__(self):
- return 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- result = wrapper(None, None)
- self.assertEqual(result, 'OK')
-
- def test_add_view_context_as_class(self):
- from zope.interface import implementedBy
- view = lambda *arg: 'OK'
- class Foo:
- pass
- config = self._makeOne(autocommit=True)
- config.add_view(context=Foo, view=view)
- foo = implementedBy(Foo)
- wrapper = self._getViewCallable(config, foo)
- self.assertEqual(wrapper, view)
-
- def test_add_view_context_as_iface(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(context=IDummy, view=view)
- wrapper = self._getViewCallable(config, IDummy)
- self.assertEqual(wrapper, view)
-
- def test_add_view_context_as_dottedname(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(context='pyramid.tests.test_configuration.IDummy',
- view=view)
- wrapper = self._getViewCallable(config, IDummy)
- self.assertEqual(wrapper, view)
-
- def test_add_view_for__as_dottedname(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(for_='pyramid.tests.test_configuration.IDummy',
- view=view)
- wrapper = self._getViewCallable(config, IDummy)
- self.assertEqual(wrapper, view)
-
- def test_add_view_for_as_class(self):
- # ``for_`` is older spelling for ``context``
- from zope.interface import implementedBy
- view = lambda *arg: 'OK'
- class Foo:
- pass
- config = self._makeOne(autocommit=True)
- config.add_view(for_=Foo, view=view)
- foo = implementedBy(Foo)
- wrapper = self._getViewCallable(config, foo)
- self.assertEqual(wrapper, view)
-
- def test_add_view_for_as_iface(self):
- # ``for_`` is older spelling for ``context``
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(for_=IDummy, view=view)
- wrapper = self._getViewCallable(config, IDummy)
- self.assertEqual(wrapper, view)
-
- def test_add_view_context_trumps_for(self):
- # ``for_`` is older spelling for ``context``
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- class Foo:
- pass
- config.add_view(context=IDummy, for_=Foo, view=view)
- wrapper = self._getViewCallable(config, IDummy)
- self.assertEqual(wrapper, view)
-
- def test_add_view_register_secured_view(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import ISecuredView
- from pyramid.interfaces import IViewClassifier
- view = lambda *arg: 'OK'
- view.__call_permissive__ = view
- config = self._makeOne(autocommit=True)
- config.add_view(view=view)
- wrapper = config.registry.adapters.lookup(
- (IViewClassifier, IRequest, Interface),
- ISecuredView, name='', default=None)
- self.assertEqual(wrapper, view)
-
- def test_add_view_exception_register_secured_view(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IExceptionViewClassifier
- view = lambda *arg: 'OK'
- view.__call_permissive__ = view
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, context=RuntimeError)
- wrapper = config.registry.adapters.lookup(
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='', default=None)
- self.assertEqual(wrapper, view)
-
- def test_add_view_same_phash_overrides_existing_single_view(self):
- from pyramid.compat import md5
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IMultiView
- phash = md5()
- phash.update('xhr:True')
- view = lambda *arg: 'NOT OK'
- view.__phash__ = phash.hexdigest()
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview, xhr=True)
- wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_exc_same_phash_overrides_existing_single_view(self):
- from pyramid.compat import md5
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IExceptionViewClassifier
- from pyramid.interfaces import IMultiView
- phash = md5()
- phash.update('xhr:True')
- view = lambda *arg: 'NOT OK'
- view.__phash__ = phash.hexdigest()
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview, xhr=True, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_default_phash_overrides_no_phash(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'NOT OK'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview)
- wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_exc_default_phash_overrides_no_phash(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IExceptionViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'NOT OK'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_default_phash_overrides_default_phash(self):
- from pyramid.configuration import DEFAULT_PHASH
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'NOT OK'
- view.__phash__ = DEFAULT_PHASH
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview)
- wrapper = self._getViewCallable(config)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_exc_default_phash_overrides_default_phash(self):
- from pyramid.configuration import DEFAULT_PHASH
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IExceptionViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'NOT OK'
- view.__phash__ = DEFAULT_PHASH
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- def newview(context, request):
- return 'OK'
- config.add_view(view=newview, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failIf(IMultiView.providedBy(wrapper))
- request = DummyRequest()
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_multiview_replaces_existing_view(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'OK'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_view_exc_multiview_replaces_existing_view(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IExceptionViewClassifier
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IMultiView
- view = lambda *arg: 'OK'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.add_view(view=view, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_view_multiview_replaces_existing_securedview(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import ISecuredView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- view = lambda *arg: 'OK'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface),
- ISecuredView, name='')
- config.add_view(view=view)
- wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_view_exc_multiview_replaces_existing_securedview(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import ISecuredView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- view = lambda *arg: 'OK'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IViewClassifier, IRequest, implementedBy(RuntimeError)),
- ISecuredView, name='')
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- ISecuredView, name='')
- config.add_view(view=view, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_view_with_accept_multiview_replaces_existing_view(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- def view(context, request):
- return 'OK'
- def view2(context, request):
- return 'OK2'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- config.add_view(view=view2, accept='text/html')
- wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(len(wrapper.views), 1)
- self.assertEqual(len(wrapper.media_views), 1)
- self.assertEqual(wrapper(None, None), 'OK')
- request = DummyRequest()
- request.accept = DummyAccept('text/html', 'text/html')
- self.assertEqual(wrapper(None, request), 'OK2')
-
- def test_add_view_exc_with_accept_multiview_replaces_existing_view(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- def view(context, request):
- return 'OK'
- def view2(context, request):
- return 'OK2'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.add_view(view=view2, accept='text/html', context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(len(wrapper.views), 1)
- self.assertEqual(len(wrapper.media_views), 1)
- self.assertEqual(wrapper(None, None), 'OK')
- request = DummyRequest()
- request.accept = DummyAccept('text/html', 'text/html')
- self.assertEqual(wrapper(None, request), 'OK2')
-
- def test_add_view_multiview_replaces_existing_view_with___accept__(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- def view(context, request):
- return 'OK'
- def view2(context, request):
- return 'OK2'
- view.__accept__ = 'text/html'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface), IView, name='')
- config.add_view(view=view2)
- wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(len(wrapper.views), 1)
- self.assertEqual(len(wrapper.media_views), 1)
- self.assertEqual(wrapper(None, None), 'OK2')
- request = DummyRequest()
- request.accept = DummyAccept('text/html')
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_exc_mulview_replaces_existing_view_with___accept__(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- def view(context, request):
- return 'OK'
- def view2(context, request):
- return 'OK2'
- view.__accept__ = 'text/html'
- view.__phash__ = 'abc'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IView, name='')
- config.add_view(view=view2, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual(len(wrapper.views), 1)
- self.assertEqual(len(wrapper.media_views), 1)
- self.assertEqual(wrapper(None, None), 'OK2')
- request = DummyRequest()
- request.accept = DummyAccept('text/html')
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_multiview_replaces_multiview(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- view = DummyMultiView()
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Interface),
- IMultiView, name='')
- view2 = lambda *arg: 'OK2'
- config.add_view(view=view2)
- wrapper = self._getViewCallable(config)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
- self.assertEqual(wrapper(None, None), 'OK1')
-
- def test_add_view_exc_multiview_replaces_multiview(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- view = DummyMultiView()
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view,
- (IViewClassifier, IRequest, implementedBy(RuntimeError)),
- IMultiView, name='')
- config.registry.registerAdapter(
- view,
- (IExceptionViewClassifier, IRequest, implementedBy(RuntimeError)),
- IMultiView, name='')
- view2 = lambda *arg: 'OK2'
- config.add_view(view=view2, context=RuntimeError)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError), exception_view=True)
- self.failUnless(IMultiView.providedBy(wrapper))
- self.assertEqual([x[:2] for x in wrapper.views], [(view2, None)])
- self.assertEqual(wrapper(None, None), 'OK1')
-
- def test_add_view_multiview_context_superclass_then_subclass(self):
- from zope.interface import Interface
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- class ISuper(Interface):
- pass
- class ISub(ISuper):
- pass
- view = lambda *arg: 'OK'
- view2 = lambda *arg: 'OK2'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, ISuper), IView, name='')
- config.add_view(view=view2, for_=ISub)
- wrapper = self._getViewCallable(config, ISuper, IRequest)
- self.failIf(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK')
- wrapper = self._getViewCallable(config, ISub, IRequest)
- self.failIf(IMultiView.providedBy(wrapper))
- self.assertEqual(wrapper(None, None), 'OK2')
-
- def test_add_view_multiview_exception_superclass_then_subclass(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.interfaces import IView
- from pyramid.interfaces import IMultiView
- from pyramid.interfaces import IViewClassifier
- from pyramid.interfaces import IExceptionViewClassifier
- class Super(Exception):
- pass
- class Sub(Super):
- pass
- view = lambda *arg: 'OK'
- view2 = lambda *arg: 'OK2'
- config = self._makeOne(autocommit=True)
- config.registry.registerAdapter(
- view, (IViewClassifier, IRequest, Super), IView, name='')
- config.registry.registerAdapter(
- view, (IExceptionViewClassifier, IRequest, Super), IView, name='')
- config.add_view(view=view2, for_=Sub)
- wrapper = self._getViewCallable(
- config, implementedBy(Super), IRequest)
- wrapper_exc_view = self._getViewCallable(
- config, implementedBy(Super), IRequest, exception_view=True)
- self.assertEqual(wrapper_exc_view, wrapper)
- self.failIf(IMultiView.providedBy(wrapper_exc_view))
- self.assertEqual(wrapper_exc_view(None, None), 'OK')
- wrapper = self._getViewCallable(
- config, implementedBy(Sub), IRequest)
- wrapper_exc_view = self._getViewCallable(
- config, implementedBy(Sub), IRequest, exception_view=True)
- self.assertEqual(wrapper_exc_view, wrapper)
- self.failIf(IMultiView.providedBy(wrapper_exc_view))
- self.assertEqual(wrapper_exc_view(None, None), 'OK2')
-
- def test_add_view_multiview_call_ordering(self):
- from zope.interface import directlyProvides
- def view1(context, request): return 'view1'
- def view2(context, request): return 'view2'
- def view3(context, request): return 'view3'
- def view4(context, request): return 'view4'
- def view5(context, request): return 'view5'
- def view6(context, request): return 'view6'
- def view7(context, request): return 'view7'
- def view8(context, request): return 'view8'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view1)
- config.add_view(view=view2, request_method='POST')
- config.add_view(view=view3,request_param='param')
- config.add_view(view=view4, containment=IDummy)
- config.add_view(view=view5, request_method='POST',request_param='param')
- config.add_view(view=view6, request_method='POST', containment=IDummy)
- config.add_view(view=view7, request_param='param', containment=IDummy)
- config.add_view(view=view8, request_method='POST',request_param='param',
- containment=IDummy)
-
-
- wrapper = self._getViewCallable(config)
-
- ctx = DummyContext()
- request = self._makeRequest(config)
- request.method = 'GET'
- request.params = {}
- self.assertEqual(wrapper(ctx, request), 'view1')
-
- ctx = DummyContext()
- request = self._makeRequest(config)
- request.params = {}
- request.method = 'POST'
- self.assertEqual(wrapper(ctx, request), 'view2')
-
- ctx = DummyContext()
- request = self._makeRequest(config)
- request.params = {'param':'1'}
- request.method = 'GET'
- self.assertEqual(wrapper(ctx, request), 'view3')
-
- ctx = DummyContext()
- directlyProvides(ctx, IDummy)
- request = self._makeRequest(config)
- request.method = 'GET'
- request.params = {}
- self.assertEqual(wrapper(ctx, request), 'view4')
-
- ctx = DummyContext()
- request = self._makeRequest(config)
- request.method = 'POST'
- request.params = {'param':'1'}
- self.assertEqual(wrapper(ctx, request), 'view5')
-
- ctx = DummyContext()
- directlyProvides(ctx, IDummy)
- request = self._makeRequest(config)
- request.params = {}
- request.method = 'POST'
- self.assertEqual(wrapper(ctx, request), 'view6')
-
- ctx = DummyContext()
- directlyProvides(ctx, IDummy)
- request = self._makeRequest(config)
- request.method = 'GET'
- request.params = {'param':'1'}
- self.assertEqual(wrapper(ctx, request), 'view7')
-
- ctx = DummyContext()
- directlyProvides(ctx, IDummy)
- request = self._makeRequest(config)
- request.method = 'POST'
- request.params = {'param':'1'}
- self.assertEqual(wrapper(ctx, request), 'view8')
-
- def test_add_view_with_template_renderer(self):
- import pyramid.tests
- from pyramid.interfaces import ISettings
- class view(object):
- def __init__(self, context, request):
- self.request = request
- self.context = context
-
- def __call__(self):
- return {'a':'1'}
- config = self._makeOne(autocommit=True)
- renderer = self._registerRenderer(config)
- fixture = 'pyramid.tests:fixtures/minimal.txt'
- config.add_view(view=view, renderer=fixture)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- result = wrapper(None, request)
- self.assertEqual(result.body, 'Hello!')
- settings = config.registry.queryUtility(ISettings)
- result = renderer.info
- self.assertEqual(result.registry, config.registry)
- self.assertEqual(result.type, '.txt')
- self.assertEqual(result.package, pyramid.tests)
- self.assertEqual(result.name, fixture)
- self.assertEqual(result.settings, settings)
-
- def test_add_view_with_template_renderer_no_callable(self):
- import pyramid.tests
- from pyramid.interfaces import ISettings
- config = self._makeOne(autocommit=True)
- renderer = self._registerRenderer(config)
- fixture = 'pyramid.tests:fixtures/minimal.txt'
- config.add_view(view=None, renderer=fixture)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- result = wrapper(None, request)
- self.assertEqual(result.body, 'Hello!')
- settings = config.registry.queryUtility(ISettings)
- result = renderer.info
- self.assertEqual(result.registry, config.registry)
- self.assertEqual(result.type, '.txt')
- self.assertEqual(result.package, pyramid.tests)
- self.assertEqual(result.name, fixture)
- self.assertEqual(result.settings, settings)
-
- def test_add_view_with_request_type_as_iface(self):
- from zope.interface import directlyProvides
- def view(context, request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(request_type=IDummy, view=view)
- wrapper = self._getViewCallable(config, None)
- request = self._makeRequest(config)
- directlyProvides(request, IDummy)
- result = wrapper(None, request)
- self.assertEqual(result, 'OK')
-
- def test_add_view_with_request_type_as_noniface(self):
- from pyramid.exceptions import ConfigurationError
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self.assertRaises(ConfigurationError,
- config.add_view, view, '', None, None, object)
-
- def test_add_view_with_route_name(self):
- from zope.component import ComponentLookupError
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, route_name='foo')
- self.assertEqual(len(config.registry.deferred_route_views), 1)
- infos = config.registry.deferred_route_views['foo']
- self.assertEqual(len(infos), 1)
- info = infos[0]
- self.assertEqual(info['route_name'], 'foo')
- self.assertEqual(info['view'], view)
- self.assertRaises(ComponentLookupError,
- self._getRouteRequestIface, config, 'foo')
- wrapper = self._getViewCallable(config, None)
- self.assertEqual(wrapper, None)
- config.add_route('foo', '/a/b')
- request_iface = self._getRouteRequestIface(config, 'foo')
- self.failIfEqual(request_iface, None)
- wrapper = self._getViewCallable(config, request_iface=request_iface)
- self.failIfEqual(wrapper, None)
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_deferred_route_views_retains_custom_predicates(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, route_name='foo', custom_predicates=('123',))
- self.assertEqual(len(config.registry.deferred_route_views), 1)
- infos = config.registry.deferred_route_views['foo']
- self.assertEqual(len(infos), 1)
- info = infos[0]
- self.assertEqual(info['route_name'], 'foo')
- self.assertEqual(info['custom_predicates'], ('123',))
-
- def test_add_view_with_route_name_exception(self):
- from zope.interface import implementedBy
- from zope.component import ComponentLookupError
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, route_name='foo', context=RuntimeError)
- self.assertEqual(len(config.registry.deferred_route_views), 1)
- infos = config.registry.deferred_route_views['foo']
- self.assertEqual(len(infos), 1)
- info = infos[0]
- self.assertEqual(info['route_name'], 'foo')
- self.assertEqual(info['view'], view)
- self.assertRaises(ComponentLookupError,
- self._getRouteRequestIface, config, 'foo')
- wrapper_exc_view = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError),
- exception_view=True)
- self.assertEqual(wrapper_exc_view, None)
- config.add_route('foo', '/a/b')
- request_iface = self._getRouteRequestIface(config, 'foo')
- self.failIfEqual(request_iface, None)
- wrapper_exc_view = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError),
- request_iface=request_iface, exception_view=True)
- self.failIfEqual(wrapper_exc_view, None)
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError),
- request_iface=request_iface)
- self.assertEqual(wrapper_exc_view, wrapper)
- self.assertEqual(wrapper_exc_view(None, None), 'OK')
-
- def test_add_view_with_request_method_true(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_method='POST')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.method = 'POST'
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_request_method_false(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_method='POST')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.method = 'GET'
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_request_param_noval_true(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_param='abc')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.params = {'abc':''}
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_request_param_noval_false(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_param='abc')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.params = {}
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_request_param_val_true(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_param='abc=123')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.params = {'abc':'123'}
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_request_param_val_false(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_param='abc=123')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.params = {'abc':''}
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_xhr_true(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, xhr=True)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_xhr_false(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, xhr=True)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.is_xhr = False
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_header_badregex(self):
- from pyramid.exceptions import ConfigurationError
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self.assertRaises(ConfigurationError,
- config.add_view, view=view, header='Host:a\\')
-
- def test_add_view_with_header_noval_match(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, header='Host')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.headers = {'Host':'whatever'}
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_header_noval_nomatch(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, header='Host')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.headers = {'NotHost':'whatever'}
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_header_val_match(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, header=r'Host:\d')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.headers = {'Host':'1'}
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_header_val_nomatch(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, header=r'Host:\d')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.headers = {'Host':'abc'}
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_header_val_missing(self):
- from pyramid.exceptions import NotFound
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, header=r'Host:\d')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.headers = {'NoHost':'1'}
- self.assertRaises(NotFound, wrapper, None, request)
-
- def test_add_view_with_accept_match(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, accept='text/xml')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.accept = ['text/xml']
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_accept_nomatch(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, accept='text/xml')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.accept = ['text/html']
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_containment_true(self):
- from zope.interface import directlyProvides
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, containment=IDummy)
- wrapper = self._getViewCallable(config)
- context = DummyContext()
- directlyProvides(context, IDummy)
- self.assertEqual(wrapper(context, None), 'OK')
-
- def test_add_view_with_containment_false(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, containment=IDummy)
- wrapper = self._getViewCallable(config)
- context = DummyContext()
- self._assertNotFound(wrapper, context, None)
-
- def test_add_view_with_containment_dottedname(self):
- from zope.interface import directlyProvides
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(
- view=view,
- containment='pyramid.tests.test_configuration.IDummy')
- wrapper = self._getViewCallable(config)
- context = DummyContext()
- directlyProvides(context, IDummy)
- self.assertEqual(wrapper(context, None), 'OK')
-
- def test_add_view_with_path_info_badregex(self):
- from pyramid.exceptions import ConfigurationError
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self.assertRaises(ConfigurationError,
- config.add_view, view=view, path_info='\\')
-
- def test_add_view_with_path_info_match(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, path_info='/foo')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.path_info = '/foo'
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_path_info_nomatch(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, path_info='/foo')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.path_info = '/'
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_with_custom_predicates_match(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- def pred1(context, request):
- return True
- def pred2(context, request):
- return True
- predicates = (pred1, pred2)
- config.add_view(view=view, custom_predicates=predicates)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_with_custom_predicates_nomatch(self):
- view = lambda *arg: 'OK'
- config = self._makeOne(autocommit=True)
- def pred1(context, request):
- return True
- def pred2(context, request):
- return False
- predicates = (pred1, pred2)
- config.add_view(view=view, custom_predicates=predicates)
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- self._assertNotFound(wrapper, None, request)
-
- def test_add_view_custom_predicate_bests_standard_predicate(self):
- view = lambda *arg: 'OK'
- view2 = lambda *arg: 'NOT OK'
- config = self._makeOne(autocommit=True)
- def pred1(context, request):
- return True
- config.add_view(view=view, custom_predicates=(pred1,))
- config.add_view(view=view2, request_method='GET')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.method = 'GET'
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_custom_more_preds_first_bests_fewer_preds_last(self):
- view = lambda *arg: 'OK'
- view2 = lambda *arg: 'NOT OK'
- config = self._makeOne(autocommit=True)
- config.add_view(view=view, request_method='GET', xhr=True)
- config.add_view(view=view2, request_method='GET')
- wrapper = self._getViewCallable(config)
- request = self._makeRequest(config)
- request.method = 'GET'
- request.is_xhr = True
- self.assertEqual(wrapper(None, request), 'OK')
-
- def test_add_view_same_predicates(self):
- from zope.configuration.config import ConfigurationConflictError
- view2 = lambda *arg: 'second'
- view1 = lambda *arg: 'first'
- config = self._makeOne()
- config.add_view(view=view1)
- config.add_view(view=view2)
- self.assertRaises(ConfigurationConflictError, config.commit)
-
- def test_add_view_with_permission(self):
- view1 = lambda *arg: 'OK'
- outerself = self
- class DummyPolicy(object):
- def effective_principals(self, r):
- outerself.assertEqual(r, request)
- return ['abc']
- def permits(self, context, principals, permission):
- outerself.assertEqual(context, None)
- outerself.assertEqual(principals, ['abc'])
- outerself.assertEqual(permission, 'view')
- return True
- policy = DummyPolicy()
- config = self._makeOne(authorization_policy=policy,
- authentication_policy=policy,
- autocommit=True)
- config.add_view(view=view1, permission='view')
- view = self._getViewCallable(config)
- request = self._makeRequest(config)
- self.assertEqual(view(None, request), 'OK')
-
- def test_add_view_with_default_permission_no_explicit_permission(self):
- view1 = lambda *arg: 'OK'
- outerself = self
- class DummyPolicy(object):
- def effective_principals(self, r):
- outerself.assertEqual(r, request)
- return ['abc']
- def permits(self, context, principals, permission):
- outerself.assertEqual(context, None)
- outerself.assertEqual(principals, ['abc'])
- outerself.assertEqual(permission, 'view')
- return True
- policy = DummyPolicy()
- config = self._makeOne(authorization_policy=policy,
- authentication_policy=policy,
- default_permission='view',
- autocommit=True)
- config.add_view(view=view1)
- view = self._getViewCallable(config)
- request = self._makeRequest(config)
- self.assertEqual(view(None, request), 'OK')
-
- def test_add_view_with_no_default_permission_no_explicit_permission(self):
- view1 = lambda *arg: 'OK'
- class DummyPolicy(object): pass # wont be called
- policy = DummyPolicy()
- config = self._makeOne(authorization_policy=policy,
- authentication_policy=policy,
- autocommit=True)
- config.add_view(view=view1)
- view = self._getViewCallable(config)
- request = self._makeRequest(config)
- self.assertEqual(view(None, request), 'OK')
-
- def test_add_handler_action_in_route_pattern(self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_handler('name', '/:action', DummyHandler)
- self._assertRoute(config, 'name', '/:action', 0)
- self.assertEqual(len(views), 2)
-
- view = views[0]
- preds = view['custom_predicates']
- self.assertEqual(len(preds), 1)
- pred = preds[0]
- request = DummyRequest()
- self.assertEqual(pred(None, request), False)
- request.matchdict = {'action':'action1'}
- self.assertEqual(pred(None, request), True)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['attr'], 'action1')
- self.assertEqual(view['view'], DummyHandler)
-
- view = views[1]
- preds = view['custom_predicates']
- self.assertEqual(len(preds), 1)
- pred = preds[0]
- request = DummyRequest()
- self.assertEqual(pred(None, request), False)
- request.matchdict = {'action':'action2'}
- self.assertEqual(pred(None, request), True)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['attr'], 'action2')
- self.assertEqual(view['view'], DummyHandler)
-
- def test_add_handler_with_view_overridden_autoexpose_None(self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw) # pragma: no cover
- config.add_view = dummy_add_view
- class MyView(DummyHandler):
- __autoexpose__ = None
- config.add_handler('name', '/:action', MyView)
- self._assertRoute(config, 'name', '/:action', 0)
- self.assertEqual(len(views), 0)
-
- def test_add_handler_with_view_overridden_autoexpose_broken_regex1(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- def dummy_add_view(**kw):
- """ """
- config.add_view = dummy_add_view
- class MyView(DummyHandler):
- __autoexpose__ = 1
- self.assertRaises(ConfigurationError, config.add_handler,
- 'name', '/{action}', MyView)
-
- def test_add_handler_with_view_overridden_autoexpose_broken_regex2(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- def dummy_add_view(**kw):
- """ """
- config.add_view = dummy_add_view
- class MyView(DummyHandler):
- __autoexpose__ = 'a\\'
- self.assertRaises(ConfigurationError, config.add_handler,
- 'name', '/{action}', MyView)
-
- def test_add_handler_with_view_method_has_expose_config(self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- class MyView(object):
- def action(self): # pragma: no cover
- return 'response'
- action.__exposed__ = [{'custom_predicates':(1,)}]
- config.add_handler('name', '/:action', MyView)
- self._assertRoute(config, 'name', '/:action', 0)
- self.assertEqual(len(views), 1)
- view = views[0]
- preds = view['custom_predicates']
- self.assertEqual(len(preds), 2)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['attr'], 'action')
- self.assertEqual(view['view'], MyView)
-
- def test_add_handler_with_view_method_has_expose_config_with_action(self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- class MyView(object):
- def action(self): # pragma: no cover
- return 'response'
- action.__exposed__ = [{'name':'action3000'}]
- config.add_handler('name', '/:action', MyView)
- self._assertRoute(config, 'name', '/:action', 0)
- self.assertEqual(len(views), 1)
- view = views[0]
- preds = view['custom_predicates']
- self.assertEqual(len(preds), 1)
- pred = preds[0]
- request = DummyRequest()
- self.assertEqual(pred(None, request), False)
- request.matchdict = {'action':'action3000'}
- self.assertEqual(pred(None, request), True)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['attr'], 'action')
- self.assertEqual(view['view'], MyView)
-
- def test_add_handler_with_view_method_has_expose_config_with_action_regex(
- self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- class MyView(object):
- def action(self): # pragma: no cover
- return 'response'
- action.__exposed__ = [{'name':'^action3000$'}]
- config.add_handler('name', '/:action', MyView)
- self._assertRoute(config, 'name', '/:action', 0)
- self.assertEqual(len(views), 1)
- view = views[0]
- preds = view['custom_predicates']
- self.assertEqual(len(preds), 1)
- pred = preds[0]
- request = DummyRequest()
- self.assertEqual(pred(None, request), False)
- request.matchdict = {'action':'action3000'}
- self.assertEqual(pred(None, request), True)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['attr'], 'action')
- self.assertEqual(view['view'], MyView)
-
- def test_add_handler_doesnt_mutate_expose_dict(self):
- config = self._makeOne(autocommit=True)
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- exposed = [{'name':'^action3000$'}]
- class MyView(object):
- def action(self): # pragma: no cover
- return 'response'
- action.__exposed__ = exposed
- config.add_handler('name', '/{action}', MyView)
- self.assertEqual(exposed[0], {'name':'^action3000$'}) # not mutated
-
- def test_add_handler_with_action_and_action_in_path(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.add_handler,
- 'name', '/{action}', DummyHandler, action='abc')
-
- def test_add_handler_with_explicit_action(self):
- config = self._makeOne(autocommit=True)
- class DummyHandler(object):
- def index(self): pass
- index.__exposed__ = [{'a':'1'}]
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_handler('name', '/abc', DummyHandler, action='index')
- self.assertEqual(len(views), 1)
- view = views[0]
- self.assertEqual(view['a'], '1')
- self.assertEqual(view['attr'], 'index')
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['view'], DummyHandler)
-
- def test_add_handler_with_implicit_action(self):
- config = self._makeOne(autocommit=True)
- class DummyHandler(object):
- def __call__(self): pass
- __call__.__exposed__ = [{'a':'1'}]
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_handler('name', '/abc', DummyHandler)
- self.assertEqual(len(views), 1)
- view = views[0]
- self.assertEqual(view['a'], '1')
- self.assertEqual(view['attr'], None)
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['view'], DummyHandler)
-
- def test_add_handler_with_multiple_action(self):
- config = self._makeOne(autocommit=True)
- class DummyHandler(object):
- def index(self): pass
- def create(self): pass
- create.__exposed__ = [{'name': 'index'}]
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_handler('name', '/abc', DummyHandler, action='index')
- self.assertEqual(len(views), 2)
- view = views[0]
- self.assertEqual(view['attr'], 'create')
- self.assertEqual(view['route_name'], 'name')
- self.assertEqual(view['view'], DummyHandler)
- view = views[1]
- self.assertEqual(view['attr'], 'index')
-
- def test_add_handler_string(self):
- import pyramid
- views = []
- config = self._makeOne(autocommit=True)
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_handler('name', '/abc', 'pyramid')
- self.assertEqual(len(views), 1)
- view = views[0]
- self.assertEqual(view['view'], pyramid)
-
- def test_add_handler_pattern_None_no_previous_route(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.add_handler,
- 'name', None, 'pyramid')
-
- def test_add_handler_pattern_None_with_previous_route(self):
- import pyramid
- config = self._makeOne(autocommit=True)
- config.add_route('name', ':def')
- views = []
- def dummy_add_view(**kw):
- views.append(kw)
- config.add_view = dummy_add_view
- config.add_route = None # shouldn't be called
- config.add_handler('name', None, 'pyramid')
- self.assertEqual(len(views), 1)
- view = views[0]
- self.assertEqual(view['view'], pyramid)
-
-
- def _assertRoute(self, config, name, path, num_predicates=0):
- from pyramid.interfaces import IRoutesMapper
- mapper = config.registry.getUtility(IRoutesMapper)
- routes = mapper.get_routes()
- route = routes[0]
- self.assertEqual(len(routes), 1)
- self.assertEqual(route.name, name)
- self.assertEqual(route.path, path)
- self.assertEqual(len(routes[0].predicates), num_predicates)
- return route
-
- def test_get_routes_mapper_not_yet_registered(self):
- config = self._makeOne()
- mapper = config.get_routes_mapper()
- self.assertEqual(mapper.routelist, [])
-
- def test_get_routes_mapper_already_registered(self):
- from pyramid.interfaces import IRoutesMapper
- config = self._makeOne()
- mapper = object()
- config.registry.registerUtility(mapper, IRoutesMapper)
- result = config.get_routes_mapper()
- self.assertEqual(result, mapper)
-
- def test_add_route_defaults(self):
- config = self._makeOne(autocommit=True)
- route = config.add_route('name', 'path')
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(route.name, 'name')
-
- def test_add_route_with_factory(self):
- config = self._makeOne(autocommit=True)
- factory = object()
- route = config.add_route('name', 'path', factory=factory)
- self.assertEqual(route.factory, factory)
-
- def test_add_route_with_factory_dottedname(self):
- config = self._makeOne(autocommit=True)
- route = config.add_route(
- 'name', 'path',
- factory='pyramid.tests.test_configuration.dummyfactory')
- self.assertEqual(route.factory, dummyfactory)
-
- def test_add_route_with_xhr(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', xhr=True)
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.is_xhr = True
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.is_xhr = False
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_request_method(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', request_method='GET')
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.method = 'GET'
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.method = 'POST'
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_path_info(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', path_info='/foo')
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.path_info = '/foo'
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.path_info = '/'
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_request_param(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', request_param='abc')
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.params = {'abc':'123'}
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.params = {}
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_custom_predicates(self):
- config = self._makeOne(autocommit=True)
- def pred1(context, request): pass
- def pred2(context, request): pass
- config.add_route('name', 'path', custom_predicates=(pred1, pred2))
- route = self._assertRoute(config, 'name', 'path', 2)
- self.assertEqual(route.predicates, [pred1, pred2])
-
- def test_add_route_with_header(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', header='Host')
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.headers = {'Host':'example.com'}
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.headers = {}
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_accept(self):
- config = self._makeOne(autocommit=True)
- config.add_route('name', 'path', accept='text/xml')
- route = self._assertRoute(config, 'name', 'path', 1)
- predicate = route.predicates[0]
- request = self._makeRequest(config)
- request.accept = ['text/xml']
- self.assertEqual(predicate(None, request), True)
- request = self._makeRequest(config)
- request.accept = ['text/html']
- self.assertEqual(predicate(None, request), False)
-
- def test_add_route_with_view(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
-
- def test_add_route_with_view_context(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_context=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_exception(self):
- from zope.interface import implementedBy
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_context=RuntimeError)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(
- config, ctx_iface=implementedBy(RuntimeError),
- request_iface=request_type, exception_view=True)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(
- config, ctx_iface=IOther,
- request_iface=request_type, exception_view=True)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_for(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_for=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_for_(self):
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, for_=IDummy)
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, IDummy, request_type)
- self.assertEqual(wrapper(None, None), 'OK')
- self._assertRoute(config, 'name', 'path')
- wrapper = self._getViewCallable(config, IOther, request_type)
- self.assertEqual(wrapper, None)
-
- def test_add_route_with_view_renderer(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view,
- view_renderer='fixtures/minimal.txt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None).body, 'Hello!')
-
- def test_add_route_with_view_attr(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- class View(object):
- def __init__(self, context, request):
- pass
- def alt(self):
- return 'OK'
- config.add_route('name', 'path', view=View, view_attr='alt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None), 'OK')
-
- def test_add_route_with_view_renderer_alias(self):
- config = self._makeOne(autocommit=True)
- self._registerRenderer(config)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view,
- renderer='fixtures/minimal.txt')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(wrapper(None, None).body, 'Hello!')
-
- def test_add_route_with_view_permission(self):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- config = self._makeOne(autocommit=True)
- policy = lambda *arg: None
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, view_permission='edit')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.failUnless(hasattr(wrapper, '__call_permissive__'))
-
- def test_add_route_with_view_permission_alias(self):
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- config = self._makeOne(autocommit=True)
- policy = lambda *arg: None
- config.registry.registerUtility(policy, IAuthenticationPolicy)
- config.registry.registerUtility(policy, IAuthorizationPolicy)
- view = lambda *arg: 'OK'
- config.add_route('name', 'path', view=view, permission='edit')
- request_type = self._getRouteRequestIface(config, 'name')
- wrapper = self._getViewCallable(config, None, request_type)
- self._assertRoute(config, 'name', 'path')
- self.failUnless(hasattr(wrapper, '__call_permissive__'))
-
- def test_add_route_no_pattern_with_path(self):
- config = self._makeOne(autocommit=True)
- route = config.add_route('name', path='path')
- self._assertRoute(config, 'name', 'path')
- self.assertEqual(route.name, 'name')
-
- def test_add_route_no_path_no_pattern(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.add_route, 'name')
-
- def test_add_route_with_pregenerator(self):
- config = self._makeOne(autocommit=True)
- route = config.add_route('name', 'pattern', pregenerator='123')
- self.assertEqual(route.pregenerator, '123')
-
- def test__override_not_yet_registered(self):
- from pyramid.interfaces import IPackageOverrides
- package = DummyPackage('package')
- opackage = DummyPackage('opackage')
- config = self._makeOne()
- config._override(package, 'path', opackage, 'oprefix',
- PackageOverrides=DummyOverrides)
- overrides = config.registry.queryUtility(IPackageOverrides,
- name='package')
- self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
- self.assertEqual(overrides.package, package)
-
- def test__override_already_registered(self):
- from pyramid.interfaces import IPackageOverrides
- package = DummyPackage('package')
- opackage = DummyPackage('opackage')
- overrides = DummyOverrides(package)
- config = self._makeOne()
- config.registry.registerUtility(overrides, IPackageOverrides,
- name='package')
- config._override(package, 'path', opackage, 'oprefix',
- PackageOverrides=DummyOverrides)
- self.assertEqual(overrides.inserted, [('path', 'opackage', 'oprefix')])
- self.assertEqual(overrides.package, package)
-
- def test_add_static_here_no_utility_registered(self):
- from pyramid.static import PackageURLParser
- from zope.interface import implementedBy
- from pyramid.static import StaticURLInfo
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- config = self._makeOne(autocommit=True)
- config.add_static_view('static', 'fixtures/static')
- request_type = self._getRouteRequestIface(config, 'static/')
- route = self._assertRoute(config, 'static/', 'static/*subpath')
- self.assertEqual(route.factory.__class__, type(lambda x: x))
- iface = implementedBy(StaticURLInfo)
- wrapped = config.registry.adapters.lookup(
- (IViewClassifier, request_type, iface), IView, name='')
- request = self._makeRequest(config)
- self.assertEqual(wrapped(None, request).__class__, PackageURLParser)
-
- def test_add_static_view_package_relative(self):
- from pyramid.interfaces import IStaticURLInfo
- info = DummyStaticURLInfo()
- config = self._makeOne(autocommit=True)
- config.registry.registerUtility(info, IStaticURLInfo)
- config.add_static_view('static', 'pyramid.tests:fixtures/static')
- self.assertEqual(info.added,
- [('static', 'pyramid.tests:fixtures/static', {})])
-
- def test_add_static_view_package_here_relative(self):
- from pyramid.interfaces import IStaticURLInfo
- info = DummyStaticURLInfo()
- config = self._makeOne(autocommit=True)
- config.registry.registerUtility(info, IStaticURLInfo)
- config.add_static_view('static', 'fixtures/static')
- self.assertEqual(info.added,
- [('static', 'pyramid.tests:fixtures/static', {})])
-
- def test_add_static_view_absolute(self):
- import os
- from pyramid.interfaces import IStaticURLInfo
- info = DummyStaticURLInfo()
- config = self._makeOne(autocommit=True)
- config.registry.registerUtility(info, IStaticURLInfo)
- here = os.path.dirname(__file__)
- static_path = os.path.join(here, 'fixtures', 'static')
- config.add_static_view('static', static_path)
- self.assertEqual(info.added,
- [('static', static_path, {})])
-
- def test_set_notfound_view(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.exceptions import NotFound
- config = self._makeOne(autocommit=True)
- view = lambda *arg: arg
- config.set_notfound_view(view)
- request = self._makeRequest(config)
- view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
- request_iface=IRequest)
- result = view(None, request)
- self.assertEqual(result, (None, request))
-
- def test_set_notfound_view_request_has_context(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.exceptions import NotFound
- config = self._makeOne(autocommit=True)
- view = lambda *arg: arg
- config.set_notfound_view(view)
- request = self._makeRequest(config)
- request.context = 'abc'
- view = self._getViewCallable(config, ctx_iface=implementedBy(NotFound),
- request_iface=IRequest)
- result = view(None, request)
- self.assertEqual(result, ('abc', request))
-
- def test_set_forbidden_view(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.exceptions import Forbidden
- config = self._makeOne(autocommit=True)
- view = lambda *arg: 'OK'
- config.set_forbidden_view(view)
- request = self._makeRequest(config)
- view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden),
- request_iface=IRequest)
- result = view(None, request)
- self.assertEqual(result, 'OK')
-
- def test_set_forbidden_view_request_has_context(self):
- from zope.interface import implementedBy
- from pyramid.interfaces import IRequest
- from pyramid.exceptions import Forbidden
- config = self._makeOne(autocommit=True)
- view = lambda *arg: arg
- config.set_forbidden_view(view)
- request = self._makeRequest(config)
- request.context = 'abc'
- view = self._getViewCallable(config, ctx_iface=implementedBy(Forbidden),
- request_iface=IRequest)
- result = view(None, request)
- self.assertEqual(result, ('abc', request))
-
- def test__set_authentication_policy(self):
- from pyramid.interfaces import IAuthenticationPolicy
- config = self._makeOne(autocommit=True)
- policy = object()
- config._set_authentication_policy(policy)
- self.assertEqual(
- config.registry.getUtility(IAuthenticationPolicy), policy)
-
- def test__set_authorization_policy(self):
- from pyramid.interfaces import IAuthorizationPolicy
- config = self._makeOne(autocommit=True)
- policy = object()
- config._set_authorization_policy(policy)
- self.assertEqual(
- config.registry.getUtility(IAuthorizationPolicy), policy)
-
- def test_set_locale_negotiator(self):
- from pyramid.interfaces import ILocaleNegotiator
- config = self._makeOne(autocommit=True)
- def negotiator(request): pass
- config.set_locale_negotiator(negotiator)
- self.assertEqual(config.registry.getUtility(ILocaleNegotiator),
- negotiator)
-
- def test_set_locale_negotiator_dottedname(self):
- from pyramid.interfaces import ILocaleNegotiator
- config = self._makeOne(autocommit=True)
- config.set_locale_negotiator(
- 'pyramid.tests.test_configuration.dummyfactory')
- self.assertEqual(config.registry.getUtility(ILocaleNegotiator),
- dummyfactory)
-
- def test_set_request_factory(self):
- from pyramid.interfaces import IRequestFactory
- config = self._makeOne(autocommit=True)
- factory = object()
- config.set_request_factory(factory)
- self.assertEqual(config.registry.getUtility(IRequestFactory), factory)
-
- def test_set_request_factory_dottedname(self):
- from pyramid.interfaces import IRequestFactory
- config = self._makeOne(autocommit=True)
- config.set_request_factory(
- 'pyramid.tests.test_configuration.dummyfactory')
- self.assertEqual(config.registry.getUtility(IRequestFactory),
- dummyfactory)
-
- def test_set_renderer_globals_factory(self):
- from pyramid.interfaces import IRendererGlobalsFactory
- config = self._makeOne(autocommit=True)
- factory = object()
- config.set_renderer_globals_factory(factory)
- self.assertEqual(config.registry.getUtility(IRendererGlobalsFactory),
- factory)
-
- def test_set_renderer_globals_factory_dottedname(self):
- from pyramid.interfaces import IRendererGlobalsFactory
- config = self._makeOne(autocommit=True)
- config.set_renderer_globals_factory(
- 'pyramid.tests.test_configuration.dummyfactory')
- self.assertEqual(config.registry.getUtility(IRendererGlobalsFactory),
- dummyfactory)
-
- def test_set_default_permission(self):
- from pyramid.interfaces import IDefaultPermission
- config = self._makeOne(autocommit=True)
- config.set_default_permission('view')
- self.assertEqual(config.registry.getUtility(IDefaultPermission),
- 'view')
-
- def test_set_session_factory(self):
- from pyramid.interfaces import ISessionFactory
- config = self._makeOne(autocommit=True)
- config.set_session_factory('factory')
- self.assertEqual(config.registry.getUtility(ISessionFactory),
- 'factory')
-
- def test_add_translation_dirs_missing_dir(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError,
- config.add_translation_dirs,
- '/wont/exist/on/my/system')
-
- def test_add_translation_dirs_resource_spec(self):
- import os
- from pyramid.interfaces import ITranslationDirectories
- config = self._makeOne(autocommit=True)
- config.add_translation_dirs('pyramid.tests.localeapp:locale')
- here = os.path.dirname(__file__)
- locale = os.path.join(here, 'localeapp', 'locale')
- self.assertEqual(config.registry.getUtility(ITranslationDirectories),
- [locale])
-
- def test_add_translation_dirs_registers_chameleon_translate(self):
- from pyramid.interfaces import IChameleonTranslate
- from pyramid.threadlocal import manager
- request = DummyRequest()
- config = self._makeOne(autocommit=True)
- manager.push({'request':request, 'registry':config.registry})
- try:
- config.add_translation_dirs('pyramid.tests.localeapp:locale')
- translate = config.registry.getUtility(IChameleonTranslate)
- self.assertEqual(translate('Approve'), u'Approve')
- finally:
- manager.pop()
-
- def test_add_translation_dirs_abspath(self):
- import os
- from pyramid.interfaces import ITranslationDirectories
- config = self._makeOne(autocommit=True)
- here = os.path.dirname(__file__)
- locale = os.path.join(here, 'localeapp', 'locale')
- config.add_translation_dirs(locale)
- self.assertEqual(config.registry.getUtility(ITranslationDirectories),
- [locale])
-
- def test_derive_view_function(self):
- def view(request):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(view)
- self.failIf(result is view)
- self.assertEqual(result(None, None), 'OK')
-
- def test_derive_view_dottedname(self):
- config = self._makeOne()
- result = config.derive_view(
- 'pyramid.tests.test_configuration.dummy_view')
- self.failIf(result is dummy_view)
- self.assertEqual(result(None, None), 'OK')
-
- def test_derive_view_with_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'moo'
- config.add_renderer('moo', moo)
- result = config.derive_view(view, renderer='moo')
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'moo')
-
- def test_derive_view_with_default_renderer_no_explicit_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'moo'
- config.add_renderer(None, moo)
- result = config.derive_view(view)
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'moo')
-
- def test_derive_view_with_default_renderer_with_explicit_renderer(self):
- def view(request):
- return 'OK'
- config = self._makeOne(autocommit=True)
- class moo(object): pass
- class foo(object):
- def __init__(self, *arg, **kw):
- pass
- def __call__(self, *arg, **kw):
- return 'foo'
- config.add_renderer(None, moo)
- config.add_renderer('foo', foo)
- result = config.derive_view(view, renderer='foo')
- self.failIf(result is view)
- self.assertEqual(result(None, None).body, 'foo')
-
- def test_derive_view_class_without_attr(self):
- class View(object):
- def __init__(self, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(View)
- self.assertEqual(result(None, None), 'OK')
-
- def test_derive_view_class_with_attr(self):
- class View(object):
- def __init__(self, request):
- pass
- def another(self):
- return 'OK'
- config = self._makeOne()
- result = config.derive_view(View, attr='another')
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_function_context_and_request(self):
- def view(context, request):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(view(None, None), 'OK')
-
- def test__derive_view_as_function_requestonly(self):
- def view(request):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_newstyle_class_context_and_request(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_newstyle_class_requestonly(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_oldstyle_class_context_and_request(self):
- class view:
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_oldstyle_class_requestonly(self):
- class view:
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_instance_context_and_request(self):
- class View:
- def __call__(self, context, request):
- return 'OK'
- view = View()
- config = self._makeOne()
- result = config._derive_view(view)
- self.failUnless(result is view)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_as_instance_requestonly(self):
- class View:
- def __call__(self, request):
- return 'OK'
- view = View()
- config = self._makeOne()
- result = config._derive_view(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- self.assertEqual(result(None, None), 'OK')
-
- def test__derive_view_with_debug_authorization_no_authpol(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): Allowed "
- "(no authorization policy in use)")
-
- def test__derive_view_with_debug_authorization_no_permission(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- self._registerSecurityPolicy(config, True)
- logger = self._registerLogger(config)
- result = config._derive_view(view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): Allowed ("
- "no permission registered)")
-
- def test__derive_view_debug_auth_permission_authpol_permitted(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config, debug_authorization=True,
- reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, True)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result.__call_permissive__, view)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): True")
-
- def test__derive_view_debug_auth_permission_authpol_denied(self):
- from pyramid.exceptions import Forbidden
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result.__call_permissive__, view)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertRaises(Forbidden, result, None, request)
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): False")
-
- def test__derive_view_debug_auth_permission_authpol_denied2(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view, permission='view')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- permitted = result.__permitted__(None, None)
- self.assertEqual(permitted, False)
-
- def test__derive_view_debug_auth_permission_authpol_overridden(self):
- view = lambda *arg: 'OK'
- config = self._makeOne()
- self._registerSettings(config,
- debug_authorization=True, reload_templates=True)
- logger = self._registerLogger(config)
- self._registerSecurityPolicy(config, False)
- result = config._derive_view(view,
- permission='__no_permission_required__')
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.failIf(hasattr(result, '__call_permissive__'))
- request = self._makeRequest(config)
- request.view_name = 'view_name'
- request.url = 'url'
- self.assertEqual(result(None, request), 'OK')
- self.assertEqual(len(logger.messages), 1)
- self.assertEqual(logger.messages[0],
- "debug_authorization of url url (view name "
- "'view_name' against context None): False")
-
- def test__derive_view_with_predicates_all(self):
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return True
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- next = result(None, None)
- self.assertEqual(next, 'OK')
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_predicates_checker(self):
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return True
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- next = result.__predicated__(None, None)
- self.assertEqual(next, True)
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_predicates_notall(self):
- from pyramid.exceptions import NotFound
- view = lambda *arg: 'OK'
- predicates = []
- def predicate1(context, request):
- predicates.append(True)
- return True
- def predicate2(context, request):
- predicates.append(True)
- return False
- config = self._makeOne()
- result = config._derive_view(view, predicates=[predicate1, predicate2])
- request = self._makeRequest(config)
- request.method = 'POST'
- self.assertRaises(NotFound, result, None, None)
- self.assertEqual(predicates, [True, True])
-
- def test__derive_view_with_wrapper_viewname(self):
- from webob import Response
- from pyramid.interfaces import IView
- from pyramid.interfaces import IViewClassifier
- inner_response = Response('OK')
- def inner_view(context, request):
- return inner_response
- def outer_view(context, request):
- self.assertEqual(request.wrapped_response, inner_response)
- self.assertEqual(request.wrapped_body, inner_response.body)
- self.assertEqual(request.wrapped_view, inner_view)
- return Response('outer ' + request.wrapped_body)
- config = self._makeOne()
- config.registry.registerAdapter(
- outer_view, (IViewClassifier, None, None), IView, 'owrap')
- result = config._derive_view(inner_view, viewname='inner',
- wrapper_viewname='owrap')
- self.failIf(result is inner_view)
- self.assertEqual(inner_view.__module__, result.__module__)
- self.assertEqual(inner_view.__doc__, result.__doc__)
- request = self._makeRequest(config)
- request.registry = config.registry
- response = result(None, request)
- self.assertEqual(response.body, 'outer OK')
-
- def test__derive_view_with_wrapper_viewname_notfound(self):
- from webob import Response
- inner_response = Response('OK')
- def inner_view(context, request):
- return inner_response
- config = self._makeOne()
- request = self._makeRequest(config)
- request.registry = config.registry
- wrapped = config._derive_view(
- inner_view, viewname='inner', wrapper_viewname='owrap')
- self.assertRaises(ValueError, wrapped, None, request)
-
- def test_override_resource_samename(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.override_resource,'a', 'a')
-
- def test_override_resource_directory_with_file(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.override_resource,
- 'a:foo/', 'a:foo.pt')
-
- def test_override_resource_file_with_directory(self):
- from pyramid.exceptions import ConfigurationError
- config = self._makeOne()
- self.assertRaises(ConfigurationError, config.override_resource,
- 'a:foo.pt', 'a:foo/')
-
- def test_override_resource_success(self):
- config = self._makeOne(autocommit=True)
- override = DummyUnderOverride()
- config.override_resource(
- 'pyramid.tests.fixtureapp:templates/foo.pt',
- 'pyramid.tests.fixtureapp.subpackage:templates/bar.pt',
- _override=override)
- from pyramid.tests import fixtureapp
- from pyramid.tests.fixtureapp import subpackage
- self.assertEqual(override.package, fixtureapp)
- self.assertEqual(override.path, 'templates/foo.pt')
- self.assertEqual(override.override_package, subpackage)
- self.assertEqual(override.override_prefix, 'templates/bar.pt')
-
- def test_add_renderer(self):
- from pyramid.interfaces import IRendererFactory
- config = self._makeOne(autocommit=True)
- renderer = object()
- config.add_renderer('name', renderer)
- self.assertEqual(config.registry.getUtility(IRendererFactory, 'name'),
- renderer)
-
- def test_add_renderer_dottedname_factory(self):
- from pyramid.interfaces import IRendererFactory
- config = self._makeOne(autocommit=True)
- import pyramid.tests
- config.add_renderer('name', 'pyramid.tests')
- self.assertEqual(config.registry.getUtility(IRendererFactory, 'name'),
- pyramid.tests)
-
- def test_scan_integration(self):
- import os
- from zope.interface import alsoProvides
- from pyramid.interfaces import IRequest
- from pyramid.view import render_view_to_response
- import pyramid.tests.grokkedapp as package
- config = self._makeOne(autocommit=True)
- config.scan(package)
-
- ctx = DummyContext()
- req = DummyRequest()
- alsoProvides(req, IRequest)
- req.registry = config.registry
-
- req.method = 'GET'
- result = render_view_to_response(ctx, req, '')
- self.assertEqual(result, 'grokked')
-
- req.method = 'POST'
- result = render_view_to_response(ctx, req, '')
- self.assertEqual(result, 'grokked_post')
-
- result= render_view_to_response(ctx, req, 'grokked_class')
- self.assertEqual(result, 'grokked_class')
-
- result= render_view_to_response(ctx, req, 'grokked_instance')
- self.assertEqual(result, 'grokked_instance')
-
- result= render_view_to_response(ctx, req, 'oldstyle_grokked_class')
- self.assertEqual(result, 'oldstyle_grokked_class')
-
- req.method = 'GET'
- result = render_view_to_response(ctx, req, 'another')
- self.assertEqual(result, 'another_grokked')
-
- req.method = 'POST'
- result = render_view_to_response(ctx, req, 'another')
- self.assertEqual(result, 'another_grokked_post')
-
- result= render_view_to_response(ctx, req, 'another_grokked_class')
- self.assertEqual(result, 'another_grokked_class')
-
- result= render_view_to_response(ctx, req, 'another_grokked_instance')
- self.assertEqual(result, 'another_grokked_instance')
-
- result= render_view_to_response(ctx, req,
- 'another_oldstyle_grokked_class')
- self.assertEqual(result, 'another_oldstyle_grokked_class')
-
- result = render_view_to_response(ctx, req, 'stacked1')
- self.assertEqual(result, 'stacked')
-
- result = render_view_to_response(ctx, req, 'stacked2')
- self.assertEqual(result, 'stacked')
-
- result = render_view_to_response(ctx, req, 'another_stacked1')
- self.assertEqual(result, 'another_stacked')
-
- result = render_view_to_response(ctx, req, 'another_stacked2')
- self.assertEqual(result, 'another_stacked')
-
- result = render_view_to_response(ctx, req, 'stacked_class1')
- self.assertEqual(result, 'stacked_class')
-
- result = render_view_to_response(ctx, req, 'stacked_class2')
- self.assertEqual(result, 'stacked_class')
-
- result = render_view_to_response(ctx, req, 'another_stacked_class1')
- self.assertEqual(result, 'another_stacked_class')
-
- result = render_view_to_response(ctx, req, 'another_stacked_class2')
- self.assertEqual(result, 'another_stacked_class')
-
- if not os.name.startswith('java'):
- # on Jython, a class without an __init__ apparently accepts
- # any number of arguments without raising a TypeError.
-
- self.assertRaises(TypeError,
- render_view_to_response, ctx, req, 'basemethod')
-
- result = render_view_to_response(ctx, req, 'method1')
- self.assertEqual(result, 'method1')
-
- result = render_view_to_response(ctx, req, 'method2')
- self.assertEqual(result, 'method2')
-
- result = render_view_to_response(ctx, req, 'stacked_method1')
- self.assertEqual(result, 'stacked_method')
-
- result = render_view_to_response(ctx, req, 'stacked_method2')
- self.assertEqual(result, 'stacked_method')
-
- result = render_view_to_response(ctx, req, 'subpackage_init')
- self.assertEqual(result, 'subpackage_init')
-
- result = render_view_to_response(ctx, req, 'subpackage_notinit')
- self.assertEqual(result, 'subpackage_notinit')
-
- result = render_view_to_response(ctx, req, 'subsubpackage_init')
- self.assertEqual(result, 'subsubpackage_init')
-
- result = render_view_to_response(ctx, req, 'pod_notinit')
- self.assertEqual(result, None)
-
- def test_scan_integration_dottedname_package(self):
- from zope.interface import alsoProvides
- from pyramid.interfaces import IRequest
- from pyramid.view import render_view_to_response
- config = self._makeOne(autocommit=True)
- config.scan('pyramid.tests.grokkedapp')
-
- ctx = DummyContext()
- req = DummyRequest()
- alsoProvides(req, IRequest)
- req.registry = config.registry
-
- req.method = 'GET'
- result = render_view_to_response(ctx, req, '')
- self.assertEqual(result, 'grokked')
-
- def test_testing_securitypolicy(self):
- from pyramid.testing import DummySecurityPolicy
- config = self._makeOne(autocommit=True)
- config.testing_securitypolicy('user', ('group1', 'group2'),
- permissive=False)
- from pyramid.interfaces import IAuthenticationPolicy
- from pyramid.interfaces import IAuthorizationPolicy
- ut = config.registry.getUtility(IAuthenticationPolicy)
- self.failUnless(isinstance(ut, DummySecurityPolicy))
- ut = config.registry.getUtility(IAuthorizationPolicy)
- self.assertEqual(ut.userid, 'user')
- self.assertEqual(ut.groupids, ('group1', 'group2'))
- self.assertEqual(ut.permissive, False)
-
- def test_testing_models(self):
- from pyramid.traversal import find_model
- from pyramid.interfaces import ITraverser
- ob1 = object()
- ob2 = object()
- models = {'/ob1':ob1, '/ob2':ob2}
- config = self._makeOne(autocommit=True)
- config.testing_models(models)
- adapter = config.registry.getAdapter(None, ITraverser)
- result = adapter({'PATH_INFO':'/ob1'})
- self.assertEqual(result['context'], ob1)
- self.assertEqual(result['view_name'], '')
- self.assertEqual(result['subpath'], ())
- self.assertEqual(result['traversed'], (u'ob1',))
- self.assertEqual(result['virtual_root'], ob1)
- self.assertEqual(result['virtual_root_path'], ())
- result = adapter({'PATH_INFO':'/ob2'})
- self.assertEqual(result['context'], ob2)
- self.assertEqual(result['view_name'], '')
- self.assertEqual(result['subpath'], ())
- self.assertEqual(result['traversed'], (u'ob2',))
- self.assertEqual(result['virtual_root'], ob2)
- self.assertEqual(result['virtual_root_path'], ())
- self.assertRaises(KeyError, adapter, {'PATH_INFO':'/ob3'})
- try:
- config.begin()
- self.assertEqual(find_model(None, '/ob1'), ob1)
- finally:
- config.end()
-
- def test_testing_add_subscriber_single(self):
- config = self._makeOne(autocommit=True)
- L = config.testing_add_subscriber(IDummy)
- event = DummyEvent()
- config.registry.notify(event)
- self.assertEqual(len(L), 1)
- self.assertEqual(L[0], event)
- config.registry.notify(object())
- self.assertEqual(len(L), 1)
-
- def test_testing_add_subscriber_dottedname(self):
- config = self._makeOne(autocommit=True)
- L = config.testing_add_subscriber(
- 'pyramid.tests.test_configuration.IDummy')
- event = DummyEvent()
- config.registry.notify(event)
- self.assertEqual(len(L), 1)
- self.assertEqual(L[0], event)
- config.registry.notify(object())
- self.assertEqual(len(L), 1)
-
- def test_testing_add_subscriber_multiple(self):
- config = self._makeOne(autocommit=True)
- L = config.testing_add_subscriber((Interface, IDummy))
- event = DummyEvent()
- event.object = 'foo'
- # the below is the equivalent of z.c.event.objectEventNotify(event)
- config.registry.subscribers((event.object, event), None)
- self.assertEqual(len(L), 2)
- self.assertEqual(L[0], 'foo')
- self.assertEqual(L[1], event)
-
- def test_testing_add_subscriber_defaults(self):
- config = self._makeOne(autocommit=True)
- L = config.testing_add_subscriber()
- event = object()
- config.registry.notify(event)
- self.assertEqual(L[-1], event)
- event2 = object()
- config.registry.notify(event2)
- self.assertEqual(L[-1], event2)
-
- def test_hook_zca(self):
- from pyramid.threadlocal import get_current_registry
- gsm = DummyGetSiteManager()
- config = self._makeOne()
- config.hook_zca(getSiteManager=gsm)
- self.assertEqual(gsm.hook, get_current_registry)
-
- def test_unhook_zca(self):
- gsm = DummyGetSiteManager()
- config = self._makeOne()
- config.unhook_zca(getSiteManager=gsm)
- self.assertEqual(gsm.unhooked, True)
-
- def test_testing_add_renderer(self):
- config = self._makeOne(autocommit=True)
- renderer = config.testing_add_renderer('templates/foo.pt')
- from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer, DummyTemplateRenderer))
- from pyramid.renderers import render_to_response
- # must provide request to pass in registry (this is a functest)
- request = DummyRequest()
- request.registry = config.registry
- render_to_response(
- 'templates/foo.pt', {'foo':1, 'bar':2}, request=request)
- renderer.assert_(foo=1)
- renderer.assert_(bar=2)
- renderer.assert_(request=request)
-
- def test_testing_add_renderer_explicitrenderer(self):
- config = self._makeOne(autocommit=True)
- class E(Exception): pass
- def renderer(kw, system):
- self.assertEqual(kw, {'foo':1, 'bar':2})
- raise E
- renderer = config.testing_add_renderer('templates/foo.pt', renderer)
- from pyramid.renderers import render_to_response
- # must provide request to pass in registry (this is a functest)
- request = DummyRequest()
- request.registry = config.registry
- try:
- render_to_response(
- 'templates/foo.pt', {'foo':1, 'bar':2}, request=request)
- except E:
- pass
- else: # pragma: no cover
- raise AssertionError
-
- def test_testing_add_template(self):
- config = self._makeOne(autocommit=True)
- renderer = config.testing_add_template('templates/foo.pt')
- from pyramid.testing import DummyTemplateRenderer
- self.failUnless(isinstance(renderer, DummyTemplateRenderer))
- from pyramid.renderers import render_to_response
- # must provide request to pass in registry (this is a functest)
- request = DummyRequest()
- request.registry = config.registry
- render_to_response('templates/foo.pt', dict(foo=1, bar=2),
- request=request)
- renderer.assert_(foo=1)
- renderer.assert_(bar=2)
- renderer.assert_(request=request)
-
- def test_commit_conflict_simple(self):
- from zope.configuration.config import ConfigurationConflictError
- config = self._makeOne()
- def view1(request): pass
- def view2(request): pass
- config.add_view(view1)
- config.add_view(view2)
- self.assertRaises(ConfigurationConflictError, config.commit)
-
- def test_commit_conflict_resolved_with_include(self):
- config = self._makeOne()
- def view1(request): pass
- def view2(request): pass
- def includeme(config):
- config.add_view(view2)
- config.add_view(view1)
- config.include(includeme)
- config.commit()
- registeredview = self._getViewCallable(config)
- self.assertEqual(registeredview.__name__, 'view1')
-
- def test_commit_conflict_with_two_includes(self):
- from zope.configuration.config import ConfigurationConflictError
- config = self._makeOne()
- def view1(request): pass
- def view2(request): pass
- def includeme1(config):
- config.add_view(view1)
- def includeme2(config):
- config.add_view(view2)
- config.include(includeme1)
- config.include(includeme2)
- self.assertRaises(ConfigurationConflictError, config.commit)
-
- def test_commit_conflict_resolved_with_two_includes_and_local(self):
- config = self._makeOne()
- def view1(request): pass
- def view2(request): pass
- def view3(request): pass
- def includeme1(config):
- config.add_view(view1)
- def includeme2(config):
- config.add_view(view2)
- config.include(includeme1)
- config.include(includeme2)
- config.add_view(view3)
- config.commit()
- registeredview = self._getViewCallable(config)
- self.assertEqual(registeredview.__name__, 'view3')
-
- def test_autocommit_no_conflicts(self):
- config = self._makeOne(autocommit=True)
- def view1(request): pass
- def view2(request): pass
- def view3(request): pass
- config.add_view(view1)
- config.add_view(view2)
- config.add_view(view3)
- config.commit()
- registeredview = self._getViewCallable(config)
- self.assertEqual(registeredview.__name__, 'view3')
-
-class Test__map_view(unittest.TestCase):
+class ConfiguratorTests(unittest.TestCase):
def setUp(self):
- from pyramid.registry import Registry
- self.registry = Registry()
- testing.setUp(registry=self.registry)
+ from zope.deprecation import __show__
+ __show__.off()
def tearDown(self):
- del self.registry
- testing.tearDown()
-
- def _registerRenderer(self, typ='.txt'):
- from pyramid.interfaces import IRendererFactory
- from pyramid.interfaces import ITemplateRenderer
- from zope.interface import implements
- class Renderer:
- implements(ITemplateRenderer)
- spec = 'abc' + typ
- def __init__(self, path):
- self.__class__.path = path
- def __call__(self, *arg):
- return 'Hello!'
- self.registry.registerUtility(Renderer, IRendererFactory, name=typ)
- return Renderer
-
- def _makeRequest(self):
- request = DummyRequest()
- request.registry = self.registry
- return request
-
- def _callFUT(self, view, **kw):
- from pyramid.configuration import _map_view
- return _map_view(view, self.registry, **kw)
-
- def test__map_view_as_function_context_and_request(self):
- def view(context, request):
- return 'OK'
- result = self._callFUT(view)
- self.failUnless(result is view)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_function_with_attr(self):
- def view(context, request):
- """ """
- result = self._callFUT(view, attr='__name__')
- self.failIf(result is view)
- self.assertRaises(TypeError, result, None, None)
-
- def test__map_view_as_function_with_attr_and_renderer(self):
- renderer = self._registerRenderer()
- view = lambda *arg: 'OK'
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='__name__', renderer=info)
- self.failIf(result is view)
- self.assertRaises(TypeError, result, None, None)
-
- def test__map_view_as_function_requestonly(self):
- def view(request):
- return 'OK'
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_function_requestonly_with_attr(self):
- def view(request):
- """ """
- result = self._callFUT(view, attr='__name__')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertRaises(TypeError, result, None, None)
-
- def test__map_view_as_newstyle_class_context_and_request(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_newstyle_class_context_and_request_with_attr(self):
- class view(object):
- def __init__(self, context, request):
- pass
- def index(self):
- return 'OK'
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_newstyle_class_context_and_request_attr_and_renderer(
- self):
- renderer = self._registerRenderer()
- class view(object):
- def __init__(self, context, request):
- pass
- def index(self):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_as_newstyle_class_requestonly(self):
- class view(object):
- def __init__(self, request):
- pass
- def __call__(self):
- return 'OK'
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_newstyle_class_requestonly_with_attr(self):
- class view(object):
- def __init__(self, request):
- pass
- def index(self):
- return 'OK'
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_newstyle_class_requestonly_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class view(object):
- def __init__(self, request):
- pass
- def index(self):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_as_oldstyle_class_context_and_request(self):
- class view:
- def __init__(self, context, request):
- pass
- def __call__(self):
- return 'OK'
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_oldstyle_class_context_and_request_with_attr(self):
- class view:
- def __init__(self, context, request):
- pass
- def index(self):
- return 'OK'
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_oldstyle_cls_context_request_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class view:
- def __init__(self, context, request):
- pass
- def index(self):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_as_oldstyle_class_requestonly(self):
- class view:
- def __init__(self, request):
- pass
- def __call__(self):
- return 'OK'
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_oldstyle_class_requestonly_with_attr(self):
- class view:
- def __init__(self, request):
- pass
- def index(self):
- return 'OK'
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_oldstyle_class_requestonly_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class view:
- def __init__(self, request):
- pass
- def index(self):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.assertEqual(view.__name__, result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_as_instance_context_and_request(self):
- class View:
- def __call__(self, context, request):
- return 'OK'
- view = View()
- result = self._callFUT(view)
- self.failUnless(result is view)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_context_and_request_and_attr(self):
- class View:
- def index(self, context, request):
- return 'OK'
- view = View()
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_context_and_request_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class View:
- def index(self, context, request):
- return {'a':'1'}
- view = View()
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_as_instance_requestonly(self):
- class View:
- def __call__(self, request):
- return 'OK'
- view = View()
- result = self._callFUT(view)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_requestonly_with_attr(self):
- class View:
- def index(self, request):
- return 'OK'
- view = View()
- result = self._callFUT(view, attr='index')
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- self.assertEqual(result(None, None), 'OK')
-
- def test__map_view_as_instance_requestonly_with_attr_and_renderer(self):
- renderer = self._registerRenderer()
- class View:
- def index(self, request):
- return {'a':'1'}
- view = View()
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, attr='index', renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- self.failUnless('instance' in result.__name__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_rendereronly(self):
- renderer = self._registerRenderer()
- def view(context, request):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
- def test__map_view_with_registry(self):
- renderer = self._registerRenderer()
- def view(context, request):
- return {'a':'1'}
- info = {'name':renderer.spec, 'package':None}
- result = self._callFUT(view, renderer=info)
- self.failIf(result is view)
- self.assertEqual(view.__module__, result.__module__)
- self.assertEqual(view.__doc__, result.__doc__)
- request = self._makeRequest()
- self.assertEqual(result(None, request).body, 'Hello!')
-
-class Test_decorate_view(unittest.TestCase):
- def _callFUT(self, wrapped, original):
- from pyramid.configuration import decorate_view
- return decorate_view(wrapped, original)
-
- def test_it_same(self):
- def view(context, request):
- """ """
- result = self._callFUT(view, view)
- self.assertEqual(result, False)
-
- def test_it_different(self):
- class DummyView1:
- """ 1 """
- __name__ = '1'
- __module__ = '1'
- def __call__(self, context, request):
- """ """
- def __call_permissive__(self, context, reuqest):
- """ """
- def __predicated__(self, context, reuqest):
- """ """
- def __permitted__(self, context, request):
- """ """
- class DummyView2:
- """ 2 """
- __name__ = '2'
- __module__ = '2'
- def __call__(self, context, request):
- """ """
- def __call_permissive__(self, context, reuqest):
- """ """
- def __predicated__(self, context, reuqest):
- """ """
- def __permitted__(self, context, request):
- """ """
- view1 = DummyView1()
- view2 = DummyView2()
- result = self._callFUT(view1, view2)
- self.assertEqual(result, True)
- self.failUnless(view1.__doc__ is view2.__doc__)
- self.failUnless(view1.__module__ is view2.__module__)
- self.failUnless(view1.__name__ is view2.__name__)
- self.failUnless(view1.__call_permissive__.im_func is
- view2.__call_permissive__.im_func)
- self.failUnless(view1.__permitted__.im_func is
- view2.__permitted__.im_func)
- self.failUnless(view1.__predicated__.im_func is
- view2.__predicated__.im_func)
-
-class Test__make_predicates(unittest.TestCase):
- def _callFUT(self, **kw):
- from pyramid.configuration import _make_predicates
- return _make_predicates(**kw)
-
- def test_ordering_xhr_and_request_method_trump_only_containment(self):
- order1, _, _ = self._callFUT(xhr=True, request_method='GET')
- order2, _, _ = self._callFUT(containment=True)
- self.failUnless(order1 < order2)
-
- def test_ordering_number_of_predicates(self):
- order1, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- accept='accept',
- containment='containment',
- request_type='request_type',
- custom=('a',)
- )
- order2, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- accept='accept',
- containment='containment',
- request_type='request_type',
- custom=('a',)
- )
- order3, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- accept='accept',
- containment='containment',
- request_type='request_type',
- )
- order4, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- accept='accept',
- containment='containment',
- )
- order5, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- accept='accept',
- )
- order6, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- header='header',
- )
- order7, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- request_param='param',
- )
- order8, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- )
- order9, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- )
- order10, _, _ = self._callFUT(
- xhr='xhr',
- )
- order11, _, _ = self._callFUT(
- )
- self.assertEqual(order1, order2)
- self.failUnless(order3 > order2)
- self.failUnless(order4 > order3)
- self.failUnless(order5 > order4)
- self.failUnless(order6 > order5)
- self.failUnless(order7 > order6)
- self.failUnless(order8 > order7)
- self.failUnless(order9 > order8)
- self.failUnless(order10 > order9)
- self.failUnless(order11 > order10)
-
- def test_ordering_importance_of_predicates(self):
- order1, _, _ = self._callFUT(
- xhr='xhr',
- )
- order2, _, _ = self._callFUT(
- request_method='request_method',
- )
- order3, _, _ = self._callFUT(
- path_info='path_info',
- )
- order4, _, _ = self._callFUT(
- request_param='param',
- )
- order5, _, _ = self._callFUT(
- header='header',
- )
- order6, _, _ = self._callFUT(
- accept='accept',
- )
- order7, _, _ = self._callFUT(
- containment='containment',
- )
- order8, _, _ = self._callFUT(
- request_type='request_type',
- )
- order9, _, _ = self._callFUT(
- custom=('a',),
- )
- self.failUnless(order1 > order2)
- self.failUnless(order2 > order3)
- self.failUnless(order3 > order4)
- self.failUnless(order4 > order5)
- self.failUnless(order5 > order6)
- self.failUnless(order6 > order7)
- self.failUnless(order7 > order8)
- self.failUnless(order8 > order9)
-
- def test_ordering_importance_and_number(self):
- order1, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- )
- order2, _, _ = self._callFUT(
- custom=('a',),
- )
- self.failUnless(order1 < order2)
-
- order1, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- )
- order2, _, _ = self._callFUT(
- request_method='request_method',
- custom=('a',),
- )
- self.failUnless(order1 > order2)
-
- order1, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- )
- order2, _, _ = self._callFUT(
- request_method='request_method',
- custom=('a',),
- )
- self.failUnless(order1 < order2)
-
- order1, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- path_info='path_info',
- )
- order2, _, _ = self._callFUT(
- xhr='xhr',
- request_method='request_method',
- custom=('a',),
- )
- self.failUnless(order1 > order2)
-
- def test_different_custom_predicates_with_same_hash(self):
- class PredicateWithHash(object):
- def __hash__(self):
- return 1
- a = PredicateWithHash()
- b = PredicateWithHash()
- _, _, a_phash = self._callFUT(custom=(a,))
- _, _, b_phash = self._callFUT(custom=(b,))
- self.assertEqual(a_phash, b_phash)
-
- def test_traverse_has_remainder_already(self):
- order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
- self.assertEqual(len(predicates), 1)
- pred = predicates[0]
- info = {'traverse':'abc'}
- request = DummyRequest()
- result = pred(info, request)
- self.assertEqual(result, True)
- self.assertEqual(info, {'traverse':'abc'})
-
- def test_traverse_matches(self):
- order, predicates, phash = self._callFUT(traverse='/1/:a/:b')
- self.assertEqual(len(predicates), 1)
- pred = predicates[0]
- info = {'match':{'a':'a', 'b':'b'}}
- request = DummyRequest()
- result = pred(info, request)
- self.assertEqual(result, True)
- self.assertEqual(info, {'match':
- {'a':'a', 'b':'b', 'traverse':('1', 'a', 'b')}})
-
-class TestMultiView(unittest.TestCase):
- def _getTargetClass(self):
- from pyramid.configuration import MultiView
- return MultiView
-
- def _makeOne(self, name='name'):
- return self._getTargetClass()(name)
-
- def test_class_implements_ISecuredView(self):
- from zope.interface.verify import verifyClass
- from pyramid.interfaces import ISecuredView
- verifyClass(ISecuredView, self._getTargetClass())
-
- def test_instance_implements_ISecuredView(self):
- from zope.interface.verify import verifyObject
- from pyramid.interfaces import ISecuredView
- verifyObject(ISecuredView, self._makeOne())
-
- def test_add(self):
- mv = self._makeOne()
- mv.add('view', 100)
- self.assertEqual(mv.views, [(100, 'view', None)])
- mv.add('view2', 99)
- self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
- mv.add('view3', 100, 'text/html')
- self.assertEqual(mv.media_views['text/html'], [(100, 'view3', None)])
- mv.add('view4', 99, 'text/html')
- self.assertEqual(mv.media_views['text/html'],
- [(99, 'view4', None), (100, 'view3', None)])
- mv.add('view5', 100, 'text/xml')
- self.assertEqual(mv.media_views['text/xml'], [(100, 'view5', None)])
- self.assertEqual(set(mv.accepts), set(['text/xml', 'text/html']))
- self.assertEqual(mv.views, [(99, 'view2', None), (100, 'view', None)])
- mv.add('view6', 98, 'text/*')
- self.assertEqual(mv.views, [(98, 'view6', None),
- (99, 'view2', None),
- (100, 'view', None)])
-
- def test_add_with_phash(self):
- mv = self._makeOne()
- mv.add('view', 100, phash='abc')
- self.assertEqual(mv.views, [(100, 'view', 'abc')])
- mv.add('view', 100, phash='abc')
- self.assertEqual(mv.views, [(100, 'view', 'abc')])
- mv.add('view', 100, phash='def')
- self.assertEqual(mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')])
- mv.add('view', 100, phash='abc')
- self.assertEqual(mv.views, [(100, 'view', 'abc'), (100, 'view', 'def')])
-
- def test_get_views_request_has_no_accept(self):
- request = DummyRequest()
- mv = self._makeOne()
- mv.views = [(99, lambda *arg: None)]
- self.assertEqual(mv.get_views(request), mv.views)
-
- def test_get_views_no_self_accepts(self):
- request = DummyRequest()
- request.accept = True
- mv = self._makeOne()
- mv.accepts = []
- mv.views = [(99, lambda *arg: None)]
- self.assertEqual(mv.get_views(request), mv.views)
-
- def test_get_views(self):
- request = DummyRequest()
- request.accept = DummyAccept('text/html')
- mv = self._makeOne()
- mv.accepts = ['text/html']
- mv.views = [(99, lambda *arg: None)]
- html_views = [(98, lambda *arg: None)]
- mv.media_views['text/html'] = html_views
- self.assertEqual(mv.get_views(request), html_views + mv.views)
-
- def test_get_views_best_match_returns_None(self):
- request = DummyRequest()
- request.accept = DummyAccept(None)
- mv = self._makeOne()
- mv.accepts = ['text/html']
- mv.views = [(99, lambda *arg: None)]
- self.assertEqual(mv.get_views(request), mv.views)
-
- def test_match_not_found(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- self.assertRaises(NotFound, mv.match, context, request)
-
- def test_match_predicate_fails(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- def view(context, request):
- """ """
- view.__predicated__ = lambda *arg: False
- mv.views = [(100, view, None)]
- context = DummyContext()
- request = DummyRequest()
- self.assertRaises(NotFound, mv.match, context, request)
-
- def test_match_predicate_succeeds(self):
- mv = self._makeOne()
- def view(context, request):
- """ """
- view.__predicated__ = lambda *arg: True
- mv.views = [(100, view, None)]
- context = DummyContext()
- request = DummyRequest()
- result = mv.match(context, request)
- self.assertEqual(result, view)
-
- def test_permitted_no_views(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- self.assertRaises(NotFound, mv.__permitted__, context, request)
-
- def test_permitted_no_match_with__permitted__(self):
- mv = self._makeOne()
- def view(context, request):
- """ """
- mv.views = [(100, view, None)]
- self.assertEqual(mv.__permitted__(None, None), True)
-
- def test_permitted(self):
- mv = self._makeOne()
- def view(context, request):
- """ """
- def permitted(context, request):
- return False
- view.__permitted__ = permitted
- mv.views = [(100, view, None)]
- context = DummyContext()
- request = DummyRequest()
- result = mv.__permitted__(context, request)
- self.assertEqual(result, False)
-
- def test__call__not_found(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- self.assertRaises(NotFound, mv, context, request)
-
- def test___call__intermediate_not_found(self):
- from pyramid.exceptions import PredicateMismatch
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.view_name = ''
- expected_response = DummyResponse()
- def view1(context, request):
- raise PredicateMismatch
- def view2(context, request):
- return expected_response
- mv.views = [(100, view1, None), (99, view2, None)]
- response = mv(context, request)
- self.assertEqual(response, expected_response)
-
- def test___call__raise_not_found_isnt_interpreted_as_pred_mismatch(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.view_name = ''
- def view1(context, request):
- raise NotFound
- def view2(context, request):
- """ """
- mv.views = [(100, view1, None), (99, view2, None)]
- self.assertRaises(NotFound, mv, context, request)
-
- def test___call__(self):
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.view_name = ''
- expected_response = DummyResponse()
- def view(context, request):
- return expected_response
- mv.views = [(100, view, None)]
- response = mv(context, request)
- self.assertEqual(response, expected_response)
-
- def test__call_permissive__not_found(self):
- from pyramid.exceptions import NotFound
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- self.assertRaises(NotFound, mv, context, request)
-
- def test___call_permissive_has_call_permissive(self):
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.view_name = ''
- expected_response = DummyResponse()
- def view(context, request):
- """ """
- def permissive(context, request):
- return expected_response
- view.__call_permissive__ = permissive
- mv.views = [(100, view, None)]
- response = mv.__call_permissive__(context, request)
- self.assertEqual(response, expected_response)
-
- def test___call_permissive_has_no_call_permissive(self):
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.view_name = ''
- expected_response = DummyResponse()
- def view(context, request):
- return expected_response
- mv.views = [(100, view, None)]
- response = mv.__call_permissive__(context, request)
- self.assertEqual(response, expected_response)
-
- def test__call__with_accept_match(self):
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.accept = DummyAccept('text/html', 'text/xml')
- expected_response = DummyResponse()
- def view(context, request):
- return expected_response
- mv.views = [(100, None)]
- mv.media_views['text/xml'] = [(100, view, None)]
- mv.accepts = ['text/xml']
- response = mv(context, request)
- self.assertEqual(response, expected_response)
-
- def test__call__with_accept_miss(self):
- mv = self._makeOne()
- context = DummyContext()
- request = DummyRequest()
- request.accept = DummyAccept('text/plain', 'text/html')
- expected_response = DummyResponse()
- def view(context, request):
- return expected_response
- mv.views = [(100, view, None)]
- mv.media_views['text/xml'] = [(100, None, None)]
- mv.accepts = ['text/xml']
- response = mv(context, request)
- self.assertEqual(response, expected_response)
-
-
-class TestRequestOnly(unittest.TestCase):
- def _callFUT(self, arg):
- from pyramid.configuration import requestonly
- return requestonly(arg)
-
- def test_newstyle_class_no_init(self):
- class foo(object):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_newstyle_class_init_toomanyargs(self):
- class foo(object):
- def __init__(self, context, request):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_newstyle_class_init_onearg_named_request(self):
- class foo(object):
- def __init__(self, request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_onearg_named_somethingelse(self):
- class foo(object):
- def __init__(self, req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_defaultargs_firstname_not_request(self):
- class foo(object):
- def __init__(self, context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_newstyle_class_init_defaultargs_firstname_request(self):
- class foo(object):
- def __init__(self, request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_newstyle_class_init_noargs(self):
- class foo(object):
- def __init__():
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_no_init(self):
- class foo:
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_toomanyargs(self):
- class foo:
- def __init__(self, context, request):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_onearg_named_request(self):
- class foo:
- def __init__(self, request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_oldstyle_class_init_onearg_named_somethingelse(self):
- class foo:
- def __init__(self, req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_oldstyle_class_init_defaultargs_firstname_not_request(self):
- class foo:
- def __init__(self, context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_oldstyle_class_init_defaultargs_firstname_request(self):
- class foo:
- def __init__(self, request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo), True)
-
- def test_oldstyle_class_init_noargs(self):
- class foo:
- def __init__():
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_toomanyargs(self):
- def foo(context, request):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_onearg_named_request(self):
- def foo(request):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_function_onearg_named_somethingelse(self):
- def foo(req):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_function_defaultargs_firstname_not_request(self):
- def foo(context, request=None):
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_function_defaultargs_firstname_request(self):
- def foo(request, foo=1, bar=2):
- """ """
- self.assertTrue(self._callFUT(foo))
-
- def test_function_noargs(self):
- def foo():
- """ """
- self.assertFalse(self._callFUT(foo))
-
- def test_instance_toomanyargs(self):
- class Foo:
- def __call__(self, context, request):
- """ """
- foo = Foo()
- self.assertFalse(self._callFUT(foo))
-
- def test_instance_defaultargs_onearg_named_request(self):
- class Foo:
- def __call__(self, request):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo))
-
- def test_instance_defaultargs_onearg_named_somethingelse(self):
- class Foo:
- def __call__(self, req):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo))
-
- def test_instance_defaultargs_firstname_not_request(self):
- class Foo:
- def __call__(self, context, request=None):
- """ """
- foo = Foo()
- self.assertFalse(self._callFUT(foo))
-
- def test_instance_defaultargs_firstname_request(self):
- class Foo:
- def __call__(self, request, foo=1, bar=2):
- """ """
- foo = Foo()
- self.assertTrue(self._callFUT(foo), True)
-
- def test_instance_nocall(self):
- class Foo: pass
- foo = Foo()
- self.assertFalse(self._callFUT(foo))
-
-class TestMakeApp(unittest.TestCase):
- def setUp(self):
- testing.setUp()
-
- def tearDown(self):
- testing.tearDown()
-
- def _callFUT(self, *arg, **kw):
- from pyramid.configuration import make_app
- return make_app(*arg, **kw)
-
- def test_it(self):
- settings = {'a':1}
- rootfactory = object()
- app = self._callFUT(rootfactory, settings=settings,
- Configurator=DummyConfigurator)
- self.assertEqual(app.root_factory, rootfactory)
- self.assertEqual(app.settings, settings)
- self.assertEqual(app.zcml_file, 'configure.zcml')
- self.assertEqual(app.zca_hooked, True)
-
- def test_it_options_means_settings(self):
- settings = {'a':1}
- rootfactory = object()
- app = self._callFUT(rootfactory, options=settings,
- Configurator=DummyConfigurator)
- self.assertEqual(app.root_factory, rootfactory)
- self.assertEqual(app.settings, settings)
- self.assertEqual(app.zcml_file, 'configure.zcml')
-
- def test_it_with_package(self):
- package = object()
- rootfactory = object()
- app = self._callFUT(rootfactory, package=package,
- Configurator=DummyConfigurator)
- self.assertEqual(app.package, package)
-
- def test_it_with_custom_configure_zcml(self):
- rootfactory = object()
- settings = {'configure_zcml':'2.zcml'}
- app = self._callFUT(rootfactory, filename='1.zcml', settings=settings,
- Configurator=DummyConfigurator)
- self.assertEqual(app.zcml_file, '2.zcml')
-
-class Test_isexception(unittest.TestCase):
- def _callFUT(self, ob):
- from pyramid.configuration import isexception
- return isexception(ob)
-
- def test_is_exception_instance(self):
- class E(Exception):
- pass
- e = E()
- self.assertEqual(self._callFUT(e), True)
-
- def test_is_exception_class(self):
- class E(Exception):
- pass
- self.assertEqual(self._callFUT(E), True)
-
- def test_is_IException(self):
- from pyramid.interfaces import IException
- self.assertEqual(self._callFUT(IException), True)
-
- def test_is_IException_subinterface(self):
- from pyramid.interfaces import IException
- class ISubException(IException):
- pass
- self.assertEqual(self._callFUT(ISubException), True)
-
-class TestActionPredicate(unittest.TestCase):
- def _getTargetClass(self):
- from pyramid.configuration import ActionPredicate
- return ActionPredicate
-
- def _makeOne(self, action='myaction'):
- return self._getTargetClass()(action)
-
- def test_bad_action_regex_string(self):
- from pyramid.exceptions import ConfigurationError
- cls = self._getTargetClass()
- self.assertRaises(ConfigurationError, cls, '[a-z')
-
- def test_bad_action_regex_None(self):
- from pyramid.exceptions import ConfigurationError
- cls = self._getTargetClass()
- self.assertRaises(ConfigurationError, cls, None)
-
- def test___call__no_matchdict(self):
- pred = self._makeOne()
- request = DummyRequest()
- self.assertEqual(pred(None, request), False)
-
- def test___call__no_action_in_matchdict(self):
- pred = self._makeOne()
- request = DummyRequest()
- request.matchdict = {}
- self.assertEqual(pred(None, request), False)
-
- def test___call__action_does_not_match(self):
- pred = self._makeOne()
- request = DummyRequest()
- request.matchdict = {'action':'notmyaction'}
- self.assertEqual(pred(None, request), False)
-
- def test___call__action_matches(self):
- pred = self._makeOne()
- request = DummyRequest()
- request.matchdict = {'action':'myaction'}
- self.assertEqual(pred(None, request), True)
-
- def test___hash__(self):
- pred1 = self._makeOne()
- pred2 = self._makeOne()
- pred3 = self._makeOne(action='notthesame')
- self.assertEqual(hash(pred1), hash(pred2))
- self.assertNotEqual(hash(pred1), hash(pred3))
- self.assertNotEqual(hash(pred2), hash(pred3))
-
-
-
-class DummyRequest:
- subpath = ()
- matchdict = None
- def __init__(self):
- self.environ = {'PATH_INFO':'/static'}
- self.params = {}
- self.cookies = {}
- def copy(self):
- return self
- def get_response(self, app):
- return app
-
-class DummyContext:
- pass
-
-class DummyLock:
- def acquire(self):
- self.acquired = True
-
- def release(self):
- self.released = True
-
-class DummyPackage:
- def __init__(self, name):
- self.__name__ = name
-
-class DummyOverrides:
- def __init__(self, package):
- self.package = package
- self.inserted = []
-
- def insert(self, path, package, prefix):
- self.inserted.append((path, package, prefix))
-
-class DummyUnderOverride:
- def __call__(self, package, path, override_package, override_prefix,
- _info=u''):
- self.package = package
- self.path = path
- self.override_package = override_package
- self.override_prefix = override_prefix
-
-from zope.interface import Interface
-class IDummy(Interface):
- pass
-
-class IOther(Interface):
- pass
-
-class DummyResponse:
- status = '200 OK'
- headerlist = ()
- app_iter = ()
- body = ''
-
-class DummyLogger:
- def __init__(self):
- self.messages = []
- def info(self, msg):
- self.messages.append(msg)
- warn = info
- debug = info
-
-class DummySecurityPolicy:
- def __init__(self, permitted=True):
- self.permitted = permitted
-
- def effective_principals(self, request):
- return []
-
- def permits(self, context, principals, permission):
- return self.permitted
-
-class DummyConfigurator(object):
- def __init__(self, registry=None, package=None, root_factory=None,
- settings=None):
- self.root_factory = root_factory
- self.package = package
- self.settings = settings
-
- def begin(self, request=None):
- self.begun = True
- self.request = request
-
- def end(self):
- self.ended = True
-
- def load_zcml(self, filename):
- self.zcml_file = filename
-
- def make_wsgi_app(self):
- return self
-
- def hook_zca(self):
- self.zca_hooked = True
-
-
-class DummyAccept(object):
- def __init__(self, *matches):
- self.matches = list(matches)
-
- def best_match(self, offered):
- if self.matches:
- for match in self.matches:
- if match in offered:
- self.matches.remove(match)
- return match
- def __contains__(self, val):
- return val in self.matches
-
-from zope.interface import implements
-from pyramid.interfaces import IMultiView
-class DummyMultiView:
- implements(IMultiView)
- def __init__(self):
- self.views = []
- self.name = 'name'
- def add(self, view, order, accept=None, phash=None):
- self.views.append((view, accept, phash))
- def __call__(self, context, request):
- return 'OK1'
- def __permitted__(self, context, request):
- """ """
-
-class DummyGetSiteManager(object):
- def sethook(self, hook):
- self.hook = hook
- def reset(self):
- self.unhooked = True
-
-class DummyThreadLocalManager(object):
- pushed = None
- popped = False
- def push(self, d):
- self.pushed = d
- def pop(self):
- self.popped = True
-
-class IFactory(Interface):
- pass
-
-class DummyFactory(object):
- implements(IFactory)
- def __call__(self):
- """ """
-
-class DummyEvent:
- implements(IDummy)
-
-class DummyStaticURLInfo:
- def __init__(self):
- self.added = []
-
- def add(self, name, spec, **kw):
- self.added.append((name, spec, kw))
-
-def dummy_view(request):
- return 'OK'
-
-def dummyfactory(request):
- """ """
-
-class DummyHandler(object): # pragma: no cover
- def __init__(self, request):
- self.request = request
+ from zope.deprecation import __show__
+ __show__.on()
+
+ def _makeOne(self, *arg, **kw):
+ from pyramid.configuration import Configurator
+ return Configurator(*arg, **kw)
- def action1(self):
- return 'response 1'
+ def test_autocommit_true(self):
+ config = self._makeOne()
+ self.assertEqual(config.autocommit, True)
+
- def action2(self):
- return 'response 2'
-def dummy_include(config):
- config._action('discrim', None, config.package)
-
diff --git a/pyramid/tests/test_integration.py b/pyramid/tests/test_integration.py
index f7654de78..2c8892eef 100644
--- a/pyramid/tests/test_integration.py
+++ b/pyramid/tests/test_integration.py
@@ -31,9 +31,9 @@ class WGSIAppPlusViewConfigTests(unittest.TestCase):
from pyramid.interfaces import IRequest
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
- from pyramid.configuration import Config
+ from pyramid.config import Configurator
from pyramid.tests import test_integration
- config = Config()
+ config = Configurator()
config.scan(test_integration)
config.commit()
reg = config.registry
@@ -67,8 +67,8 @@ class TestStaticApp(unittest.TestCase):
class IntegrationBase(unittest.TestCase):
root_factory = None
def setUp(self):
- from pyramid.configuration import Config
- config = Config(root_factory=self.root_factory)
+ from pyramid.config import Configurator
+ config = Configurator(root_factory=self.root_factory)
config.begin()
config.load_zcml(self.config)
config.commit()
@@ -243,8 +243,8 @@ class TestExceptionViewsApp(IntegrationBase):
class ImperativeIncludeConfigurationTest(unittest.TestCase):
def setUp(self):
- from pyramid.configuration import Config
- config = Config()
+ from pyramid.config import Configurator
+ config = Configurator()
from pyramid.tests.includeapp1.root import configure
configure(config)
app = config.make_wsgi_app()
diff --git a/pyramid/tests/test_router.py b/pyramid/tests/test_router.py
index fc2d87630..0ed3d79cf 100644
--- a/pyramid/tests/test_router.py
+++ b/pyramid/tests/test_router.py
@@ -965,6 +965,79 @@ class TestRouter(unittest.TestCase):
start_response = DummyStartResponse()
self.assertRaises(RuntimeError, router, environ, start_response)
+class TestMakeApp(unittest.TestCase):
+ def setUp(self):
+ from zope.deprecation import __show__
+ __show__.off()
+ testing.setUp()
+
+ def tearDown(self):
+ from zope.deprecation import __show__
+ __show__.on()
+ testing.tearDown()
+
+ def _callFUT(self, *arg, **kw):
+ from pyramid.router import make_app
+ return make_app(*arg, **kw)
+
+ def test_it(self):
+ settings = {'a':1}
+ rootfactory = object()
+ app = self._callFUT(rootfactory, settings=settings,
+ Configurator=DummyConfigurator)
+ self.assertEqual(app.root_factory, rootfactory)
+ self.assertEqual(app.settings, settings)
+ self.assertEqual(app.zcml_file, 'configure.zcml')
+ self.assertEqual(app.zca_hooked, True)
+
+ def test_it_options_means_settings(self):
+ settings = {'a':1}
+ rootfactory = object()
+ app = self._callFUT(rootfactory, options=settings,
+ Configurator=DummyConfigurator)
+ self.assertEqual(app.root_factory, rootfactory)
+ self.assertEqual(app.settings, settings)
+ self.assertEqual(app.zcml_file, 'configure.zcml')
+
+ def test_it_with_package(self):
+ package = object()
+ rootfactory = object()
+ app = self._callFUT(rootfactory, package=package,
+ Configurator=DummyConfigurator)
+ self.assertEqual(app.package, package)
+
+ def test_it_with_custom_configure_zcml(self):
+ rootfactory = object()
+ settings = {'configure_zcml':'2.zcml'}
+ app = self._callFUT(rootfactory, filename='1.zcml', settings=settings,
+ Configurator=DummyConfigurator)
+ self.assertEqual(app.zcml_file, '2.zcml')
+
+class DummyConfigurator(object):
+ def __init__(self, registry=None, package=None, root_factory=None,
+ settings=None, autocommit=True):
+ self.root_factory = root_factory
+ self.package = package
+ self.settings = settings
+ self.autocommit = autocommit
+
+ def begin(self, request=None):
+ self.begun = True
+ self.request = request
+
+ def end(self):
+ self.ended = True
+
+ def load_zcml(self, filename):
+ self.zcml_file = filename
+
+ def make_wsgi_app(self):
+ return self
+
+ def hook_zca(self):
+ self.zca_hooked = True
+
+
class DummyContext:
pass
diff --git a/pyramid/tests/test_util.py b/pyramid/tests/test_util.py
index 2929f888f..47aab948a 100644
--- a/pyramid/tests/test_util.py
+++ b/pyramid/tests/test_util.py
@@ -154,7 +154,7 @@ class TestDottedNameResolver(unittest.TestCase):
self.assertEqual(typ.package_name, 'pyramid.tests')
def test_ctor_string_irresolveable(self):
- from pyramid.configuration import ConfigurationError
+ from pyramid.config import ConfigurationError
self.assertRaises(ConfigurationError, self._makeOne, 'cant.be.found')
def test_ctor_module(self):
diff --git a/pyramid/tests/test_zcml.py b/pyramid/tests/test_zcml.py
index a5aea32ec..33a67873f 100644
--- a/pyramid/tests/test_zcml.py
+++ b/pyramid/tests/test_zcml.py
@@ -163,9 +163,9 @@ class TestNotFoundDirective(unittest.TestCase):
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
from pyramid.exceptions import NotFound
- from pyramid.configuration import Config
+ from pyramid.config import Configurator
reg = self.config.registry
- config = Config(reg)
+ config = Configurator(reg)
def dummy_renderer_factory(*arg, **kw):
return lambda *arg, **kw: 'OK'
config.add_renderer('.pt', dummy_renderer_factory)
@@ -232,9 +232,9 @@ class TestForbiddenDirective(unittest.TestCase):
from pyramid.interfaces import IView
from pyramid.interfaces import IViewClassifier
from pyramid.exceptions import Forbidden
- from pyramid.configuration import Config
+ from pyramid.config import Configurator
reg = self.config.registry
- config = Config(reg)
+ config = Configurator(reg)
def dummy_renderer_factory(*arg, **kw):
return lambda *arg, **kw: 'OK'
config.add_renderer('.pt', dummy_renderer_factory)
diff --git a/pyramid/zcml.py b/pyramid/zcml.py
index 6f2fa30e2..06e8cee4b 100644
--- a/pyramid/zcml.py
+++ b/pyramid/zcml.py
@@ -19,7 +19,7 @@ from pyramid.authentication import AuthTktAuthenticationPolicy
from pyramid.authentication import RemoteUserAuthenticationPolicy
from pyramid.authentication import RepozeWho1AuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
-from pyramid.configuration import Config
+from pyramid.config import Configurator
from pyramid.exceptions import ConfigurationError
from pyramid.resource import resource_spec_from_abspath
from pyramid.threadlocal import get_current_registry
@@ -167,7 +167,7 @@ def view(
context = context or for_
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.add_view(
permission=permission, context=context, view=view, name=name,
request_type=request_type, route_name=route_name,
@@ -266,7 +266,7 @@ def route(_context,
if pattern is None:
raise ConfigurationError('route directive must include a "pattern"')
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.add_route(
name,
pattern,
@@ -315,7 +315,7 @@ def notfound(_context,
renderer=None,
wrapper=None):
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.set_notfound_view(view=view, attr=attr, renderer=renderer,
wrapper=wrapper)
@@ -326,7 +326,7 @@ def forbidden(_context,
renderer=None,
wrapper=None):
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.set_forbidden_view(view=view, attr=attr, renderer=renderer,
wrapper=wrapper)
@@ -346,7 +346,7 @@ class IResourceDirective(Interface):
required=True)
def resource(_context, to_override, override_with, _override=None):
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.override_resource(to_override, override_with, _override=_override)
class IRepozeWho1AuthenticationPolicyDirective(Interface):
@@ -360,7 +360,7 @@ def repozewho1authenticationpolicy(_context, identifier_name='auth_tkt',
callback=callback)
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config._set_authentication_policy(policy)
class IRemoteUserAuthenticationPolicyDirective(Interface):
@@ -374,7 +374,7 @@ def remoteuserauthenticationpolicy(_context, environ_key='REMOTE_USER',
callback=callback)
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config._set_authentication_policy(policy)
class IAuthTktAuthenticationPolicyDirective(Interface):
@@ -416,7 +416,7 @@ def authtktauthenticationpolicy(_context,
raise ConfigurationError(str(why))
# authentication policies must be registered eagerly so they can
# be found by the view registration machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config._set_authentication_policy(policy)
class IACLAuthorizationPolicyDirective(Interface):
@@ -426,7 +426,7 @@ def aclauthorizationpolicy(_context):
policy = ACLAuthorizationPolicy()
# authorization policies must be registered eagerly so they can be
# found by the view registration machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config._set_authorization_policy(policy)
class IRendererDirective(Interface):
@@ -441,7 +441,7 @@ class IRendererDirective(Interface):
def renderer(_context, factory, name=''):
# renderer factories must be registered eagerly so they can be
# found by the view machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.add_renderer(name, factory)
class IStaticDirective(Interface):
@@ -472,7 +472,7 @@ def static(_context, name, path, cache_max_age=3600,
permission='__no_permission_required__'):
""" Handle ``static`` ZCML directives
"""
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.add_static_view(name, path, cache_max_age=cache_max_age,
permission=permission)
@@ -483,7 +483,7 @@ class IScanDirective(Interface):
)
def scan(_context, package):
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.scan(package)
class ITranslationDirDirective(Interface):
@@ -495,7 +495,7 @@ class ITranslationDirDirective(Interface):
def translationdir(_context, dir):
path = path_spec(_context, dir)
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.add_translation_dirs(path)
class ILocaleNegotiatorDirective(Interface):
@@ -506,7 +506,7 @@ class ILocaleNegotiatorDirective(Interface):
)
def localenegotiator(_context, negotiator):
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.set_locale_negotiator(negotiator)
class IAdapterDirective(Interface):
@@ -645,7 +645,7 @@ def subscriber(_context, for_=None, factory=None, handler=None, provides=None):
for_ = tuple(for_)
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
if handler is not None:
config.add_subscriber(handler, for_)
@@ -732,7 +732,7 @@ def default_permission(_context, name):
""" Register a default permission name """
# the default permission must be registered eagerly so it can
# be found by the view registration machinery
- config = Config.with_context(_context)
+ config = Configurator.with_context(_context)
config.set_default_permission(name)
def path_spec(context, path):
@@ -753,7 +753,7 @@ def zcml_configure(name, package):
"""
registry = get_current_registry()
- configurator = Config(registry=registry, package=package)
+ configurator = Configurator(registry=registry, package=package)
configurator.load_zcml(name)
actions = configurator._ctx.actions[:]
configurator.commit()