Package suds :: Module client
[hide private]
[frames] | no frames]

Source Code for Module suds.client

  1  # This program is free software; you can redistribute it and/or modify 
  2  # it under the terms of the (LGPL) GNU Lesser General Public License as 
  3  # published by the Free Software Foundation; either version 3 of the  
  4  # License, or (at your option) any later version. 
  5  # 
  6  # This program is distributed in the hope that it will be useful, 
  7  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  8  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  9  # GNU Library Lesser General Public License for more details at 
 10  # ( http://www.gnu.org/licenses/lgpl.html ). 
 11  # 
 12  # You should have received a copy of the GNU Lesser General Public License 
 13  # along with this program; if not, write to the Free Software 
 14  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 15  # written by: Jeff Ortel ( jortel@redhat.com ) 
 16   
 17  """ 
 18  The I{2nd generation} service proxy provides access to web services. 
 19  See I{README.txt} 
 20  """ 
 21   
 22  import suds 
 23  import suds.metrics as metrics 
 24  from cookielib import CookieJar 
 25  from suds import * 
 26  from suds.reader import DefinitionsReader 
 27  from suds.transport import TransportError, Request 
 28  from suds.transport.https import HttpAuthenticated 
 29  from suds.servicedefinition import ServiceDefinition 
 30  from suds import sudsobject 
 31  from sudsobject import Factory as InstFactory 
 32  from sudsobject import Object 
 33  from suds.resolver import PathResolver 
 34  from suds.builder import Builder 
 35  from suds.wsdl import Definitions 
 36  from suds.cache import ObjectCache 
 37  from suds.sax.document import Document 
 38  from suds.sax.parser import Parser 
 39  from suds.options import Options 
 40  from suds.properties import Unskin 
 41  from urlparse import urlparse 
 42  from copy import deepcopy 
 43  from suds.plugin import PluginContainer 
 44  from logging import getLogger 
 45   
 46  log = getLogger(__name__) 
47 48 49 -class Client(object):
50 """ 51 A lightweight web services client. 52 I{(2nd generation)} API. 53 @ivar wsdl: The WSDL object. 54 @type wsdl:L{Definitions} 55 @ivar service: The service proxy used to invoke operations. 56 @type service: L{Service} 57 @ivar factory: The factory used to create objects. 58 @type factory: L{Factory} 59 @ivar sd: The service definition 60 @type sd: L{ServiceDefinition} 61 @ivar messages: The last sent/received messages. 62 @type messages: str[2] 63 """ 64 @classmethod
65 - def items(cls, sobject):
66 """ 67 Extract the I{items} from a suds object much like the 68 items() method works on I{dict}. 69 @param sobject: A suds object 70 @type sobject: L{Object} 71 @return: A list of items contained in I{sobject}. 72 @rtype: [(key, value),...] 73 """ 74 return sudsobject.items(sobject)
75 76 @classmethod
77 - def dict(cls, sobject):
78 """ 79 Convert a sudsobject into a dictionary. 80 @param sobject: A suds object 81 @type sobject: L{Object} 82 @return: A python dictionary containing the 83 items contained in I{sobject}. 84 @rtype: dict 85 """ 86 return sudsobject.asdict(sobject)
87 88 @classmethod
89 - def metadata(cls, sobject):
90 """ 91 Extract the metadata from a suds object. 92 @param sobject: A suds object 93 @type sobject: L{Object} 94 @return: The object's metadata 95 @rtype: L{sudsobject.Metadata} 96 """ 97 return sobject.__metadata__
98
99 - def __init__(self, url, **kwargs):
100 """ 101 @param url: The URL for the WSDL. 102 @type url: str 103 @param kwargs: keyword arguments. 104 @see: L{Options} 105 """ 106 options = Options() 107 options.transport = HttpAuthenticated() 108 self.options = options 109 options.cache = ObjectCache(days=1) 110 self.set_options(**kwargs) 111 reader = DefinitionsReader(options, Definitions) 112 self.wsdl = reader.open(url) 113 plugins = PluginContainer(options.plugins) 114 plugins.init.initialized(wsdl=self.wsdl) 115 self.factory = Factory(self.wsdl) 116 self.service = ServiceSelector(self, self.wsdl.services) 117 self.sd = [] 118 for s in self.wsdl.services: 119 sd = ServiceDefinition(self.wsdl, s) 120 self.sd.append(sd) 121 self.messages = dict(tx=None, rx=None)
122
123 - def set_options(self, **kwargs):
124 """ 125 Set options. 126 @param kwargs: keyword arguments. 127 @see: L{Options} 128 """ 129 p = Unskin(self.options) 130 p.update(kwargs)
131
132 - def add_prefix(self, prefix, uri):
133 """ 134 Add I{static} mapping of an XML namespace prefix to a namespace. 135 This is useful for cases when a wsdl and referenced schemas make heavy 136 use of namespaces and those namespaces are subject to changed. 137 @param prefix: An XML namespace prefix. 138 @type prefix: str 139 @param uri: An XML namespace URI. 140 @type uri: str 141 @raise Exception: when prefix is already mapped. 142 """ 143 root = self.wsdl.root 144 mapped = root.resolvePrefix(prefix, None) 145 if mapped is None: 146 root.addPrefix(prefix, uri) 147 return 148 if mapped[1] != uri: 149 raise Exception('"%s" already mapped as "%s"' % (prefix, mapped))
150
151 - def last_sent(self):
152 """ 153 Get last sent I{soap} message. 154 @return: The last sent I{soap} message. 155 @rtype: L{Document} 156 """ 157 return self.messages.get('tx')
158
159 - def last_received(self):
160 """ 161 Get last received I{soap} message. 162 @return: The last received I{soap} message. 163 @rtype: L{Document} 164 """ 165 return self.messages.get('rx')
166
167 - def clone(self):
168 """ 169 Get a shallow clone of this object. 170 The clone only shares the WSDL. All other attributes are 171 unique to the cloned object including options. 172 @return: A shallow clone. 173 @rtype: L{Client} 174 """ 175 class Uninitialized(Client): 176 def __init__(self): 177 pass
178 clone = Uninitialized() 179 clone.options = Options() 180 cp = Unskin(clone.options) 181 mp = Unskin(self.options) 182 cp.update(deepcopy(mp)) 183 clone.wsdl = self.wsdl 184 clone.factory = self.factory 185 clone.service = ServiceSelector(clone, self.wsdl.services) 186 clone.sd = self.sd 187 clone.messages = dict(tx=None, rx=None) 188 return clone 189
190 - def __str__(self):
191 return unicode(self)
192
193 - def __unicode__(self):
194 s = ['\n'] 195 build = suds.__build__.split() 196 s.append('Suds ( https://fedorahosted.org/suds/ )') 197 s.append(' version: %s' % suds.__version__) 198 s.append(' %s build: %s' % (build[0], build[1])) 199 for sd in self.sd: 200 s.append('\n\n%s' % unicode(sd)) 201 return ''.join(s)
202
203 204 -class Factory:
205 """ 206 A factory for instantiating types defined in the wsdl 207 @ivar resolver: A schema type resolver. 208 @type resolver: L{PathResolver} 209 @ivar builder: A schema object builder. 210 @type builder: L{Builder} 211 """ 212
213 - def __init__(self, wsdl):
214 """ 215 @param wsdl: A schema object. 216 @type wsdl: L{wsdl.Definitions} 217 """ 218 self.wsdl = wsdl 219 self.resolver = PathResolver(wsdl) 220 self.builder = Builder(self.resolver)
221
222 - def create(self, name):
223 """ 224 create a WSDL type by name 225 @param name: The name of a type defined in the WSDL. 226 @type name: str 227 @return: The requested object. 228 @rtype: L{Object} 229 """ 230 timer = metrics.Timer() 231 timer.start() 232 type = self.resolver.find(name) 233 if type is None: 234 raise TypeNotFound(name) 235 if type.enum(): 236 result = InstFactory.object(name) 237 for e, a in type.children(): 238 setattr(result, e.name, e.name) 239 else: 240 try: 241 result = self.builder.build(type) 242 except Exception, e: 243 log.error("create '%s' failed", name, exc_info=True) 244 raise BuildError(name, e) 245 timer.stop() 246 metrics.log.debug('%s created: %s', name, timer) 247 return result
248
249 - def separator(self, ps):
250 """ 251 Set the path separator. 252 @param ps: The new path separator. 253 @type ps: char 254 """ 255 self.resolver = PathResolver(self.wsdl, ps)
256
257 258 -class ServiceSelector:
259 """ 260 The B{service} selector is used to select a web service. 261 In most cases, the wsdl only defines (1) service in which access 262 by subscript is passed through to a L{PortSelector}. This is also the 263 behavior when a I{default} service has been specified. In cases 264 where multiple services have been defined and no default has been 265 specified, the service is found by name (or index) and a L{PortSelector} 266 for the service is returned. In all cases, attribute access is 267 forwarded to the L{PortSelector} for either the I{first} service or the 268 I{default} service (when specified). 269 @ivar __client: A suds client. 270 @type __client: L{Client} 271 @ivar __services: A list of I{wsdl} services. 272 @type __services: list 273 """
274 - def __init__(self, client, services):
275 """ 276 @param client: A suds client. 277 @type client: L{Client} 278 @param services: A list of I{wsdl} services. 279 @type services: list 280 """ 281 self.__client = client 282 self.__services = services
283
284 - def __getattr__(self, name):
285 """ 286 Request to access an attribute is forwarded to the 287 L{PortSelector} for either the I{first} service or the 288 I{default} service (when specified). 289 @param name: The name of a method. 290 @type name: str 291 @return: A L{PortSelector}. 292 @rtype: L{PortSelector}. 293 """ 294 default = self.__ds() 295 if default is None: 296 port = self.__find(0) 297 else: 298 port = default 299 return getattr(port, name)
300
301 - def __getitem__(self, name):
302 """ 303 Provides selection of the I{service} by name (string) or 304 index (integer). In cases where only (1) service is defined 305 or a I{default} has been specified, the request is forwarded 306 to the L{PortSelector}. 307 @param name: The name (or index) of a service. 308 @type name: (int|str) 309 @return: A L{PortSelector} for the specified service. 310 @rtype: L{PortSelector}. 311 """ 312 if len(self.__services) == 1: 313 port = self.__find(0) 314 return port[name] 315 default = self.__ds() 316 if default is not None: 317 port = default 318 return port[name] 319 return self.__find(name)
320
321 - def __find(self, name):
322 """ 323 Find a I{service} by name (string) or index (integer). 324 @param name: The name (or index) of a service. 325 @type name: (int|str) 326 @return: A L{PortSelector} for the found service. 327 @rtype: L{PortSelector}. 328 """ 329 service = None 330 if not len(self.__services): 331 raise Exception, 'No services defined' 332 if isinstance(name, int): 333 try: 334 service = self.__services[name] 335 name = service.name 336 except IndexError: 337 raise ServiceNotFound, 'at [%d]' % name 338 else: 339 for s in self.__services: 340 if name == s.name: 341 service = s 342 break 343 if service is None: 344 raise ServiceNotFound, name 345 return PortSelector(self.__client, service.ports, name)
346
347 - def __ds(self):
348 """ 349 Get the I{default} service if defined in the I{options}. 350 @return: A L{PortSelector} for the I{default} service. 351 @rtype: L{PortSelector}. 352 """ 353 ds = self.__client.options.service 354 if ds is None: 355 return None 356 else: 357 return self.__find(ds)
358
359 360 -class PortSelector:
361 """ 362 The B{port} selector is used to select a I{web service} B{port}. 363 In cases where multiple ports have been defined and no default has been 364 specified, the port is found by name (or index) and a L{MethodSelector} 365 for the port is returned. In all cases, attribute access is 366 forwarded to the L{MethodSelector} for either the I{first} port or the 367 I{default} port (when specified). 368 @ivar __client: A suds client. 369 @type __client: L{Client} 370 @ivar __ports: A list of I{service} ports. 371 @type __ports: list 372 @ivar __qn: The I{qualified} name of the port (used for logging). 373 @type __qn: str 374 """
375 - def __init__(self, client, ports, qn):
376 """ 377 @param client: A suds client. 378 @type client: L{Client} 379 @param ports: A list of I{service} ports. 380 @type ports: list 381 @param qn: The name of the service. 382 @type qn: str 383 """ 384 self.__client = client 385 self.__ports = ports 386 self.__qn = qn
387
388 - def __getattr__(self, name):
389 """ 390 Request to access an attribute is forwarded to the 391 L{MethodSelector} for either the I{first} port or the 392 I{default} port (when specified). 393 @param name: The name of a method. 394 @type name: str 395 @return: A L{MethodSelector}. 396 @rtype: L{MethodSelector}. 397 """ 398 default = self.__dp() 399 if default is None: 400 m = self.__find(0) 401 else: 402 m = default 403 return getattr(m, name)
404
405 - def __getitem__(self, name):
406 """ 407 Provides selection of the I{port} by name (string) or 408 index (integer). In cases where only (1) port is defined 409 or a I{default} has been specified, the request is forwarded 410 to the L{MethodSelector}. 411 @param name: The name (or index) of a port. 412 @type name: (int|str) 413 @return: A L{MethodSelector} for the specified port. 414 @rtype: L{MethodSelector}. 415 """ 416 default = self.__dp() 417 if default is None: 418 return self.__find(name) 419 else: 420 return default
421
422 - def __find(self, name):
423 """ 424 Find a I{port} by name (string) or index (integer). 425 @param name: The name (or index) of a port. 426 @type name: (int|str) 427 @return: A L{MethodSelector} for the found port. 428 @rtype: L{MethodSelector}. 429 """ 430 port = None 431 if not len(self.__ports): 432 raise Exception, 'No ports defined: %s' % self.__qn 433 if isinstance(name, int): 434 qn = '%s[%d]' % (self.__qn, name) 435 try: 436 port = self.__ports[name] 437 except IndexError: 438 raise PortNotFound, qn 439 else: 440 qn = '.'.join((self.__qn, name)) 441 for p in self.__ports: 442 if name == p.name: 443 port = p 444 break 445 if port is None: 446 raise PortNotFound, qn 447 qn = '.'.join((self.__qn, port.name)) 448 return MethodSelector(self.__client, port.methods, qn)
449
450 - def __dp(self):
451 """ 452 Get the I{default} port if defined in the I{options}. 453 @return: A L{MethodSelector} for the I{default} port. 454 @rtype: L{MethodSelector}. 455 """ 456 dp = self.__client.options.port 457 if dp is None: 458 return None 459 else: 460 return self.__find(dp)
461
462 463 -class MethodSelector:
464 """ 465 The B{method} selector is used to select a B{method} by name. 466 @ivar __client: A suds client. 467 @type __client: L{Client} 468 @ivar __methods: A dictionary of methods. 469 @type __methods: dict 470 @ivar __qn: The I{qualified} name of the method (used for logging). 471 @type __qn: str 472 """
473 - def __init__(self, client, methods, qn):
474 """ 475 @param client: A suds client. 476 @type client: L{Client} 477 @param methods: A dictionary of methods. 478 @type methods: dict 479 @param qn: The I{qualified} name of the port. 480 @type qn: str 481 """ 482 self.__client = client 483 self.__methods = methods 484 self.__qn = qn
485
486 - def __getattr__(self, name):
487 """ 488 Get a method by name and return it in an I{execution wrapper}. 489 @param name: The name of a method. 490 @type name: str 491 @return: An I{execution wrapper} for the specified method name. 492 @rtype: L{Method} 493 """ 494 return self[name]
495
496 - def __getitem__(self, name):
497 """ 498 Get a method by name and return it in an I{execution wrapper}. 499 @param name: The name of a method. 500 @type name: str 501 @return: An I{execution wrapper} for the specified method name. 502 @rtype: L{Method} 503 """ 504 m = self.__methods.get(name) 505 if m is None: 506 qn = '.'.join((self.__qn, name)) 507 raise MethodNotFound, qn 508 return Method(self.__client, m)
509
510 511 -class Method:
512 """ 513 The I{method} (namespace) object. 514 @ivar client: A client object. 515 @type client: L{Client} 516 @ivar method: A I{wsdl} method. 517 @type I{wsdl} Method. 518 """ 519
520 - def __init__(self, client, method):
521 """ 522 @param client: A client object. 523 @type client: L{Client} 524 @param method: A I{raw} method. 525 @type I{raw} Method. 526 """ 527 self.client = client 528 self.method = method
529
530 - def __call__(self, *args, **kwargs):
531 """ 532 Invoke the method. 533 """ 534 clientclass = self.clientclass(kwargs) 535 client = clientclass(self.client, self.method) 536 if not self.faults(): 537 try: 538 return client.invoke(args, kwargs) 539 except WebFault, e: 540 return (500, e) 541 else: 542 return client.invoke(args, kwargs)
543
544 - def faults(self):
545 """ get faults option """ 546 return self.client.options.faults
547
548 - def clientclass(self, kwargs):
549 """ get soap client class """ 550 if SimClient.simulation(kwargs): 551 return SimClient 552 else: 553 return SoapClient
554
555 556 -class SoapClient:
557 """ 558 A lightweight soap based web client B{**not intended for external use} 559 @ivar service: The target method. 560 @type service: L{Service} 561 @ivar method: A target method. 562 @type method: L{Method} 563 @ivar options: A dictonary of options. 564 @type options: dict 565 @ivar cookiejar: A cookie jar. 566 @type cookiejar: libcookie.CookieJar 567 """ 568
569 - def __init__(self, client, method):
570 """ 571 @param client: A suds client. 572 @type client: L{Client} 573 @param method: A target method. 574 @type method: L{Method} 575 """ 576 self.client = client 577 self.method = method 578 self.options = client.options 579 self.cookiejar = CookieJar()
580
581 - def invoke(self, args, kwargs):
582 """ 583 Send the required soap message to invoke the specified method 584 @param args: A list of args for the method invoked. 585 @type args: list 586 @param kwargs: Named (keyword) args for the method invoked. 587 @type kwargs: dict 588 @return: The result of the method invocation. 589 @rtype: I{builtin}|I{subclass of} L{Object} 590 """ 591 timer = metrics.Timer() 592 timer.start() 593 result = None 594 binding = self.method.binding.input 595 soapenv = binding.get_message(self.method, args, kwargs) 596 timer.stop() 597 metrics.log.debug( 598 "message for '%s' created: %s", 599 self.method.name, 600 timer) 601 timer.start() 602 result = self.send(soapenv) 603 timer.stop() 604 metrics.log.debug( 605 "method '%s' invoked: %s", 606 self.method.name, 607 timer) 608 return result
609
610 - def send(self, soapenv):
611 """ 612 Send soap message. 613 @param soapenv: A soap envelope to send. 614 @type soapenv: L{Document} 615 @return: The reply to the sent message. 616 @rtype: I{builtin} or I{subclass of} L{Object} 617 """ 618 result = None 619 location = self.location() 620 binding = self.method.binding.input 621 transport = self.options.transport 622 retxml = self.options.retxml 623 nosend = self.options.nosend 624 prettyxml = self.options.prettyxml 625 timer = metrics.Timer() 626 log.debug('sending to (%s)\nmessage:\n%s', location, soapenv) 627 try: 628 self.last_sent(soapenv) 629 plugins = PluginContainer(self.options.plugins) 630 plugins.message.marshalled(envelope=soapenv.root()) 631 if prettyxml: 632 soapenv = soapenv.str() 633 else: 634 soapenv = soapenv.plain() 635 soapenv = soapenv.encode('utf-8') 636 ctx = plugins.message.sending(envelope=soapenv) 637 soapenv = ctx.envelope 638 if nosend: 639 return RequestContext(self, binding, soapenv) 640 request = Request(location, soapenv) 641 request.headers = self.headers() 642 timer.start() 643 reply = transport.send(request) 644 timer.stop() 645 metrics.log.debug('waited %s on server reply', timer) 646 ctx = plugins.message.received(reply=reply.message) 647 reply.message = ctx.reply 648 if retxml: 649 result = reply.message 650 else: 651 result = self.succeeded(binding, reply.message) 652 except TransportError, e: 653 if e.httpcode in (202,204): 654 result = None 655 else: 656 log.error(self.last_sent()) 657 result = self.failed(binding, e) 658 return result
659
660 - def headers(self):
661 """ 662 Get http headers or the http/https request. 663 @return: A dictionary of header/values. 664 @rtype: dict 665 """ 666 action = self.method.soap.action 667 if isinstance(action, unicode): 668 action = action.encode('utf-8') 669 stock = { 'Content-Type' : 'text/xml; charset=utf-8', 'SOAPAction': action } 670 result = dict(stock, **self.options.headers) 671 log.debug('headers = %s', result) 672 return result
673
674 - def succeeded(self, binding, reply):
675 """ 676 Request succeeded, process the reply 677 @param binding: The binding to be used to process the reply. 678 @type binding: L{bindings.binding.Binding} 679 @param reply: The raw reply text. 680 @type reply: str 681 @return: The method result. 682 @rtype: I{builtin}, L{Object} 683 @raise WebFault: On server. 684 """ 685 log.debug('http succeeded:\n%s', reply) 686 plugins = PluginContainer(self.options.plugins) 687 if len(reply) > 0: 688 reply, result = binding.get_reply(self.method, reply) 689 self.last_received(reply) 690 else: 691 result = None 692 ctx = plugins.message.unmarshalled(reply=result) 693 result = ctx.reply 694 if self.options.faults: 695 return result 696 else: 697 return (200, result)
698
699 - def failed(self, binding, error):
700 """ 701 Request failed, process reply based on reason 702 @param binding: The binding to be used to process the reply. 703 @type binding: L{suds.bindings.binding.Binding} 704 @param error: The http error message 705 @type error: L{transport.TransportError} 706 """ 707 status, reason = (error.httpcode, tostr(error)) 708 reply = error.fp.read() 709 log.debug('http failed:\n%s', reply) 710 if status == 500: 711 if len(reply) > 0: 712 r, p = binding.get_fault(reply) 713 self.last_received(r) 714 return (status, p) 715 else: 716 return (status, None) 717 if self.options.faults: 718 raise Exception((status, reason)) 719 else: 720 return (status, None)
721
722 - def location(self):
723 p = Unskin(self.options) 724 return p.get('location', self.method.location)
725
726 - def last_sent(self, d=None):
727 key = 'tx' 728 messages = self.client.messages 729 if d is None: 730 return messages.get(key) 731 else: 732 messages[key] = d
733
734 - def last_received(self, d=None):
735 key = 'rx' 736 messages = self.client.messages 737 if d is None: 738 return messages.get(key) 739 else: 740 messages[key] = d
741
742 743 -class SimClient(SoapClient):
744 """ 745 Loopback client used for message/reply simulation. 746 """ 747 748 injkey = '__inject' 749 750 @classmethod
751 - def simulation(cls, kwargs):
752 """ get whether loopback has been specified in the I{kwargs}. """ 753 return kwargs.has_key(SimClient.injkey)
754
755 - def invoke(self, args, kwargs):
756 """ 757 Send the required soap message to invoke the specified method 758 @param args: A list of args for the method invoked. 759 @type args: list 760 @param kwargs: Named (keyword) args for the method invoked. 761 @type kwargs: dict 762 @return: The result of the method invocation. 763 @rtype: I{builtin} or I{subclass of} L{Object} 764 """ 765 simulation = kwargs[self.injkey] 766 msg = simulation.get('msg') 767 reply = simulation.get('reply') 768 fault = simulation.get('fault') 769 if msg is None: 770 if reply is not None: 771 return self.__reply(reply, args, kwargs) 772 if fault is not None: 773 return self.__fault(fault) 774 raise Exception('(reply|fault) expected when msg=None') 775 sax = Parser() 776 msg = sax.parse(string=msg) 777 return self.send(msg)
778
779 - def __reply(self, reply, args, kwargs):
780 """ simulate the reply """ 781 binding = self.method.binding.input 782 msg = binding.get_message(self.method, args, kwargs) 783 log.debug('inject (simulated) send message:\n%s', msg) 784 binding = self.method.binding.output 785 return self.succeeded(binding, reply)
786
787 - def __fault(self, reply):
788 """ simulate the (fault) reply """ 789 binding = self.method.binding.output 790 if self.options.faults: 791 r, p = binding.get_fault(reply) 792 self.last_received(r) 793 return (500, p) 794 else: 795 return (500, None)
796
797 798 -class RequestContext:
799 """ 800 A request context. 801 Returned when the ''nosend'' options is specified. 802 @ivar client: The suds client. 803 @type client: L{Client} 804 @ivar binding: The binding for this request. 805 @type binding: I{Binding} 806 @ivar envelope: The request soap envelope. 807 @type envelope: str 808 """ 809
810 - def __init__(self, client, binding, envelope):
811 """ 812 @param client: The suds client. 813 @type client: L{Client} 814 @param binding: The binding for this request. 815 @type binding: I{Binding} 816 @param envelope: The request soap envelope. 817 @type envelope: str 818 """ 819 self.client = client 820 self.binding = binding 821 self.envelope = envelope
822
823 - def succeeded(self, reply):
824 """ 825 Re-entry for processing a successful reply. 826 @param reply: The reply soap envelope. 827 @type reply: str 828 @return: The returned value for the invoked method. 829 @rtype: object 830 """ 831 options = self.client.options 832 plugins = PluginContainer(options.plugins) 833 ctx = plugins.message.received(reply=reply) 834 reply = ctx.reply 835 return self.client.succeeded(self.binding, reply)
836
837 - def failed(self, error):
838 """ 839 Re-entry for processing a failure reply. 840 @param error: The error returned by the transport. 841 @type error: A suds I{TransportError}. 842 """ 843 return self.client.failed(self.binding, error)
844