Changeset 19

Show
Ignore:
Timestamp:
02/28/07 09:26:07 (2 years ago)
Author:
kevin
Message:

largely functional support for complex inputs

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/tgwebservices/controllers.py

    r18 r19  
    2222from tgwebservices import soap 
    2323from tgwebservices.runtime import register, primitives, \ 
    24                                   FunctionInfo, register_complex_type 
     24                                  FunctionInfo, register_complex_type, \ 
     25                                  ctvalues 
    2526 
    2627config.update({"tg.empty_flash" : False}) 
     
    117118                             value, None) 
    118119 
     120def _get_single_value(elem, itype): 
     121    """Converts a single XML element into the given type""" 
     122    if isinstance(itype, list): 
     123        itemtype = itype[0] 
     124        items = [] 
     125        for subelem in elem.getchildren(): 
     126            items.append(_get_single_value(subelem, itemtype)) 
     127        return items 
     128    if not isinstance(itype, type): 
     129        itype = type(itype) 
     130    if itype not in primitives: 
     131        return _xml_to_instance(elem, itype) 
     132    if itype == bool: 
     133        itype = boolean_converter 
     134         
     135    if elem.text is None: 
     136        text = "" 
     137    else: 
     138        text = elem.text 
     139         
     140    try: 
     141        return itype(text) 
     142    except ValueError: 
     143        raise validators.Invalid( 
     144            "%s value for the '%s' parameter is not a " 
     145            "valid %s" % (text, soap.namespace_expr.sub("", elem.tag), 
     146                         itype.__name__),  
     147            text, None) 
     148     
     149def _xml_to_instance(input, cls): 
     150    """Converts an input element into a new instance of cls.""" 
     151    instance = cls() 
     152    for elem in input.getchildren(): 
     153        tag = soap.namespace_expr.sub("", elem.tag) 
     154        try: 
     155            itype = getattr(cls, tag) 
     156        except AttributeError: 
     157            raise validators.Invalid("%s is an unknown tag for a %s"  
     158                                     % (tag, cls.__name__), 
     159                tag, None) 
     160        setattr(instance, tag, _get_single_value(elem, itype)) 
     161    return instance 
     162 
     163class ComplexConverter(object): 
     164    pass_xml = True 
     165     
     166    def __init__(self, cls): 
     167        self.cls = cls 
     168     
     169    def __call__(self, val): 
     170        return _get_single_value(val, self.cls) 
     171 
     172def _handle_xml_params(body, input_types): 
     173    kw = {} 
     174    for elem in body.getchildren(): 
     175        param = soap.namespace_expr.sub("", elem.tag) 
     176        try: 
     177            itype = input_types[param] 
     178        except KeyError: 
     179            raise validators.Invalid( 
     180                "%s is not a valid parameter (valid values are: %s)" 
     181                % (param, input_types.keys()), param, None 
     182            ) 
     183        kw[param] = _get_single_value(elem, itype) 
     184    return kw 
     185 
     186def _handle_keyword_params(kw, input_types): 
     187    # convert the input parameters to appropriate types 
     188    for key in kw: 
     189        if key in input_types: 
     190            try: 
     191                converter = input_types[key] 
     192                if converter == bool: 
     193                    converter = boolean_converter 
     194                kw[key] = converter(kw[key]) 
     195            except ValueError: 
     196                raise validators.Invalid( 
     197                    "%s value for the '%s' parameter is not a " 
     198                    "valid %s" % (kw[key], key,  
     199                                 input_types[key].__name__),  
     200                    kw[key], None) 
     201        else: 
     202            raise validators.Invalid( 
     203                "%s is not a valid parameter (valid values are: %s)" 
     204                % (key, input_types.keys()), key, None 
     205            ) 
     206             
    119207def wsvalidate(*args, **kw): 
    120208    """Validates and converts incoming parameters. Also registers the  
     
    132220        for i in range(0, len(args)): 
    133221            argtype = args[i] 
    134             if argtype is bool: 
    135                 argtype = boolean_converter 
    136222            input_types[fi.params[i]] = argtype 
    137223         
     
    140226         
    141227        def newfunc(self, **kw): 
    142             # convert the input parameters to appropriate types 
    143             for key in kw: 
    144                 if key in input_types: 
    145                     try: 
    146                         kw[key] = input_types[key](kw[key]) 
    147                     except ValueError: 
    148                         raise validators.Invalid( 
    149                             "%s value for the '%s' parameter is not a " 
    150                             "valid %s" % (kw[key], key,  
    151                                          input_types[key].__name__),  
    152                             kw[key], None) 
    153                 else: 
    154                     raise validators.Invalid( 
    155                         "%s is not a valid parameter (valid values are: %s)" 
    156                         % (key, input_types.keys()), key, None 
    157                     ) 
     228            if "xml_body" in kw and len(kw) == 1: 
     229                body = kw.pop("xml_body") 
     230                kw = _handle_xml_params(body, input_types) 
     231            else: 
     232                _handle_keyword_params(kw, input_types) 
     233                 
    158234            return func(self, **kw) 
    159235        newfunc.__name__ = func.__name__ 
  • trunk/tgwebservices/soap.py

    r13 r19  
    190190        request.soap_method = methodname 
    191191         
    192         # pull out all of the parameters 
    193         params = {} 
    194         for paramelem in body.getchildren(): 
    195             paramname = namespace_expr.sub("", paramelem.tag) 
    196             val = paramelem.text 
    197             if val is None: 
    198                 val = "" 
    199             params[paramname] = val 
    200          
    201192        try: 
    202193            method = self.wscontroller._ws_funcs[methodname] 
     
    205196                                     methodname, methodname, None) 
    206197         
     198        fi = method._ws_func_info 
     199        input_types = fi.input_types 
     200         
     201        params = {"_tgws" : True} 
     202        if len(body.getchildren()): 
     203            params["xml_body"] = body 
     204         
    207205        # ensure that the requested method has actually been exposed 
    208206        assert hasattr(method, "exposed") and method.exposed == True 
     
    211209        # in wsexpose. We want to manage the produced dictionary here, because 
    212210        # we need to pass additional information on to the soap template. 
    213         params["_tgws"] = True 
    214211        output = method(**params) 
    215212        data = dict(baseURL=self.wscontroller._ws_baseURL, 
  • trunk/tgwebservices/tests/test_soap.py

    r13 r19  
    293293    output = run_soap("times2", """<value>whaleblubber</value>""") 
    294294    print cherrypy.response.status 
     295    print output 
    295296    assert cherrypy.response.status == "500 Invalid Input" 
    296     print output 
    297297    assert output == """<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Body><Fault><faultcode>Client</faultcode><faultstring>whaleblubber value for the 'value' parameter is not a valid int</faultstring></Fault></Body></Envelope>""" 
    298298 
     
    432432    print output 
    433433    assert "fault" not in output 
     434 
     435class Person(object): 
     436    name = str 
     437    age = int 
     438 
     439class ComplexInput(WebServicesRoot): 
     440    @wsexpose() 
     441    @wsvalidate(Person) 
     442    def savePerson(self, p): 
     443        self.person = p 
     444     
     445def test_complex_input_simple_object(): 
     446    ci = ComplexInput("http://foo.bar.baz/") 
     447    cherrypy.root = ci 
     448    output = run_soap("savePerson", """<p> 
     449    <name>George</name> 
     450    <age>280</age> 
     451</p>""") 
     452    print output 
     453    assert isinstance(ci.person, Person)