wiki:Api3Proposal
Last modified 5 years ago Last modified on 09/01/09 19:55:29

API3

STATUS

Released in 0.3.3.

SUMMARY

There have been several requests for suds to support named (keyword) arguments in service method calls.

>
> client.service.foo(name='myname', age=44)
>

This is very useful because methods with lots of optional arguments require well placed (None) arguments in order by pass the arguments you want positionally. And it would be convenient to do the following:

>
> d = dict(name='myname', age=44)
> client.service.foo(**d)
>

In general, this would be very simple to implement. However, suds (as you well know) already has special keywords that are used to set options:

  • headers - used to set the http headers
  • soapheaders - used to set the soap headers.
  • location - used to override the location (url) in the wsdl.
  • inject - used to inject either the output message or inbound reply.

As of 0.3.2, any keyword set on the Method.__call__() can be set on the Client constructor. Also, the following methods were added on the Client:

  • setheaders() - sets both http/soap headers. (equals: headers & soapheaders keywords).
  • setlocation() - overrides location in wsdl. (equals: location keyword).
  • setproxy() - set the web proxy (equals: proxy keyword)

In most cases, I believe that most users will set the http & soap headers and override the location once on the Client and not using the Method.call() keywords because they apply to all methods.

ISSUES

The only issue is dealing with keyword name collisions. If a service method defined a parameter named "location" it would collide with the suds special keyword "location" for overriding the url. Now, there are several ways to deal with this. But, all of them require a change in the API.

PROPOSAL

Change the API to support named arguments to service method invocations. While we're at it, let's consolidate the way options are set on the client. Then consider all kwargs passed during service method invocation ( Method.__call__() ) as named parameters to be applied to service method parameters.

Named Arguments

  • Remove all keywords from Method.__call__() except "inject" which would change to __inject
  • Add Client.set_options(options) method that supports all options and remove Client methods that set individual options. These options would continue to be supported in the Client.__init__(). Supported options (keywords) would be as follows:
    • faults - The same as current faults keyword on Client constructor.
    • proxy - The same as current proxy keyword on Client constructor and replaces Client.setproxy().
    • port - Set the default service port (not tcp port) and replaces Client.setport()
    • location - The same as current location keyword and replaces Client.setlocation()
    • headers - The same as current headers keyword and replaces Client.setheaders()
    • soapheaders - The same as current soapheaders keyword and replaces Client.setheaders()
    • transport - The transport to be used.
    • username - A user name to be used for authentication.
    • password - A password to be used for authentication.
  • Remove option specific methods from Client:
    • setport()
    • setproxy()
    • setlocation()
    • setheaders()
  • Change Client.addprefix() to Client.add_prefix() for consistent style.

Pluggable Transport

There have been several requests to factor-out the transport (currently this is urllib2) as to support user defined transports that may be based on libraries other then urllib2.

  • Add transport.py module provides:
    • Transport interface class. Handles all transport duties (including: cookies & proxies)
      • open() - open url and return input stream.
      • send() - send message and reply buffer.
    • TransportError class - replaces urllib2 specific HTTPError
    • Request class - Transport request used by Transport
      • url - The url to be used for the request.
      • headers - (optional) http headers for the request.
      • message = (optional) message to be sent as part of a (post) request.
    • HttpTransport class - Reference (default) implementation based on current urllib2.
    • HttpAuthenticated class - Reference (default) implementation based on current urllib2 and provides basic http authentication.
  • All references to urllib2 removed from core and replace with Transport object.
  • Users can plug-in there own transport as:
    >
    > class MyTransport(Transport):
    >    ...
    > mytrans = MyTransport()
    > client = Client(url, transport=mytrans)
    > # or
    > client = Client(url)
    > client.set_options(transport=mytrans)
    > 
    

Http authentication will change slightly. Instead of passing the opener, users will either create a subclass of HttpTransport and replace the urlopener or get the HttpTransport already installed and set the urlopener. Or, use the username & password options as:

>
> client = Client(url, username='xx', password='yy')
> 

BACKWARDS COMPATIBILITY

We can support several versions of the API. Currently, suds has (2) versions. The ServiceProxy (serviceproxy.py) and the Client (client.py) so I'd rather not add a third. But, if consensus is that the proposed API change will have high impact and that we need to support the current API as well for a period of time, the proposed NEWAPI could be provided in Client class in client.py and a new module client1.py could be added containing the current Client class. Alternatively, a new package could be added named, "legacy" or "deprecated" and the current client.py and serviceproxy.py could be moved there. Either way, users wanting to use the old APIs would simply have to change the import to import the old API of choice.

Although, IMHO: given proper notice, user should be able to adapt to small API changes when upgrading to a new version.