AttributeError: у объекта 'str' нет атрибута 'errno' - PullRequest
5 голосов
/ 20 сентября 2019

Я поместил исключение ClientConnectionError в multiprocessing.Queue, которое было сгенерировано asyncio.Я сделал это, чтобы передать исключение, сгенерированное в asyncio land, клиенту в другом потоке / процессе.

Я предполагаю, что это исключение произошло во время процесса десериализации при чтении исключения из очереди.Похоже, что в противном случае достичь этого невозможно.

Traceback (most recent call last):
  File "model_neural_simplified.py", line 318, in <module>
    main(**arg_parser())
  File "model_neural_simplified.py", line 314, in main
    globals()[command](**kwargs)
  File "model_neural_simplified.py", line 304, in predict
    next_neural_data, next_sample = reader.get_next_result()
  File "/project_neural_mouse/src/asyncs3/s3reader.py", line 174, in get_next_result
    result = future.result()
  File "/usr/lib/python3.6/concurrent/futures/_base.py", line 432, in result
    return self.__get_result()
  File "/usr/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
    raise self._exception
  File "/usr/lib/python3.6/concurrent/futures/thread.py", line 56, in run
    result = self.fn(*self.args, **self.kwargs)
  File "model_neural_simplified.py", line 245, in read_sample
    f_bytes = s3f.read(read_size)
  File "/project_neural_mouse/src/asyncs3/s3reader.py", line 374, in read
    size, b = self._issue_request(S3Reader.READ, (self.url, size, self.position))
  File "/project_neural_mouse/src/asyncs3/s3reader.py", line 389, in _issue_request
    response = self.communication_channels[uuid].get()
  File "/usr/lib/python3.6/multiprocessing/queues.py", line 113, in get
    return _ForkingPickler.loads(res)
  File "/usr/local/lib/python3.6/dist-packages/aiohttp/client_exceptions.py", line 133, in __init__
    super().__init__(os_error.errno, os_error.strerror)
AttributeError: 'str' object has no attribute 'errno'

Я полагаю, что это длинный вопрос, но кто-нибудь знает что-нибудь об этой проблеме?

Python 3.6.8,aiohttp .__ version__ == 3.6.0

Обновление:

Мне удалось воспроизвести проблему (благодарность Самуэлю в комментариях за улучшение минимального воспроизводимого контрольного примера и более позднюю xtreak при ошибках.python.org для дальнейшей перегонки в тестовый набор только для рассола):

import pickle

ose = OSError(1, 'unittest')

class SubOSError(OSError):

    def __init__(self, foo, os_error):
        super().__init__(os_error.errno, os_error.strerror)

cce = SubOSError(1, ose)
cce_pickled = pickle.dumps(cce)
pickle.loads(cce_pickled)


./python.exe ../backups/bpo38254.py
Traceback (most recent call last):
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/../backups/bpo38254.py", line 12, in <module>
    pickle.loads(cce_pickled)
  File "/Users/karthikeyansingaravelan/stuff/python/cpython/../backups/bpo38254.py", line 8, in __init__
    super().__init__(os_error.errno, os_error.strerror)
AttributeError: 'str' object has no attribute 'errno'

Ссылки:

Ответы [ 2 ]

3 голосов
/ 24 сентября 2019

OSError имеет пользовательскую __reduce__ реализацию ;к сожалению, это не подходит для подклассов для подклассов, которые не соответствуют ожидаемым аргументам.Вы можете увидеть промежуточное состояние травления, вызвав __reduce__ вручную:

>>> SubOSError.__reduce__(cce)
(modulename.SubOSError, (1, 'unittest'))

Первый элемент tuple является вызываемым для вызова, второй - tuple аргументов для передачи,Поэтому, когда он пытается воссоздать ваш класс, он:

modulename.SubOSError(1, 'unittest')

потерял информацию о OSError, с которым вы изначально были созданы.

Если вы должны принять аргументы, которые неЧтобы соответствовать ожиданиям OSError.__reduce__ / OSError.__init__, вам необходимо написать собственное переопределение __reduce__, чтобы гарантировать получение правильной информации.Простая версия может выглядеть так:

class SubOSError(OSError):

    def __init__(self, foo, os_error):
        self.foo = foo  # Must preserve information for pickling later
        super().__init__(os_error.errno, os_error.strerror)

    def __reduce__(self):
        # Pickle as type plus tuple of args expected by type
        return type(self), (self.foo, OSError(*self.args))

При таком дизайне SubOSError.__reduce__(cce) теперь будет возвращать:

(modulename.SubOSError, (1, PermissionError(1, 'unittest')))

, где второй элемент tuple - это правильные аргументы, необходимые длявоссоздать экземпляр (ожидается изменение с OSError на PermissionError; OSError фактически возвращает свои собственные подклассы на основе errno).

0 голосов
/ 26 сентября 2019

Эта проблема была исправлена ​​и объединена с мастером в aiohttp 25 сентября 2019 года. Я обновлю этот ответ в будущем, если отмечу версию, к которой относится исправление (не стесняйтесь редактировать этот ответ вв будущем отметим версию, содержащую это обновление) .

Git проблема с исправлением:

https://github.com/aio-libs/aiohttp/issues/4077

...