Skip to content

Commit

Permalink
fix input bare style
Browse files Browse the repository at this point in the history
  • Loading branch information
plq committed Oct 28, 2012
1 parent 114b521 commit 3e80fe9
Show file tree
Hide file tree
Showing 13 changed files with 371 additions and 124 deletions.
9 changes: 8 additions & 1 deletion spyne/_base.py
Expand Up @@ -27,6 +27,10 @@
from spyne.const.xml_ns import DEFAULT_NS
from spyne.util.oset import oset

class BODY_STYLE_WRAPPED: pass
class BODY_STYLE_EMPTY: pass
class BODY_STYLE_BARE: pass

class AuxMethodContext(object):
"""Generic object that holds information specific to auxiliary methods"""
def __init__(self, p_ctx, error):
Expand Down Expand Up @@ -278,7 +282,7 @@ def __init__(self, function, in_message, out_message, doc,
is_callback=False, is_async=False, mtom=False, in_header=None,
out_header=None, faults=None,
port_type=None, no_ctx=False, udp=None, class_key=None,
aux=None, patterns=None):
aux=None, patterns=None, body_style=None):

self.__real_function = function
"""The original callable for the user code."""
Expand Down Expand Up @@ -351,6 +355,9 @@ def __init__(self, function, in_message, out_message, doc,
:class:`spyne.protocol.http.HttpPattern` object.
"""

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

@property
def name(self):
"""The public name of the function. Equals to the type_name of the
Expand Down
38 changes: 31 additions & 7 deletions spyne/decorator.py
Expand Up @@ -26,15 +26,20 @@
decorator is a simple example of this.
"""

from spyne._base import BODY_STYLE_EMPTY
from spyne import MethodDescriptor
from spyne._base import BODY_STYLE_WRAPPED
from spyne._base import BODY_STYLE_BARE
from spyne.model.complex import ComplexModel
from spyne.model.complex import TypeInfo

from spyne.const.xml_ns import DEFAULT_NS
from spyne.const.suffix import RESPONSE_SUFFIX
from spyne.const.suffix import RESULT_SUFFIX

def _produce_input_message(f, params, _in_message_name, _in_variable_names, no_ctx):
def _produce_input_message(f, params, kparams, _in_message_name, _in_variable_names, no_ctx):
_body_style = _validate_body_style(kparams)

if no_ctx is True:
arg_start=0
else:
Expand All @@ -59,9 +64,20 @@ def _produce_input_message(f, params, _in_message_name, _in_variable_names, no_c
if _in_message_name.startswith("{"):
ns = _in_message_name[1:].partition("}")[0]

message = ComplexModel.produce(type_name=_in_message_name, namespace=ns,
members=in_params)
message.__namespace__ = ns
if _body_style == 'bare':
if len(in_params) > 1:
raise Exception("body_style='bare' can handle at most one function "
"argument.")
in_param = None
if len(in_params) == 1:
in_param, = in_params.values()

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


return message

Expand Down Expand Up @@ -214,8 +230,8 @@ def explain_method(*args, **kwargs):

_in_message_name = kparams.get('_in_message_name', function_name)
_in_variable_names = kparams.get('_in_variable_names', {})
in_message = _produce_input_message(f, params, _in_message_name,
_in_variable_names, _no_ctx)
in_message = _produce_input_message(f, params, kparams,
_in_message_name, _in_variable_names, _no_ctx)

out_message = _produce_output_message(f, function_name, kparams)

Expand All @@ -228,11 +244,19 @@ def explain_method(*args, **kwargs):
if _pattern is not None:
_patterns = [_pattern]

body_style = BODY_STYLE_WRAPPED
if _validate_body_style(kparams) == 'bare':
body_style = BODY_STYLE_BARE
t, = in_message._type_info.values()
if t is None:
body_style = BODY_STYLE_EMPTY

retval = MethodDescriptor(f,
in_message, out_message, doc, _is_callback, _is_async,
_mtom, _in_header, _out_header, _faults,
port_type=_port_type, no_ctx=_no_ctx, udp=_udp,
class_key=function_name, aux=_aux, patterns=_patterns)
class_key=function_name, aux=_aux, patterns=_patterns,
body_style=body_style)

return retval

Expand Down
9 changes: 9 additions & 0 deletions spyne/interface/_base.py
Expand Up @@ -31,6 +31,7 @@

from spyne.model import ModelBase
from spyne.model.complex import ComplexModelBase
from spyne.model.complex import Alias


class Interface(object):
Expand Down Expand Up @@ -167,6 +168,7 @@ def populate_interface(self, types=None):
in_headers = method.in_header
else:
in_headers = (method.in_header,)

for in_header in in_headers:
self.__test_type_name_validity(in_header)
in_header.resolve_namespace(in_header, self.get_tns())
Expand Down Expand Up @@ -297,6 +299,10 @@ def add_class(self, cls):

class_key = '{%s}%s' % (ns, tn)
logger.debug('\tadding class %r for %r' % (repr(cls), class_key))

assert class_key not in self.classes, ("Somehow, you're trying to "
"overwrite %r by %r for class key %r." %
(self.classes[class_key], cls, class_key))
self.classes[class_key] = cls

if ns == self.get_tns():
Expand All @@ -309,6 +315,9 @@ def add_class(self, cls):
cls.__type_name__ = '%sArray' % child.get_type_name()

for k,v in cls._type_info.items():
if v is None:
continue

self.add_class(v)
child_ns = v.get_namespace()
if child_ns != ns and not child_ns in self.imports[ns] and \
Expand Down
1 change: 1 addition & 0 deletions spyne/interface/xml_schema/_base.py
Expand Up @@ -117,6 +117,7 @@ def __init__(self, interface):
self.schema_dict = {}
self.validation_schema = None
self.namespaces = odict()
self.complex_types = set()

def add(self, cls):
handler = _add_handlers[cls]
Expand Down
5 changes: 4 additions & 1 deletion spyne/interface/xml_schema/model.py
Expand Up @@ -166,7 +166,10 @@ def alias_add(document, cls):
t, = cls._type_info.values()
element = etree.Element('{%s}element' % _ns_xsd)
element.set('name', cls.get_type_name())
element.set('type', t.get_type_name_ns(document.interface))
if t is None:
etree.SubElement(element, "{%s}complexType" % _ns_xsd)
else:
element.set('type', t.get_type_name_ns(document.interface))

document.add_element(cls, element)

Expand Down
4 changes: 4 additions & 0 deletions spyne/model/complex.py
Expand Up @@ -559,6 +559,9 @@ def resolve_namespace(cls, default_ns):
ModelBase.resolve_namespace(cls, default_ns)

for k, v in cls._type_info.items():
if v is None:
continue

if v.__type_name__ is ModelBase.Empty:
v.__namespace__ = cls.get_namespace()
v.__type_name__ = "%s_%s%s" % (cls.get_type_name(), k, TYPE_SUFFIX)
Expand Down Expand Up @@ -720,6 +723,7 @@ class Alias(ComplexModelBase):

__metaclass__ = ComplexModelMeta


def log_repr(obj, cls=None):
"""Use this function if you want to echo a ComplexModel subclass. It will
limit output size of the String types, thus make your logs smaller.
Expand Down
2 changes: 2 additions & 0 deletions spyne/protocol/xml/_base.py
Expand Up @@ -58,6 +58,7 @@
from spyne.protocol.xml.model import xml_to_parent_element
from spyne.protocol.xml.model import dict_to_parent_element

from spyne.protocol.xml.model import alias_from_element
from spyne.protocol.xml.model import base_from_element
from spyne.protocol.xml.model import binary_from_element
from spyne.protocol.xml.model import array_from_element
Expand Down Expand Up @@ -129,6 +130,7 @@ def __init__(self, app=None, validator=None, xml_declaration=True,
Attachment: binary_from_element,
ComplexModelBase: complex_from_element,

Alias: alias_from_element,
Iterable: iterable_from_element,
Array: array_from_element,
})
Expand Down
15 changes: 8 additions & 7 deletions spyne/protocol/xml/model.py
Expand Up @@ -192,17 +192,18 @@ def alias_to_parent_element(prot, cls, value, tns, parent_elt, name=None):
(k,t), = cls._type_info.items()
if t is not None:
subvalue = getattr(value, k, None)
mo = t.Attributes.max_occurs

if subvalue is not None and mo > 1:
for sv in subvalue:
prot.to_parent_element(t, sv, tns, parent_elt, name)

# Don't include empty values for non-nillable optional attributes.
elif subvalue is not None or t.Attributes.min_occurs > 0:
if subvalue is not None:
prot.to_parent_element(t, subvalue, tns, parent_elt, name)


@nillable_element
def alias_from_element(prot, cls, element):
t, = cls._type_info.values()
if t is not None:
return prot.from_element(t, element)


@nillable_element
def complex_from_element(prot, cls, element):
inst = cls.get_deserialization_instance()
Expand Down
7 changes: 7 additions & 0 deletions spyne/service.py
Expand Up @@ -17,9 +17,11 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#

from spyne._base import BODY_STYLE_EMPTY
import logging
logger = logging.getLogger(__name__)

from spyne._base import BODY_STYLE_BARE
from spyne._base import EventManager
from spyne.util.oset import oset

Expand Down Expand Up @@ -199,6 +201,11 @@ def call_wrapper(cls, ctx):
The overriding function must call this function by convention.
'''

if ctx.descriptor.body_style is BODY_STYLE_BARE:
ctx.in_object = [ctx.in_object]
elif ctx.descriptor.body_style is BODY_STYLE_EMPTY:
ctx.in_object = []

if ctx.descriptor.no_ctx:
return ctx.function(*ctx.in_object)
else:
Expand Down
8 changes: 8 additions & 0 deletions spyne/test/interop/server/_service.py
Expand Up @@ -304,6 +304,14 @@ def echo_simple_bare(ss):
def echo_complex_bare(ss):
return ss

@srpc(_returns=String, _body_style='bare')
def empty_input_bare():
return "empty"

@srpc(String, _body_style='bare')
def empty_output_bare(ss):
assert ss is not None


class InteropException(ServiceBase):
@srpc()
Expand Down

0 comments on commit 3e80fe9

Please sign in to comment.