Example #1
0
def _get_event_managers(kparams):
    _evmgr = kparams.pop("_evmgr", None)
    _evmgrs = kparams.pop("_evmgrs", None)

    if _evmgr is not None and _evmgrs is not None:
        raise LogicError("Pass one of _evmgr or _evmgrs but not both")

    if _evmgr is not None:
        _evmgrs = [_evmgr]

    _event_manager = kparams.pop("_event_manager", None)
    _event_managers = kparams.pop("_event_managers", None)

    if _event_manager is not None and _event_managers is not None:
        raise LogicError("Pass one of _event_manager or "
                         "_event_managers but not both")

    if _event_manager is not None:
        _event_managers = [_event_manager]

    if _evmgrs is not None and _event_managers is not None:
        raise LogicError("You must pass at most one of _evmgr* "
                         "arguments or _event_manager* arguments")
    elif _evmgrs is not None:
        _event_managers = _evmgrs

    return _event_managers if _event_managers is not None else []
Example #2
0
def _substitute_self_reference(params, kparams, self_ref_replacement, _no_self):
    from spyne.model import SelfReference

    for i, v in enumerate(params):
        if isclass(v) and issubclass(v, SelfReference):
            if _no_self:
                raise LogicError("SelfReference can't be used in @rpc")
            params[i] = recust_selfref(v, self_ref_replacement)
        else:
            params[i] = v

    for k, v in kparams.items():
        if isclass(v) and issubclass(v, SelfReference):
            if _no_self:
                raise LogicError("SelfReference can't be used in @rpc")
            kparams[k] = recust_selfref(v, self_ref_replacement)
        else:
            kparams[k] = v
Example #3
0
def _produce_input_message(f, params, in_message_name, in_variable_names,
                           no_ctx, no_self, argnames, body_style_str,
                           self_ref_cls):
    arg_start = 0
    if no_ctx is False:
        arg_start += 1
    if no_self is False:
        arg_start += 1

    if argnames is None:
        try:
            argcount = f.__code__.co_argcount
            argnames = f.__code__.co_varnames[arg_start:argcount]

        except AttributeError:
            raise TypeError(
                "It's not possible to instrospect builtins. You must pass a "
                "sequence of argument names as the '_args' argument to the "
                "rpc decorator to manually denote the arguments that this "
                "function accepts.")

        if no_self is False:
            params = [self_ref_cls.novalidate_freq()] + params
            argnames = ('self', ) + argnames

        if len(params) != len(argnames):
            raise LogicError(
                "%r function has %d argument(s) but its decorator "
                "has %d." % (f.__name__, len(argnames), len(params)))

    else:
        argnames = copy(argnames)
        if len(params) != len(argnames):
            raise LogicError("%r function has %d argument(s) but the _args "
                             "argument has %d." %
                             (f.__name__, len(argnames), len(params)))

    in_params = TypeInfo()
    from spyne import SelfReference
    for k, v in zip(argnames, params):
        try:
            is_self_ref = issubclass(v, SelfReference)
        except TypeError:
            is_self_ref = False

        if is_self_ref:
            if no_self is False:
                raise LogicError("SelfReference can't be used in @rpc")
            v = recust_selfref(v, self_ref_cls)

        k = in_variable_names.get(k, k)
        in_params[k] = v

    ns = spyne.const.xml.DEFAULT_NS
    if in_message_name.startswith("{"):
        ns, _, in_message_name = in_message_name[1:].partition("}")

    message = None
    if body_style_str == 'bare':
        if len(in_params) > 1:
            raise LogicError("body_style='bare' can handle at most one "
                             "function argument.")

        if len(in_params) == 0:
            message = ComplexModel.produce(type_name=in_message_name,
                                           namespace=ns,
                                           members=in_params)
        else:
            message, = in_params.values()
            message = message.customize(sub_name=in_message_name, sub_ns=ns)

            if issubclass(message,
                          ComplexModelBase) and not message._type_info:
                raise LogicError("body_style='bare' does not allow empty "
                                 "model as param")

            # there can't be multiple arguments here.
            if message.__type_name__ is ModelBase.Empty:
                message._fill_empty_type_name(ns, in_message_name,
                                              "%s_arg0" % in_message_name)

    else:
        message = ComplexModel.produce(type_name=in_message_name,
                                       namespace=ns,
                                       members=in_params)
        message.__namespace__ = ns

    return message
Example #4
0
        def explain_method(**kwargs):
            # params and kparams are passed by the user to the @rpc family
            # of decorators.

            # kwargs is passed by spyne while sanitizing methods. it mainly
            # contains information about the method context like the service
            # class that contains the method at hand.

            function_name = kwargs['_default_function_name']
            _service_class = kwargs.pop("_service_class", None)
            _self_ref_replacement = None

            # this block is passed straight to the descriptor
            _is_callback = kparams.pop('_is_callback', False)
            _is_async = kparams.pop('_is_async', False)
            _mtom = kparams.pop('_mtom', False)
            _in_header = kparams.pop('_in_header', None)
            _out_header = kparams.pop('_out_header', None)
            _port_type = kparams.pop('_port_type', None)
            _no_ctx = kparams.pop('_no_ctx', False)
            _aux = kparams.pop('_aux', None)
            _pattern = kparams.pop("_pattern", None)
            _patterns = kparams.pop("_patterns", [])
            _args = kparams.pop("_args", None)
            _translations = kparams.pop("_translations", None)
            _when = kparams.pop("_when", None)
            _static_when = kparams.pop("_static_when", None)
            _href = kparams.pop("_href", None)
            _internal_key_suffix = kparams.pop('_internal_key_suffix', '')
            if '_service' in kparams and '_service_class' in kparams:
                raise LogicError("Please pass only one of '_service' and "
                                 "'_service_class'")
            if '_service' in kparams:
                _service_class = kparams.pop("_service")
            if '_service_class' in kparams:
                _service_class = kparams.pop("_service_class")

            _no_self = kparams.pop('_no_self', True)
            _event_managers = _get_event_managers(kparams)

            # mrpc-specific
            _self_ref_replacement = kwargs.pop('_self_ref_replacement', None)
            _default_on_null = kparams.pop('_default_on_null', False)
            _substitute_self_reference(params, kparams, _self_ref_replacement,
                                       _no_self)

            _faults = None
            if ('_faults' in kparams) and ('_throws' in kparams):
                raise ValueError(
                    "only one of '_throws ' or '_faults' arguments"
                    "must be given -- they're synonyms.")

            elif '_faults' in kparams:
                _faults = kparams.pop('_faults')

            elif '_throws' in kparams:
                _faults = kparams.pop('_throws')

            _is_in_message_name_overridden = not ('_in_message_name'
                                                  in kparams)
            _in_message_name = kparams.pop('_in_message_name', function_name)

            if _no_self is False and _is_in_message_name_overridden:
                _in_message_name = '%s.%s' % \
                       (_self_ref_replacement.get_type_name(), _in_message_name)

            _operation_name = kparams.pop('_operation_name', function_name)

            if _operation_name != function_name and \
                                              _in_message_name != function_name:
                raise ValueError(
                    "only one of '_operation_name' and '_in_message_name' "
                    "arguments should be given")

            if _in_message_name == function_name:
                _in_message_name = add_request_suffix(_operation_name)

            if '_in_arg_names' in kparams and '_in_variable_names' in kparams:
                raise LogicError("Use either '_in_arg_names' or "
                                 "'_in_variable_names', not both.")
            elif '_in_arg_names' in kparams:
                _in_arg_names = kparams.pop('_in_arg_names')

            elif '_in_variable_names' in kparams:
                _in_arg_names = kparams.pop('_in_variable_names')

            else:
                _in_arg_names = {}

            if '_udd' in kparams and '_udp' in kparams:
                raise LogicError("Use either '_udd' or '_udp', not both.")
            elif '_udd' in kparams:
                _udd = kparams.pop('_udd')

            elif '_udp' in kparams:
                _udd = kparams.pop('_udp')

            else:
                _udd = {}

            body_style = BODY_STYLE_WRAPPED
            body_style_str = _validate_body_style(kparams)
            if body_style_str.endswith('bare'):
                if body_style_str == 'out_bare':
                    body_style = BODY_STYLE_OUT_BARE
                else:
                    body_style = BODY_STYLE_BARE

            in_message = _produce_input_message(f, params, _in_message_name,
                                                _in_arg_names, _no_ctx,
                                                _no_self, _args,
                                                body_style_str,
                                                _self_ref_replacement)

            out_message = _produce_output_message(function_name,
                                                  body_style_str,
                                                  _self_ref_replacement,
                                                  _no_self, kparams)

            doc = getattr(f, '__doc__')

            if _pattern is not None and _patterns != []:
                raise ValueError("only one of '_pattern' and '_patterns' "
                                 "arguments should be given")

            if _pattern is not None:
                _patterns = [_pattern]

            if body_style_str.endswith('bare'):
                from spyne.model import ComplexModelBase

                ti = in_message
                to = out_message
                if issubclass(ti, ComplexModelBase) and len(
                        ti._type_info) == 0:
                    if not issubclass(to, ComplexModelBase) or \
                                                         len(to._type_info) > 0:
                        body_style = BODY_STYLE_EMPTY_OUT_BARE
                    else:
                        body_style = BODY_STYLE_EMPTY

            assert _in_header is None or isinstance(_in_header, tuple)
            retval = MethodDescriptor(
                f,
                in_message,
                out_message,
                doc,
                is_callback=_is_callback,
                is_async=_is_async,
                mtom=_mtom,
                in_header=_in_header,
                out_header=_out_header,
                faults=_faults,
                parent_class=_self_ref_replacement,
                port_type=_port_type,
                no_ctx=_no_ctx,
                udd=_udd,
                class_key=function_name,
                aux=_aux,
                patterns=_patterns,
                body_style=body_style,
                args=_args,
                operation_name=_operation_name,
                no_self=_no_self,
                translations=_translations,
                when=_when,
                static_when=_static_when,
                service_class=_service_class,
                href=_href,
                internal_key_suffix=_internal_key_suffix,
                default_on_null=_default_on_null,
                event_managers=_event_managers,
            )

            if _patterns is not None and _no_self:
                for p in _patterns:
                    p.hello(retval)

            if len(kparams) > 0:
                raise ValueError("Unknown kwarg(s) %r passed.", kparams)
            return retval
Example #5
0
def _produce_output_message(func_name, body_style_str, self_ref_cls, no_self,
                            kparams):
    """Generate an output message for "rpc"-style API methods.

    This message is a wrapper to the declared return type.
    """

    _returns = kparams.pop('_returns', None)

    try:
        is_self_ref = issubclass(_returns, SelfReference)
    except TypeError:
        is_self_ref = False

    if is_self_ref:
        if no_self is False:
            raise LogicError("SelfReference can't be used in @rpc")

        _returns = recust_selfref(_returns, self_ref_cls)

    _is_out_message_name_overridden = not ('_out_message_name' in kparams)
    _out_message_name = kparams.pop(
        '_out_message_name', '%s%s' % (func_name, spyne.const.RESPONSE_SUFFIX))

    if no_self is False and \
               (body_style_str == 'wrapped' or _is_out_message_name_overridden):
        _out_message_name = '%s.%s' % \
                               (self_ref_cls.get_type_name(), _out_message_name)

    out_params = TypeInfo()

    if _returns and body_style_str == 'wrapped':
        if isinstance(_returns, (list, tuple)):
            default_names = [
                '%s%s%d' % (func_name, spyne.const.RESULT_SUFFIX, i)
                for i in range(len(_returns))
            ]

            _out_variable_names = kparams.pop('_out_variable_names',
                                              default_names)

            assert (len(_returns) == len(_out_variable_names))

            var_pair = zip(_out_variable_names, _returns)
            out_params = TypeInfo(var_pair)

        else:
            _out_variable_name = kparams.pop(
                '_out_variable_name',
                '%s%s' % (func_name, spyne.const.RESULT_SUFFIX))

            out_params[_out_variable_name] = _returns

    ns = spyne.const.xml.DEFAULT_NS
    if _out_message_name.startswith("{"):
        _out_message_name_parts = _out_message_name[1:].partition("}")
        ns = _out_message_name_parts[0]  # skip index 1, it is the closing '}'
        _out_message_name = _out_message_name_parts[2]

    if body_style_str.endswith('bare') and _returns is not None:
        message = _returns.customize(sub_name=_out_message_name, sub_ns=ns)
        if message.__type_name__ is ModelBase.Empty:
            message.__type_name__ = _out_message_name

    else:
        message = ComplexModel.produce(type_name=_out_message_name,
                                       namespace=ns,
                                       members=out_params)

        message.Attributes._wrapper = True
        message.__namespace__ = ns  # FIXME: is this necessary?

    return message
Example #6
0
    def __init__(self, function, in_message, out_message, doc, is_callback,
                 is_async, mtom, in_header, out_header, faults, parent_class,
                 port_type, no_ctx, udd, class_key, aux, patterns, body_style,
                 args, operation_name, no_self, translations, when,
                 static_when, service_class, href, internal_key_suffix,
                 default_on_null, event_managers, logged):

        self.__real_function = function
        """The original callable for the user code."""

        self.reset_function()

        self.operation_name = operation_name
        """The base name of an operation without the request suffix, as
        generated by the ``@srpc`` decorator."""

        self.internal_key_suffix = internal_key_suffix
        """A string that is appended to the internal key string. Helpful when
        generating services programmatically."""

        self.in_message = in_message
        """A :class:`spyne.model.complex.ComplexModel` subclass that defines the
        input signature of the user function and that was automatically
        generated by the ``@srpc`` decorator."""

        self.name = None
        """The public name of the function. Equals to the type_name of the
        in_message."""

        if body_style is BODY_STYLE_BARE:
            self.name = in_message.Attributes.sub_name

        if self.name is None:
            self.name = self.in_message.get_type_name()

        self.out_message = out_message
        """A :class:`spyne.model.complex.ComplexModel` subclass that defines the
        output signature of the user function and that was automatically
        generated by the ``@srpc`` decorator."""

        self.doc = doc
        """The function docstring."""

        # these are not working, so they are not documented.
        self.is_callback = is_callback
        self.is_async = is_async
        self.mtom = mtom
        #"""Flag to indicate whether to use MTOM transport with SOAP."""
        self.port_type = port_type
        #"""The portType this function belongs to."""

        self.in_header = in_header
        """An iterable of :class:`spyne.model.complex.ComplexModel`
        subclasses to denote the types of header objects that this method can
        accept."""

        self.out_header = out_header
        """An iterable of :class:`spyne.model.complex.ComplexModel`
        subclasses to denote the types of header objects that this method can
        emit along with its return value."""

        self.faults = faults
        """An iterable of :class:`spyne.model.fault.Fault` subclasses to denote
        the types of exceptions that this method can throw."""

        self.no_ctx = no_ctx
        """no_ctx: Boolean flag to denote whether the user code gets an
        implicit :class:`spyne.MethodContext` instance as first argument."""

        self.udd = DefaultAttrDict(**udd)
        """Short for "User Defined Data", this is an empty DefaultAttrDict that
        can be updated by the user to pass arbitrary metadata via the ``@rpc``
        decorator."""

        self.class_key = class_key
        """ The identifier of this method in its parent
        :class:`spyne.service.Service` subclass."""

        self.aux = aux
        """Value to indicate what kind of auxiliary method this is. (None means
        primary)

        Primary methods block the request as long as they're running. Their
        return values are returned to the client. Auxiliary ones execute
        asyncronously after the primary method returns, and their return values
        are ignored by the rpc layer.
        """

        self.patterns = patterns
        """This list stores patterns which will match this callable using
        various elements of the request protocol.

        Currently, the only object supported here is the
        :class:`spyne.protocol.http.HttpPattern` object.
        """

        self.body_style = body_style
        """One of (BODY_STYLE_EMPTY, BODY_STYLE_BARE, BODY_STYLE_WRAPPED)."""

        self.args = args
        """A sequence of the names of the exposed arguments, or None."""

        self.no_self = no_self
        """When False, this passes self as first argument (before ctx) to the
        decorated function. This is what separates ``@rpc`` and ``@mrpc``."""

        self.service_class = service_class
        """The Service subclass the method belongs to. If not None for
        ``@mrpc`` methods, a Service subclass for anything else."""

        self.parent_class = parent_class
        """The ComplexModel subclass the method belongs to. Only set for
        ``@mrpc`` methods."""

        self.default_on_null = default_on_null
        if parent_class is None and not (default_on_null is False):
            raise LogicError("default_on_null is only to be used inside @mrpc")

        # HATEOAS Stuff
        self.translations = translations
        """None or a dict of locale-translation pairs."""

        self.href = href
        """None or a dict of locale-translation pairs."""

        self.when = when
        """None or a callable that takes an object instance and a
        :class:`MethodContext` and returns a boolean value. If this callable
        returns ``True``, the object can process that action.
        """

        self.static_when = static_when
        """None or a callable that takes an :class:`Application` instance and
        returns a boolean value. If true, the object can have that action
        registered in the interface document.
        """

        self.event_managers = event_managers
        """Event managers registered with this method."""

        self.logged = logged
        """Denotes the logging style for this method."""

        if self.service_class is not None:
            self.event_managers.append(self.service_class.event_manager)