Alexander, Thanks for the report.I rewrote the Options class in 0.3.7. There were a number of problems with the 0.3.6 (and earlier) version. The intention of the update() method was to provide a seamless integration between Options contained with the Transport and the main Options instance within the Client. For cases where users create a Transport, set transport related options, then pass the Transport to the Client in the constructor. Then a user changes a Transport option using Client.set_options() and it has no effect because the Transport has it's own Options object. So, the update() method was designed to find the Options attribute in the Transport and set it to itself. I know, kind of hacky :/
The main thing that is broken here is that the Options object contains a Transport _and_ the Transport contains a Options.
So, in 0.3.7, I refactored the Options class. The main suds.options.Options class contains general Suds client options and the suds.transport.Options class contains Transport related options. To support setting Transport related options via Client.set_options() (and visa versa actually), the refactored Options classes provides a mechanism to associate many options instances together creating one virtual Options domain. When accessing an option, though any of the Options instances, the request is forwarded to the "owner" of that option. This way, a user can do something like this and it will work as expected:
> > transport = HttpTransport(timeout=10) > client = Client(url, transport=transport) > # > # got the wsdl, now I need to set a proxy for invoking methods > # > proxy = dict(http='http://abc.com')) > client.set_options(proxy=proxy) > OR > > transport = HttpTransport(timeout=10) > client = Client(url, transport=transport) > # > # got the wsdl, now I need to set a proxy for invoking methods > # > proxy = dict(http='http://abc.com')) > transport.options.proxy=proxy >Also, most users run into the infinite recursion problem when trying to copy the client to be used for concurrent requests. 0.3.7 provides a Client.clone() method that, in conjuction with some tweaks in the Transport, provides a lightweight copy of the Cleint. It is lightweight because the clients share the WSDL/XSD objects but have their own transports and options.
I'm getting the release notes together now for 0.3.7 to be released soon. Hope this helps. Regards, Jeff On 10/11/2009 05:03 PM, Alexander Gattin wrote:
Hello, Options class has a controversial update(x) method, which finds all Options objects from x's children and tries to perform a merge (AFAIU) using Options.__setattr__(...). The latter method in turn calls update(...), which can cause recursion. def update(self, x): for attr, options in self.optattrs(x): if options == self: continue for k in options.__defined__: v = options.get(k) setattr(self, k, v) setattr(x, attr, self) def __setattr__(self, name, value): builtin = name.startswith('__') and name.endswith('__') if not builtin: self.__constraint__.validate(name, value) value = self.default(name, value) self.__defined__.add(name) self.update(value) self.__dict__[name] = value I'm sending a POC code and exception trace. The code creates 2 Client objects referring to the same Transport instance (t). 1st Client object (foowscl) gets created OK, but the second Client (barwscl) triggers infinite recursion by calling barwscloptions.set(**kwargs), and then barwscl.options.__setattr__('transport', t) The barwscl.options.__setattr__('transport', t) calls barwscl.options.update(t), which finds t.options object of class Options. The interesting thing here is that the t.options refers to the foowscl.options instance, foowscl.options != barwscl.options, and the foowscl.options already contains "defined" ('transport' => t) item... So the barwscl.options.update(t) calls setattr(barwscl.options, 'transport', t) => barwscl.options.__setattr__('transport', t) Loop. P.S. I don't understand why the merge is necessary in the first place. Why not just let the parent/child objects to have their own sets of options?
Description: S/MIME Cryptographic Signature