示例#1
0
class Middleware(with_metaclass(ABCMeta, object)):
    """Base class for middleware implementations.

    Each request handler is assigned a list of `Middleware` implementations.
    Before a handler is called, each middleware is executed using the
    `Middleware.before` method. When the underlying handler is finished, the
    `Middleware.after` method may manipulate the result.
    """
    def __init__(self, *args, **kwargs):
        """Initialize the decorator and register the `after()` callback."""
        pass

    def __call__(self, fn):
        """Call the `before()` method and then the decorated method. If this
        returns a `Future`, add the `after()` method as a `done` callback.
        Otherwise execute it immediately.
        """
        @coroutine
        @wraps(fn)
        def before(other, *args, **kwargs):
            before_result = yield self.before(other, args, kwargs)

            if isinstance(before_result, (ReturnInformationT, Model)):
                raise Return(before_result)

            result = yield fn(other, *args, **kwargs)

            after_result = yield self.after(other, args, kwargs, result)

            if isinstance(after_result, (ReturnInformationT, Model)):
                raise Return(after_result)

            raise Return(result)

        return before

    @abstractmethod
    def before(self, handler, args, kwargs):
        """Method executed before the underlying request handler is called."""

    @abstractmethod
    def after(self, handler, args, kwargs, result):
        """Method executed after the unterlying request handler ist called."""
示例#2
0
class ConsumerBase(with_metaclass(ConsumerMeta, object)):
    """Base class for content type consumers.

    In order to create a new consumer, you must create a new class that
    inherits from :py:class:`ConsumerBase` and sets the
    :data:`ConsumerBase.CONTENT_TYPE` variable::

        class MyConsumer(s.ConsumerBase):

            CONTENT_TYPE = s.ContentType('application/xml')

            def consume(self, handler, model):
                return model(lxml.from_string(handler.request.body))

    .. seealso:: :py:mod:`supercell.api.consumer.JsonConsumer.consume`
    """

    CONTENT_TYPE = None
    """The target content type for the consumer.

    :type: `supercell.api.ContentType`
    """
    @staticmethod
    def map_consumer(content_type, handler):
        """Map a given content type to the correct provider implementation.

        If no provider matches, raise a `NoProviderFound` exception.

        :param accept_header: HTTP Accept header value
        :type accept_header: str
        :param handler: supercell request handler

        :raises: :exc:`NoConsumerFound`
        """
        accept = parse_accept_header(content_type)
        if len(accept) == 0:
            raise NoConsumerFound()

        (ctype, params, q) = accept[0]

        if ctype not in handler._CONS_CONTENT_TYPES:
            raise NoConsumerFound()

        c = ContentType(ctype,
                        vendor=params.get('vendor', None),
                        version=params.get('version', None))
        if c not in handler._CONS_CONTENT_TYPES[ctype]:
            raise NoConsumerFound()

        known_types = [
            t for t in ConsumerMeta.KNOWN_CONTENT_TYPES[ctype] if t[0] == c
        ]

        if len(known_types) == 1:
            return (handler._CONS_MODEL[c], known_types[0][1])

        raise NoConsumerFound()

    def consume(self, handler, model):
        """This method should return the correct representation as a parsed
        model.

        :param model: the model to convert to a certain content type
        :type model: :class:`schematics.models.Model`
        """
        raise NotImplementedError
示例#3
0
class ProviderBase(with_metaclass(ProviderMeta, object)):
    """Base class for content type providers.

    Creating a new provider is just as simple as creating new consumers::

        class MyProvider(s.ProviderBase):

            CONTENT_TYPE = s.ContentType('application/xml')

            def provide(self, model, handler):
                self.set_header('Content-Type', 'application/xml')
                handler.write(model.to_xml())
    """

    CONTENT_TYPE = None
    """The target content type for the provider.

    :type: `supercell.api.ContentType`
    """

    @staticmethod
    def map_provider(accept_header, handler, allow_default=False):
        """Map a given content type to the correct provider implementation.

        If no provider matches, raise a `NoProviderFound` exception.

        :param accept_header: HTTP Accept header value
        :type accept_header: str
        :param handler: supercell request handler
        :param allow_default: allow usage of default provider if no accept
                              header is set, default is False
        :type allow_default: bool
        :raises: :exc:`NoProviderFound`

        :return: A tuple of the matching provider implementation class and
                 the provide()-kwargs
        :rtype: (supercell.api.provider.ProviderBase, dict)
        """
        if not hasattr(handler, '_PROD_CONTENT_TYPES'):
            raise NoProviderFound()

        accept = parse_accept_header(accept_header)

        if len(accept) > 0:
            for (ctype, params, q) in accept:
                if ctype not in handler._PROD_CONTENT_TYPES:
                    continue

                c = ContentType(ctype, vendor=params.get('vendor', None),
                                version=params.get('version', None))
                if c not in handler._PROD_CONTENT_TYPES[ctype]:
                    continue

                known_types = [t for t in
                               ProviderMeta.KNOWN_CONTENT_TYPES[ctype]
                               if t[0] == c]

                configuration = handler._PROD_CONFIGURATION[ctype]
                if len(known_types) == 1:
                    return (known_types[0][1], configuration)

        if allow_default and 'default' in handler._PROD_CONTENT_TYPES:
            content_type = handler._PROD_CONTENT_TYPES['default']
            configuration = handler._PROD_CONFIGURATION['default']
            ctype = content_type.content_type
            default_type = [t for t in
                            ProviderMeta.KNOWN_CONTENT_TYPES[ctype]
                            if t[0] == content_type]

            if len(default_type) == 1:
                return (default_type[0][1], configuration)

        raise NoProviderFound()

    def provide(self, model, handler, **kwargs):
        """This method should return the correct representation as a simple
        string (i.e. byte buffer) that will be used as return value.

        :param model: the model to convert to a certain content type
        :type model: supercell.schematics.Model
        :param handler: the handler to write the return
        :type handler: supercell.requesthandler.RequestHandler
        """
        raise NotImplementedError

    def error(self, status_code, message, handler):
        """This method should return the correct representation of errors
        that will be used as return value.

        :param status_code: the HTTP status code to return
        :type status_code: int
        :param message: the error message to return
        :type message: str
        :param handler: the handler to write the return
        :type handler: supercell.requesthandler.RequestHandler
        """
        raise NotImplementedError
示例#4
0
class ProviderBase(with_metaclass(ProviderMeta, object)):
    """Base class for content type providers.

    Creating a new provider is just as simple as creating new consumers::

        class MyProvider(s.ProviderBase):

            CONTENT_TYPE = s.ContentType('application/xml')

            def provide(self, model, handler):
                self.set_header('Content-Type', 'application/xml')
                handler.write(model.to_xml())
    """

    CONTENT_TYPE = None
    """The target content type for the provider.

    :type: `supercell.api.ContentType`
    """
    @staticmethod
    def map_provider(accept_header, handler, allow_default=False):
        """Map a given content type to the correct provider implementation.

        If no provider matches, raise a `NoProviderFound` exception.

        :param accept_header: HTTP Accept header value
        :type accept_header: str
        :param handler: supercell request handler
        :raises: :exc:`NoProviderFound`
        """
        if not hasattr(handler, '_PROD_CONTENT_TYPES'):
            raise NoProviderFound()

        accept = parse_accept_header(accept_header)

        if len(accept) > 0:
            for (ctype, params, q) in accept:
                if ctype not in handler._PROD_CONTENT_TYPES:
                    continue

                c = ContentType(ctype,
                                vendor=params.get('vendor', None),
                                version=params.get('version', None))
                if c not in handler._PROD_CONTENT_TYPES[ctype]:
                    continue

                known_types = [
                    t for t in ProviderMeta.KNOWN_CONTENT_TYPES[ctype]
                    if t[0] == c
                ]

                if len(known_types) == 1:
                    return known_types[0][1]

        if 'default' in handler._PROD_CONTENT_TYPES:
            content_type = handler._PROD_CONTENT_TYPES['default']
            ctype = content_type.content_type
            default_type = [
                t for t in ProviderMeta.KNOWN_CONTENT_TYPES[ctype]
                if t[0] == content_type
            ]

            if len(default_type) == 1:
                return default_type[0][1]

        raise NoProviderFound()

    def provide(self, model, handler):
        """This method should return the correct representation as a simple
        string (i.e. byte buffer) that will be used as return value.

        :param model: the model to convert to a certain content type
        :type model: supercell.schematics.Model
        """
        raise NotImplementedError