gpt4 book ai didi

python - 插入使用M2Crypto的代码时,_shutdown AttributeError(忽略)

转载 作者:行者123 更新时间:2023-12-03 02:25:59 25 4
gpt4 key购买 nike

我正在运行lint,如下所示:

$ python -m pylint.lint m2test.py


使用此代码:

import M2Crypto
def f():
M2Crypto.RSA.new_pub_key("").as_pem(cipher=None).split("\n")


棉绒输出结尾为:

Exception AttributeError: '_shutdown' in <module 'threading' from '/usr/lib/python2.7/site-packages/M2Crypto-0.21.1-py2.7-linux-x86_64.egg/M2Crypto/threading.pyc'> ignored


这段代码在运行时可以正常工作(上面的代码实际上是一个最小的测试用例;但是完整的版本可以使用)。该异常被忽略,但是 Bitten认为这是失败的,因此在此步骤上停止。

我尝试在函数的定义周围添加'M2Crypto.threading.init()'/'M2Crypto.threading.cleanup()',但这并不能解决问题。

如何防止出现此问题?

我在Debian Lenny x86_64上使用M2Crypto 0.21.1,pylint 0.24和Python 2.7(也尝试过2.7.2)。

最佳答案

您所看到的异常是由astng程序包(可能是“抽象语法树,下一代”?)中的错误引起的,该程序包是pylint所依赖的工具包,由同一人编写。我应该顺便指出,我总是鼓励人们在可能的情况下使用pyflakes而不是pylint,因为它快速,简单,快速且可预测,而pylint试图做一些深层的魔术,但并非如此只是速度很慢,但这可以使它陷入这种麻烦。 :)

这是PyPI上的两个软件包:

http://pypi.python.org/pypi/pylint

http://pypi.python.org/pypi/astng

并请注意,这个问题一定是pylint中的错误,而不是您的代码中的错误,因为pylint不会运行您的代码以生成其报告-想象一下,如果这样做会造成严重破坏(因为被删除的代码可能会删除文件等)!由于您的代码无法运行,因此无需采取任何谨慎措施,例如使用线程init()cleanup()函数保护您的调用,就可能避免了该错误-除非出于其他原因而发生了代码片段以改变我们的行为,即将调查。

因此,根据您的实际例外情况。

我以前从未真正听说过_shutdown!快速搜索Python标准库会在threading.py中显示其定义,但无法从任何地方调用该函数。仅通过搜索Python C源代码,我才发现在解释器关闭期间pythonrun.c中的位置实际上是在调用什么:

static void
wait_for_thread_shutdown(void)
{
...
PyObject *threading = PyMapping_GetItemString(tstate->interp->modules,
"threading");
if (threading == NULL) {
/* threading not imported */
PyErr_Clear();
return;
}
result = PyObject_CallMethod(threading, "_shutdown", "");
if (result == NULL) {
PyErr_WriteUnraisable(threading);
}
...
}


显然,这是 threading标准库模块所需的某种清理函数,并且他们对Python解释器本身进行了特殊区分,以确保其被调用。

从上面的代码中可以看到,Python悄无声息地处理了 threading模块在程序运行期间从未导入的情况。但是,如果确实导入了 threading,并且在关闭时仍然存在,则解释器会在内部查找 _shutdown函数,甚至可以打印错误消息-然后返回非零退出状态,这是原因您的问题-如果无法解决。

因此,我们必须找出为什么 threading模块存在但为什么 _shutdown在检查程序并且Python退出时却没有 pylint方法的原因。需要某种仪器。我们可以打印出 pylint退出时模块的外观吗?我们可以! pylint/lint.py模块的最后几行通过实例化已定义的 Run类来运行其“主程序”:

if __name__ == '__main__':
Run(sys.argv[1:])


因此,我在编辑器中打开了 lint.py(在Python Virual Environment中安装每个小项目的宏伟的事情之一就是,我可以跳入并编辑第三方代码以进行快速实验),并添加了以下 print语句在 Run类的 __init__()方法的底部:

    sys.path.pop(0)
print "*****", sys.modules['threading'].__file__ # added by me!
if exit:
sys.exit(self.linter.msg_status)


我重新运行了命令:

python -m pylint.lint m2test.py


然后出现了 __file__模块的 threading字符串:

***** /home/brandon/venv/lib/python2.7/site-packages/M2Crypto/threading.pyc


好吧,看那个。

这就是问题!

根据此路径,实际上存在一个 M2Crypto/threading.py模块,在所有正常情况下,该模块仅应称为 M2Crypto.threading,因此位于 sys.modules词典中,其名称为:

sys.modules['M2Crypto.threading']


但是以某种方式,该文件也作为主要的Python threading模块加载,从而掩盖了标准库中的官方 threading模块。因此,Python退出逻辑非常正确地抱怨标准库 _shutdown()函数丢失。

这怎么可能呢?顶级模块只能出现在 sys.path中明确列出的路径中,而不能出现在它们下面的子目录中。这就引出了一个新的问题:在 pylint运行期间,是否有任何迹象表明 …/M2Crypto/目录本身被放置在 sys.path上,好像它包含顶级模块一样?让我们来看看!

我们需要更多的工具:我们需要让Python告诉我们名称中带有 M2Crypto的目录出现在 sys.path中的那一刻。这确实会使速度变慢,但让我们在pylint的 __init__.py中添加跟踪函数-因为这是您在运行 -m pylint.lint时导入的第一个模块-它将为执行的每一行代码写一个输出文件,告诉我们,其中 sys.path是否包含任何错误值:

def install_tracer():
import sys
output = open('mytracer.out', 'w')
def mytracer(frame, event, arg):
broken = any(p.endswith('M2Crypto') for p in sys.path)
output.write('{} {}:{} {}\n'.format(
broken, frame.f_code.co_filename, frame.f_lineno, event))
return mytracer
sys.settrace(mytracer)

install_tracer()
del install_tracer


请注意我在这里有多小心:在模块的命名空间中仅定义一个名称,然后在让 pylint继续加载之前,仔细删除该名称以进行清理。跟踪功能本身需要的所有资源(即 sys模块和 output打开文件)在 install_tracer()闭包中可用,因此从外部看, pylint与总是。以防万一有人尝试自省,就像 pylint一样!

这将生成一个大约80万行的文件 mytracer.out,每行看起来像这样:

False /home/brandon/venv/lib/python2.7/posixpath.py:118 call


False表示 sys.path看起来很干净,文件名和行号是正在执行的代码行, call表示解释器处于执行的哪个阶段。

那么 sys.path是否会中毒?让我们看一下每行的第一个 TrueFalse,并查看从每个值开始的连续几行:

$ awk '{print$1}' mytracer.out | uniq -c
607997 False
3173 True
4558 False
33217 True
4304 False
41699 True
2953 False
110503 True
52575 False


哇!那是个问题!对于一次运行数千行,我们的测试用例是 True,这意味着解释器在路径上应以 …/M2Crypto/或路径名称的某种变体(其中带有 M2Crypto)运行。不仅包含 …/M2Crypto的目录应该位于路径上。在文件中寻找第一个从 FalseTrue的过渡,我看到了:

False /home/brandon/venv/lib/python2.7/site-packages/logilab/astng/builder.py:132 line
False /home/brandon/venv/lib/python2.7/posixpath.py:118 call
...
False /home/brandon/venv/lib/python2.7/posixpath.py:124 line
False /home/brandon/venv/lib/python2.7/posixpath.py:124 return
True /home/brandon/venv/lib/python2.7/site-packages/logilab/astng/builder.py:133 line


查看 builder.py文件中的第132和133行揭示了我们的罪魁祸首:

130    # build astng representation
131 try:
132 sys.path.insert(0, dirname(path)) # XXX (syt) iirk
133 node = self.string_build(data, modname, path)
134 finally:
135 sys.path.pop(0)


注意注释,它是原始代码的一部分,而不是我自己的注释!显然, XXX (syt) iirk是该程序员奇怪的母语中的短语“这个模块的父目录放在 sys.path上,这样,每次有人强迫 pylint用< cc>子模块。”显然,它是一种非常紧凑的母语。 :)

如果您调整跟踪模块以监视 pylint实际导入的 threading(我将留给读者的练习),您会看到它发生在 sys.modules上,它是由其他标准库模块在该分析又试图无害地导入 threading

因此,让我们回顾一下正在发生的事情:


SocketServer是危险的魔法。
作为其魔术的一部分,如果看到您 threading,则它会尝试在磁盘上查找 pylint,对其进行解析并预测要从其名称空间加载有效名称还是无效名称。
[请参阅下面的我的评论。]因为您在 import foo的返回值上调用 foo.py,所以 .split()会尝试自省 RSA.as_pem()方法,该方法又使用 pylint模块,该模块又进行调用导致 as_pem()导入 M2Crypto.BIO
作为加载任何模块 pylint的一部分, threading会在 foo.py上抛出包含 pylint的目录,即使该目录位于软件包中,因此也为该目录中的模块提供了对标准库模块的影子化的特权。在分析过程中使用相同的名称。
当Python退出时, foo.py库位于 sys.path所属的地方会很不高兴,因为它想运行 M2Crypto.threadingthreading方法。


您应该将此错误报告给 _shutdown()threading / pylint同事。告诉他们我发给你了。

如果您决定在使用 astng之后继续使用它,那么在这种情况下似乎有两种解决方案:要么不检查调用 logilab.org的代码,要么在 pylint期间导入 M2Crypto导入过程(例如,将 threading粘贴到 pylint中),以使模块有机会在 import threading兴奋之前尝试抓住 pylint/__init__.py插槽,并尝试让 sys.modules['threading']代替插槽。

总之,我认为 pylint的作者说得最好:XXX(syt)iirk。确实。

关于python - 插入使用M2Crypto的代码时,_shutdown AttributeError(忽略),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7302769/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com