AttributeError: 'str' object has no attribute 'errno'
AttributeError: 'str' object has no attribute 'errno'
我在 asyncio
生成的 multiprocessing.Queue
中放置了一个 ClientConnectionError
异常。我这样做是为了将在 asyncio land 中生成的异常传递回另一个 thread/process.
中的客户端
我的假设是这个异常发生在反序列化过程中从队列中读取异常。否则看起来几乎不可能到达。
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
更新:
我设法重现了这个问题(感谢 Samuel 在评论中改进了最小可重现的测试用例,后来在 bugs.python.org 的 xtreak 将其进一步提炼成一个 pickle-only 测试用例):
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'
参考文献:
OSError
有 a custom __reduce__
implementation;不幸的是,对于与预期参数不匹配的 subclasses,它不是 subclass 友好的。手动调用__reduce__
可以看到酸洗的中间状态:
>>> SubOSError.__reduce__(cce)
(modulename.SubOSError, (1, 'unittest'))
tuple
的第一个元素是要调用的可调用对象,第二个是要传递的参数的 tuple
。因此,当它尝试重新创建您的 class 时,它会:
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)
现在 return:
(modulename.SubOSError, (1, PermissionError(1, 'unittest')))
其中 tuple
的第二个元素是重新创建实例所需的正确参数(从 OSError
到 PermissionError
的变化是预期的;OSError
实际上 return 是基于 errno
).
的自己的子 classes
此问题已于 2019 年 9 月 25 日在 aiohttp
中修复并合并到 master。如果我注意到修复进入 的版本(感觉以后可以自由编辑此答案以注明包含此更新的版本).
Git 修复问题:
我在 asyncio
生成的 multiprocessing.Queue
中放置了一个 ClientConnectionError
异常。我这样做是为了将在 asyncio land 中生成的异常传递回另一个 thread/process.
我的假设是这个异常发生在反序列化过程中从队列中读取异常。否则看起来几乎不可能到达。
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
更新:
我设法重现了这个问题(感谢 Samuel 在评论中改进了最小可重现的测试用例,后来在 bugs.python.org 的 xtreak 将其进一步提炼成一个 pickle-only 测试用例):
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'
参考文献:
OSError
有 a custom __reduce__
implementation;不幸的是,对于与预期参数不匹配的 subclasses,它不是 subclass 友好的。手动调用__reduce__
可以看到酸洗的中间状态:
>>> SubOSError.__reduce__(cce)
(modulename.SubOSError, (1, 'unittest'))
tuple
的第一个元素是要调用的可调用对象,第二个是要传递的参数的 tuple
。因此,当它尝试重新创建您的 class 时,它会:
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)
现在 return:
(modulename.SubOSError, (1, PermissionError(1, 'unittest')))
其中 tuple
的第二个元素是重新创建实例所需的正确参数(从 OSError
到 PermissionError
的变化是预期的;OSError
实际上 return 是基于 errno
).
此问题已于 2019 年 9 月 25 日在 aiohttp
中修复并合并到 master。如果我注意到修复进入 的版本(感觉以后可以自由编辑此答案以注明包含此更新的版本).
Git 修复问题: