I have a working python program that is fetching a large volume of data via SOAP using suds. The web service is implemented with a paging function such that I can grab nnn rows with each fetch call and grab the next nnn with subsequent calls. If I authenticate to the HTTP server with code like the following
client = suds.client.Client(url=url, location=location, username=username, password=password, timeout=timeout)
everything works great. If, however, I use the following
t = suds.transport.https.HttpAuthenticated(username=username, password=password) t.handler = urllib2.HTTPBasicAuthHandler(t.pm) t.urlopener = urllib2.build_opener(t.handler) client = suds.client.Client(url=url, location=location, timeout=timeout, transport=t)
it works for exactly 6 iterations. That is if I specify a fetch limit of 10 rows per fetch, I get back 60 rows. On the seventh fetch, I receive
File "build/bdist.linux-i686/egg/suds/client.py", line 542, in __call__ File "build/bdist.linux-i686/egg/suds/client.py", line 602, in invoke File "build/bdist.linux-i686/egg/suds/client.py", line 649, in send File "build/bdist.linux-i686/egg/suds/client.py", line 698, in failed AttributeError: 'NoneType' object has no attribute 'read'
Does anyone have any suggestions as to what might be causing this. It is definitely this change that is causing the problem. I can swap authentication styles back and forth and it is completely reproducible.
I am running python 2.6.6 with suds 0.4.
Thanks
The problem seems to be that an urllib2.HTTPError
is being raised from a lower level, and its fp
attribute is None:
Line 81 in suds.transport.http
:
except u2.HTTPError, e:
if e.code in (202,204):
result = None
else:
raise TransportError(e.msg, e.code, e.fp)
That exception eventually gets passed to line 698 in suds.client
where that error.fp.read()
line blows up:
def failed(self, binding, error):
status, reason = (error.httpcode, tostr(error))
reply = error.fp.read()
I'd suggest monkey-patching the suds.SoapClient
class to get the HTTP error code and message. Add these lines before you construct your suds.Client
, then run it to see what HTTP error the 7th fetch raises:
class TestClient(suds.client.SoapClient):
def failed(self, binding, error):
print error.httpcode, error.args
suds.client.SoapClient = TestClient