使用pyinstaller将python脚本构建到单个exe

时间:2018-04-10 12:13:35

标签: python-3.x pandas pyinstaller

我收到以下错误:脚本名称= prepareIncidentCountMail.py

Traceback (most recent call last):
  File "Alexa\prepareIncidentCountMail.py", line 52, in <module>
  File "site-packages\pandas\core\frame.py", line 683, in style
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
  File "c:\users\avikumar\documents\learn\alexa\venv\lib\site-packages\PyInstaller\loader\pyimod03_importers.py", line 631, in exec_module
    exec(bytecode, module.__dict__)
  File "site-packages\pandas\io\formats\style.py", line 50, in <module>
  File "site-packages\pandas\io\formats\style.py", line 118, in Styler
  File "site-packages\jinja2\environment.py", line 830, in get_template
  File "site-packages\jinja2\environment.py", line 804, in _load_template
  File "site-packages\jinja2\loaders.py", line 113, in load
  File "site-packages\jinja2\loaders.py", line 234, in get_source
  File "site-packages\pkg_resources\__init__.py", line 1459, in has_resource
  File "site-packages\pkg_resources\__init__.py", line 1509, in _has
NotImplementedError: Can't perform this operation for unregistered loader type
[10536] Failed to execute script prepareIncidentCountMail

我在链接:Change color of complete row in data frame in pandas

的帮助下使用pandas风格

我看到样式正在使用jinja2导致上述错误。有没有办法挂钩此错误或任何其他工具将python脚本转换为单个可执行文件。

2 个答案:

答案 0 :(得分:2)

昨天我只是使用giumas在这里所做的调整后的版本自己解决了这个问题:https://github.com/pyinstaller/pyinstaller/issues/1898

问题不在于挂钩(这是我第一次尝试解决方案),而是pandas样式模块导入jinja2的事实,后者使用“ get_template”方法,而该方法又使用pkg_resources模块。最后一个是问题,由于某些原因,pyinstaller在pkg_resources模块中无法正常工作。

解决方案:找到熊猫的安装位置,然后转到类似的

C:\ Users \ UserName \ AppData \ Local \ Programs \ Python \ Python36 \ Lib \ site-packages \ pandas \ io \ formats

在format文件夹中找到style.py文件,然后在您喜欢的文本编辑器中将其打开。在style.py中向下滚动到第118行,您将看到以下内容:

template = env.get_template("html.tpl")

将此行更改为:

template = env.from_string("html.tpl")

保存文件并重新运行pyinstaller。当您尝试运行可执行文件时,它应该会按预期执行,并且不会出现任何错误消息。

希望有帮助。

答案 1 :(得分:1)

以下内容不需要手动更改库代码。如果有人有时间的话,可以将它添加为对pyinstaller中官方Jinja2挂钩的更改:

import sys
from jinja2.loaders import FileSystemLoader


class PyInstallerPackageLoader(FileSystemLoader):
    """Load templates from packages deployed as part of a Pyinstaller build.  It is constructed with
    the name of the python package and the path to the templates in that
    package::
        loader = PackageLoader('mypackage', 'views')
    If the package path is not given, ``'templates'`` is assumed.
    Per default the template encoding is ``'utf-8'`` which can be changed
    by setting the `encoding` parameter to something else.  Due to the nature
    of eggs it's only possible to reload templates if the package was loaded
    from the file system and not a zip file.
    """

    def __init__(self, package_name, package_path="templates", encoding="utf-8"):
        # Use the standard pyinstaller convention of storing additional package files
        full_package_path = f"{sys._MEIPASS}/{package_name}/{package_path}"
        # Defer everything else to the FileSystemLoader
        super().__init__(full_package_path, encoding)


def patch_jinja_loader():
    # patching the pandas loader which fails to locate the template when called from a pyinstaller build

    if getattr(sys, "frozen", False):
        import jinja2

        jinja2.PackageLoader = PyInstallerPackageLoader

基本上,它使加载器看起来像熊猫尝试使用的Jinja2 PackageLoader,以便可以对其进行修补。实际上,它使用的是FileSystemLoader,这是pyinstaller查找模板文件所需要的。

以上操作需要在导入熊猫之前运行。

我还发布了此解决方案on the GitHub issue