Не удается прочитать сообщение об ошибке urllib после его чтения ()

Моя проблема связана с обработкой ошибок объекта ошибки python urllib. Я не могу прочитать сообщение об ошибке, сохранив его нетронутым в объекте ошибки, чтобы его можно было использовать позже.

response = urllib.request.urlopen(request) # request that will raise an error
response.read()
response.read() # is empty now
# Also tried seek(0), that does not work either.

Вот как я собираюсь его использовать, но когда всплывает исключение, второй раз становится пустым.

try:
    response = urllib.request.urlopen(request)
except urllib.error.HTTPError as err:
    self.log.exception(err.read())
    raise err

Я попытался сделать глубокую копию объекта с ошибкой,

import copy
try:
    response = urllib.request.urlopen(request)
except urllib.error.HTTPError as err:
    err_obj_copy = copy.deepcopy(err)
    self.log.exception(
        "Method:{}\n"
        "URL:{}\n"
        "Data:{}\n"
        "Details:{}\n"
        "Headers:{}".format(method, url, data, err_obj_copy.read(), headers))
    raise err

но копия не может сделать глубокую копию и выдает ошибку - TypeError: __init__() missing 5 required positional arguments: 'url', 'code', 'msg', 'hdrs', and 'fp'.

Как прочитать сообщение об ошибке, сохранив его в объекте?

Я знаю, как это сделать с помощью requests, но я застрял с устаревшим кодом, и мне нужно заставить его работать с urllib


person Amey    schedule 11.11.2015    source источник


Ответы (2)


Вот что я сделал. Работал у меня.

При первом чтении ошибки сохраните ее в такой переменной: msg = response.read().decode('utf8'). Затем вы можете создать новый экземпляр HTTPError с сообщением и распространить его.

resp = urllib.request.urlopen(request)
msg = resp.read().decode('utf8')
self.log.exception(msg)
raise HTTPError(resp.url, resp.code, resp.reason, resp.headers, io.BytesIO(bytes(msg, 'utf8')))
person Floyd Kots    schedule 29.01.2017
comment
Вы должны сохранить результат resp.read(), чтобы передать необработанные байты обратно в HTTPError вместо повторного кодирования текста. См. Ответ @ jf выше. - person reubano; 29.01.2017
comment
Спасибо @reubano. Конечно, так лучше. Я не понимаю, почему сначала, когда я пытался передать необработанные байты, переменная msg оставалась пустым объектом bytestring. Я, должно быть, делал что-то не так. Думаю, поэтому я расшифровал bytestring. - person Floyd Kots; 29.01.2017

Объект ошибки может считываться из сети. Сеть недоступна для поиска - в общем случае вы не можете вернуться назад.

Вы можете заменить err новым экземпляром HTTPError, который читает из буфера (например, io.BytesIO()) вместо сети, например, (не проверено):

content = err.read()
self.log.exception(content)
raise HTTPError(err.url, err.code, err.reason, err.headers, io.BytesIO(content))

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

person jfs    schedule 11.11.2015