Python maximum recursion depth exceeded while calling a Python object (gevent的SSL无限递归错误)的问题解决
報錯信息?
源碼位置
分析
?很尷尬,完全看不出原因?qū)е逻@個報錯
解決方法
通過刪除代碼的方式一部一部刪除,找到了問題出處
原因是包的順序出現(xiàn)了問題,把位置互換一下,發(fā)現(xiàn)沒有報錯了,但是很明確的告訴你這兩個包沒有交互關(guān)系,沒有依賴關(guān)系,但是就是這么神奇,為什么這么神奇
看一個實例解釋
vim test.py?:
import gevent.monkey from requests.packages.urllib3.util.ssl_ import create_urllib3_context# 將monkey patch置于create_urllib3_context引入之前可防止此錯誤出現(xiàn)。 gevent.monkey.patch_all()create_urllib3_context() # output: # Traceback (most recent call last): # File "test.py", line 7, in <module> # create_urllib3_context() # File "/usr/lib/python3.6/site-packages/requests/packages/urllib3/util/ssl_.py", line 265, in create_urllib3_context # context.options |= options # File "/usr/lib/python3.6/ssl.py", line 459, in options # super(SSLContext, SSLContext).options.__set__(self, value) # File "/usr/lib/python3.6/ssl.py", line 459, in options # super(SSLContext, SSLContext).options.__set__(self, value) # File "/usr/lib/python3.6/ssl.py", line 459, in options # super(SSLContext, SSLContext).options.__set__(self, value) # [Previous line repeated 329 more times] # RecursionError: maximum recursion depth exceeded while calling a Python objectdebug
create_urllib3_context代碼片段:
... # requests/packages/urllib3/util/ssl_.py#L250context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23)# Setting the default here, as we may have no ssl module on import cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqsif options is None:options = 0# SSLv2 is easily broken and is considered harmful and dangerousoptions |= OP_NO_SSLv2# SSLv3 has several problems and is now dangerousoptions |= OP_NO_SSLv3# Disable compression to prevent CRIME attacks for OpenSSL 1.0+# (issue #309)options |= OP_NO_COMPRESSIONcontext.options |= options ...這里的SSLContext的類型為ssl.SSLContext',而不是gevent._ssl3.SSLContext。 即gevent.monkey.patch_all對其沒起作用。
查看SSLContext相關(guān)代碼:
... # requests/packages/urllib3/util/ssl_.py#L86try:from ssl import SSLContext # Modern SSL? except ImportError:import sysclass SSLContext(object): # Platform-specific: Python 2 & 3.1supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or(3, 2) <= sys.version_info) ...from ssl import SSLContext是gevent.monkey.patch_all失效的原因所在。 修正為:
import ssl SSLContext = lambda *args, **kw: ssl.SSLContext(*args, **kw)當然最好的方案還是在引入gevent庫后立即執(zhí)行monkey patch代碼。
analysis
gevent.monkey.patch_all的位置放錯導致了create_urllib3_context中的context?的類型為ssl.SSLContext而不是gevent._ssl3.SSLContext。
因此,context.options |= options最后會調(diào)用:
# ssl.py#L457@options.setter def options(self, value):super(SSLContext, SSLContext).options.__set__(self, value)而不是:
# gevent/_ssl3.py#L67# In 3.6, these became properties. They want to access the # property __set__ method in the superclass, and they do so by using # super(SSLContext, SSLContext). But we rebind SSLContext when we monkey # patch, which causes infinite recursion. # https://github.com/python/cpython/commit/328067c468f82e4ec1b5c510a4e84509e010f296 # pylint:disable=no-member @orig_SSLContext.options.setter def options(self, value):super(orig_SSLContext, orig_SSLContext).options.__set__(self, value)但是,由于已經(jīng)調(diào)用過了monkey patch代碼,故此時的SSLContext實際上是gevent._ssl3.SSLContext, 是ssl.SSLContext的子類。
所以,super(SSLContext, SSLContext).options實際上是super(gevent._ssl3.SSLContext, gevent._ssl3.SSLContext).options, 得到的結(jié)果是ssl.SSLContext.options,而不是我們所希望的_ssl._SSLContext.options。
同時,這也造成了無限遞歸。
總結(jié)
以上是生活随笔為你收集整理的Python maximum recursion depth exceeded while calling a Python object (gevent的SSL无限递归错误)的问题解决的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shell获取路径文件的文件名
- 下一篇: msf:Known bug in WMI