Странное поведение при HTTP-аутентификации с использованием библиотеки suds SOAP - PullRequest
6 голосов
/ 05 марта 2011

У меня есть работающая программа на Python, которая извлекает большой объем данных через SOAP с использованием suds. Веб-сервис реализован с функцией подкачки, так что я могу захватывать nnn строк при каждом вызове выборки и получать следующие nnn с последующими вызовами. Если я аутентифицируюсь на сервере HTTP с кодом, подобным следующему

client = suds.client.Client(url=url, location=location, username=username, password=password, timeout=timeout)

все отлично работает. Если, однако, я использую следующее

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) 

это работает ровно за 6 итераций. То есть, если я укажу ограничение выборки в 10 строк на выборку, я получу обратно 60 строк. На седьмом выручке я получаю

  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'

Есть ли у кого-нибудь предложения относительно того, что может быть причиной этого. Именно это изменение вызывает проблему. Я могу менять стили аутентификации взад-вперед, и это полностью воспроизводимо.

Я использую Python 2.6.6 с suds 0.4.

Спасибо

1 Ответ

10 голосов
/ 07 марта 2011

Кажется, проблема в том, что urllib2.HTTPError поднимается с нижнего уровня, а его атрибут fp отсутствует:

Строка 81 в suds.transport.http:

except u2.HTTPError, e:
    if e.code in (202,204):
        result = None
    else:
        raise TransportError(e.msg, e.code, e.fp)

Это исключение в конечном итоге передается в строку 698 в suds.client, где взорвана эта строка error.fp.read():

def failed(self, binding, error):
    status, reason = (error.httpcode, tostr(error))
    reply = error.fp.read()

Я бы предложил сделать патч для обезьяны класса suds.SoapClient, чтобы получить код ошибки HTTPи сообщение.Добавьте эти строки перед созданием suds.Client, затем запустите его, чтобы увидеть, какую ошибку HTTP вызывает 7-я выборка:

class TestClient(suds.client.SoapClient):
    def failed(self, binding, error):
        print error.httpcode, error.args

suds.client.SoapClient = TestClient
...