冻结可执行文件的覆盖范围

2024-05-19 21:14:16 发布

您现在位置:Python中文网/ 问答频道 /正文

有没有办法对pyinstaller构建的可执行文件运行覆盖率?我试着像一个python脚本一样运行它,但它不喜欢将可执行文件作为输入(我真的不希望它起作用),我怀疑答案是没有,没有一种简单的方法可以对构建的可执行文件运行覆盖。。。。(这是在windows.exe上)

我使用的覆盖包只是普通的覆盖包,你可以从“easy_install coverage”中获得nedbatchelder.com网站(http://nedbatchelder.com/code/coverage/


Tags: install方法答案脚本com可执行文件网站windows
2条回答

这不是一个完整的答案,但我目前所发现的。在

根据我对pyinstaller工作原理的理解,二进制文件是由一个嵌入python解释器和引导加载脚本的小型C程序构建的。PyInstaller构造的EXE在包含python代码资源的实际二进制文件结束后包含一个归档文件。这在这里解释http://www.pyinstaller.org/export/develop/project/doc/Manual.html#pyinstaller-archives。在

有每年从Pyinstaller/loader/每年Docs。您应该能够创建一个导入钩子来从二进制文件导入。google搜索pyinstaller反汇编程序发现了https://bitbucket.org/Trundle/exetractor/src/00df9ce00e1a/exetractor/pyinstaller.py,看起来它可能提取出必要的部分。在

另一部分是二进制文件中的所有资源都将被编译成python代码。很有可能,覆盖率.py在正常情况下运行时,将以与命中任何其他已编译模块相同的方式提供无用的输出。在

突出显示使用cover_pylib=True

我知道你问这个问题已经很久了,但我只是想知道答案。:)

使用coverage.py的当前位桶源,我能够成功地从PyInstaller生成的EXE文件中收集覆盖率数据。在

在我的应用程序的主要来源中,我有条件地告诉保险范围开始收集保险范围,如下所示:

if os.environ.has_key('COVERAGE') and len(os.environ['COVERAGE']) > 0:
   usingCoverage = True
   import coverage
   import time
   cov = coverage.coverage(data_file='.coverage.' + version.GetFullString(), data_suffix=time.strftime(".%Y_%m_%d_%H_%M.%S", time.localtime()), cover_pylib=True)
   cov.start()

这只在我想要的时候才开始收集保险范围。使用data_后缀可以让我更容易地利用cov.combine()进行覆盖率文件的合并。version.GetFullString()只是我的应用程序版本号。在

在这里,cover_pylib被设置为True,因为所有标准的Python库模块__file__属性都像这样...\_MEIXXXXX\random.pyc,因此与包中不存在的其他代码无法区分(基于路径)。在

当应用程序准备退出时,我有一个小片段:

^{pr2}$

一旦我的应用程序运行完毕覆盖率.py还是不能自动生成它的HTML报告。需要清理覆盖率数据,以便将...\_MEIXXXX\...文件引用转换为指向实际源代码的绝对文件路径。在

我通过运行以下代码片段来实现这一点:

import sys
import os.path

from coverage.data import CoverageData
from coverage import coverage

from glob import glob

def cleanupLines(data):
    """
    The coverage data collected via PyInstaller coverage needs the data fixed up
    so that coverage.py's report generation code can analyze the source code.
    PyInstaller __file__ attributes on code objecters are all in subdirectories of the     _MEIXXXX 
    temporary subdirectory. We need to replace the _MEIXXXX temp directory prefix with     the correct 
    prefix for each source file. 
    """
    prefix = None
    for file, lines in data.lines.iteritems():
        origFile = file
        if prefix is None:
            index = file.find('_MEI')
            if index >= 0:
                pathSepIndex = file.find('\\', index)
                if pathSepIndex >= 0:
                    prefix = file[:pathSepIndex + 1]
        if prefix is not None and file.find(prefix) >= 0:
            file = file.replace(prefix, "", 1)
            for path in sys.path:
                if os.path.exists(path) and os.path.isdir(path):
                    fileName = os.path.join(path, file)
                    if os.path.exists(fileName) and os.path.isfile(fileName):
                        file = fileName
            if origFile != file:
                del data.lines[origFile]
                data.lines[file] = lines

for file in glob('.coverage.' + version.GetFullString() + '*'):
    print "Cleaning up: ", file
    data = CoverageData(file)
    data.read()
    cleanupLines(data)
    data.write()

这里的for循环只是为了确保所有要合并的覆盖率文件都被清理干净。在

注意:默认情况下,此代码不清除的唯一覆盖率数据是PyInstaller相关文件,这些文件的_MEIXXX数据不包含在其__file__属性中。在

现在您可以成功地生成一个HTML或XML(或其他任何东西)coverage.py报告。在

在我的情况下,它看起来像这样:

cov = coverage(data_file='.coverage.' + version.GetFullString(), data_suffix='.combined')
cov.load()
cov.combine()
cov.save()
cov.load()
cov.html_report(ignore_errors=True,omit=[r'c:\python27\*', r'..\3rdParty\PythonPackages\*'])

在构造函数中使用data_文件是为了确保load/combine能够正确识别所有清理后的覆盖文件。在

html_report调用告诉coverage.py忽略标准的python库(以及签入我的版本控制树中的python库),只关注我的应用程序代码。在

我希望这有帮助。在

相关问题 更多 >