使用PyInstaller轻松分发Python应用程序

Are you jealous of Go developers building an executable and easily shipping it to users? Wouldn’t it be great if your users could run your application without installing anything? That is the dream, and PyInstaller is one way to get there in the Python ecosystem.

您是否对Go开发人员构建可执行文件并轻松将其交付给用户感到嫉妒? 如果您的用户无需安装任何程序就可以运行您的应用程序,那不是很好吗? 那是梦想, PyInstaller是在Python生态系统中实现目标的一种方法。

There are countless tutorials on how to set up virtual environments, manage dependencies, and publish to PyPI, which is useful when you’re creating Python libraries. There is much less information for developers building Python applications. This tutorial is for developers who want to distribute applications to users who may or may not be Python developers.

关于如何设置虚拟环境 , 管理依赖关系以及将其发布到PyPI的教程不计其数,这在创建Python库时非常有用。 开发人员构建Python应用程序所需的信息少得多。 本教程适用于希望将应用程序分发给可能是Python开发人员或可能不是Python开发人员的开发人员。

In this tutorial, you’ll learn the following:

在本教程中,您将学到以下内容:

  • How PyInstaller can simplify application distribution
  • How to use PyInstaller on your own projects
  • How to debug PyInstaller errors
  • What PyInstaller can’t do
  • PyInstaller如何简化应用程序分发
  • 如何在自己的项目上使用PyInstaller
  • 如何调试PyInstaller错误
  • PyInstaller无法做什么

PyInstaller gives you the ability to create a folder or executable that users can immediately run without any extra installation. To fully appreciate PyInstaller’s power, it’s useful to revisit some of the distribution problems PyInstaller helps you avoid.

PyInstaller使您能够创建一个文件夹或可执行文件,使用户无需任何额外安装即可立即运行它们。 为了充分理解PyInstaller的强大功能,重新审视PyInstaller可以帮助您避免的一些发行问题很有用。

Free Bonus: 5 Thoughts On Python Mastery, a free course for Python developers that shows you the roadmap and the mindset you’ll need to take your Python skills to the next level.

免费奖金: 关于Python精通的5个想法 ,这是针对Python开发人员的免费课程,向您展示了将Python技能提升到新水平所需的路线图和心态。

发行问题 (Distribution Problems)

Setting up a Python project can be frustrating, especially for non-developers. Often, the setup starts with opening a Terminal, which is a non-starter for a huge group of potential users. This roadblock stops users even before the installation guide delves into the complicated details of virtual environments, Python versions, and the myriad of potential dependencies.

设置Python项目可能会令人沮丧,特别是对于非开发人员而言。 通常,设置是从打开一个终端开始的,对于大量潜在用户而言,这是一个不起眼的启动器。 即使在安装指南深入研究虚拟环境,Python版本以及无数潜在依赖关系的复杂细节之前,此障碍也会阻止用户。

Think about what you typically go through when setting up a new machine for Python development. It probably goes something like this:

想一想为Python开发设置新机器时通常会经历什么。 它可能是这样的:

  • Download and install a specific version of Python
  • Set up pip
  • Set up a virtual environment
  • Get a copy of your code
  • Install dependencies
  • 下载并安装特定版本的Python
  • 设置点
  • 设置虚拟环境
  • 获取代码副本
  • 安装依赖

Stop for a moment and consider if any of the above steps make any sense if you’re not a developer, let alone a Python developer. Probably not.

停一会儿,考虑一下如果您不是开发人员,则上述任何步骤是否有意义,更不用说Python开发人员了。 可能不是。

These problems explode if your user is lucky enough to get to the dependencies portion of the installation. This has gotten much better in the last few years with the prevalence of wheels, but some dependencies still require C/C++ or even FORTRAN compilers!

如果您的用户足够幸运能够到达安装的依赖项部分,这些问题就会爆炸。 在过去的几年中,随着轮子的普及,这种情况变得更好了,但是某些依赖仍然需要C / C ++甚至是FORTRAN编译器!

This barrier to entry is way too high if your goal is to make an application available to as many users as possible. As Raymond Hettinger often says in his excellent talks, “There has to be a better way.”

如果您的目标是使应用程序可供尽可能多的用户使用,则进入的障碍过高。 正如雷蒙德·海廷格 ( Raymond Hettinger )在他的精彩演讲中经常说的:“必须有更好的方法。”

Py安装程序 (PyInstaller)

PyInstaller abstracts these details from the user by finding all your dependencies and bundling them together. Your users won’t even know they’re running a Python project because the Python Interpreter itself is bundled into your application. Goodbye complicated installation instructions!

PyInstaller通过查找所有依赖项并将它们捆绑在一起,从用户那里提取这些详细信息。 您的用户甚至都不知道他们正在运行Python项目,因为Python Interpreter本身已捆绑到您的应用程序中。 再见了复杂的安装说明!

PyInstaller performs this amazing feat by introspecting your Python code, detecting your dependencies, and then packaging them into a suitable format depending on your Operating System.

PyInstaller通过检查您的Python代码,检测您的依赖项,然后根据您的操作系统将它们打包为合适的格式来执行此惊人的壮举。

There are lots of interesting details about PyInstaller, but for now you’ll learn the basics of how it works and how to use it. You can always refer to the excellent PyInstaller docs if you want more details.

有关PyInstaller的信息,有很多有趣的细节,但是现在,您将学习它的工作原理和使用方法的基础知识。 如果您需要更多细节,可以随时参考出色的PyInstaller文档 。

In addition, PyInstaller can create executables for Windows, Linux, or macOS. This means Windows users will get a .exe, Linux users get a regular executable, and macOS users get a .app bundle. There are some caveats to this. See the limitations section for more information.

此外,PyInstaller可以为Windows,Linux或macOS创建可执行文件。 这意味着Windows用户将获得.exe ,Linux用户将获得常规可执行文件,而macOS用户将获得.app软件包。 有一些注意事项。 有关更多信息,请参见限制部分。

准备项目 (Preparing Your Project)

PyInstaller requires your application to conform to some minimal structure, namely that you have a CLI script to start your application. Often, this means creating a small script outside of your Python package that simply imports your package and runs main().

PyInstaller要求您的应用程序符合某些最小结构,即您具有一个CLI脚本来启动您的应用程序。 通常,这意味着在Python包之外创建一个小的脚本,该脚本只需导入您的包并运行main()

The entry-point script is a Python script. You can technically do anything you want in the entry-point script, but you should avoid using explicit relative imports. You can still use relative imports throughout the rest your application if that’s your preferred style.

入口点脚本是Python脚本。 从技术上讲,您可以在入口点脚本中执行任何所需的操作,但应避免使用显式的相对导入 。 如果这是您的首选样式,您仍然可以在其余的应用程序中使用相对导入。

Note: An entry-point is the code that starts your project or application.

注意:入口点是启动项目或应用程序的代码。

You can give this a try with your own project or follow along with the Real Python feed reader project. For more detailed information on the reader project, check out the the tutorial on Publishing a Package on PyPI.

您可以尝试使用自己的项目或跟随Real Python feed阅读器项目进行尝试。 有关阅读器项目的更多详细信息,请查看有关在PyPI上发布软件包的教程。

The first step to building an executable version of this project is to add the entry-point script. Luckily, the feed reader project is well structured, so all you need is a short script outside the package to run it. For example, you can create a file called cli.py alongside the reader package with the following code:

生成此项目的可执行版本的第一步是添加入口点脚本。 幸运的是,提要阅读器项目的结构良好,因此您所需要做的就是在程序包外部运行一个简短的脚本。 例如,您可以使用以下代码在阅读器包旁边创建一个名为cli.py的文件:

 from from reader.__main__ reader.__main__ import import main

main

if if __name__ __name__ == == '__main__''__main__' :
    :
    mainmain ()
()

This cli.py script calls main() to start up the feed reader.

cli.py脚本调用main()启动Feed阅读器。

Creating this entry-point script is straightforward when you’re working on your own project because you’re familiar with the code. However, it’s not as easy to find the entry-point of another person’s code. In this case, you can start by looking at the setup.py file in the third-party project.

当您在自己的项目中工作时,创建此入口点脚本非常简单,因为您对代码很熟悉。 但是,找到另一个人的代码的入口点并不容易。 在这种情况下,您可以先查看第三方项目中的setup.py文件。

Look for a reference to the entry_points argument in the project’s setup.py. For example, here’s the reader project’s setup.py:

在项目的setup.py查找对entry_points参数的引用。 例如,这是阅读器项目的setup.py

As you can see, the entry-point cli.py script calls the same function mentioned in the entry_points argument.

如您所见,入口点cli.py脚本调用了entry_points参数中提到的相同函数。

After this change, the reader project directory should look like this, assuming you checked it out into a folder called reader:

进行此更改之后,假设您将其检出到名为reader的文件夹中,那么reader项目目录应如下所示:

reader/
|
├── reader/
|   ├── __init__.py
|   ├── __main__.py
|   ├── config.cfg
|   ├── feed.py
|   └── viewer.py
|
├── cli.py
├── LICENSE
├── MANIFEST.in
├── README.md
├── setup.py
└── tests
reader/
|
├── reader/
|   ├── __init__.py
|   ├── __main__.py
|   ├── config.cfg
|   ├── feed.py
|   └── viewer.py
|
├── cli.py
├── LICENSE
├── MANIFEST.in
├── README.md
├── setup.py
└── tests

Notice there is no change to the reader code itself, just a new file called cli.py. This entry-point script is usually all that’s necessary to use your project with PyInstaller.

请注意,读取器代码本身没有更改,只有一个名为cli.py的新文件。 通常,此入口点脚本是将项目与PyInstaller一起使用所必需的。

However, you’ll also want to look out for uses of __import__() or imports inside of functions. These are referred to as hidden imports in PyInstaller terminology.

但是,您还需要注意在函数内部使用__import__()或import的__import__() 在PyInstaller术语中,这些被称为隐藏导入 。

You can manually specify the hidden imports to force PyInstaller to include those dependencies if changing the imports in your application is too difficult. You’ll see how to do this later in this tutorial.

如果在应用程序中更改导入太困难,则可以手动指定隐藏的导入以强制PyInstaller包括那些依赖项。 您将在本教程的后面部分看到如何执行此操作。

Once you can launch your application with a Python script outside of your package, you’re ready to give PyInstaller a try at creating an executable.

一旦可以使用软件包外部的Python脚本启动应用程序,就可以尝试PyInstaller创建可执行文件了。

使用PyInstaller (Using PyInstaller)

The first step is to install PyInstaller from PyPI. You can do this using pip like other Python packages:

第一步是从PyPI安装PyInstaller。 您可以像其他Python软件包一样使用pip来执行此操作:

pip will install PyInstaller’s dependencies along with a new command: pyinstaller. PyInstaller can be imported in your Python code and used as a library, but you’ll likely only use it as a CLI tool.

pip将安装PyInstaller的依赖项以及一个新命令: pyinstaller 可以将PyInstaller导入Python代码中并用作库,但是您可能仅将其用作CLI工具。

You’ll use the library interface if you create your own hook files.

如果创建自己的挂钩文件,则将使用库接口。

You’ll increase the likelihood of PyInstaller’s defaults creating an executable if you only have pure Python dependencies. However, don’t stress too much if you have more complicated dependencies with C/C++ extensions.

如果您仅具有纯Python依赖项,则将增加PyInstaller默认值创建可执行文件的可能性。 但是,如果您对C / C ++扩展有更复杂的依赖关系,请不要过分强调。

PyInstaller supports lots of popular packages like NumPy, PyQt, and Matplotlib without any additional work from you. You can see more about the list of packages that PyInstaller officially supports by referring to the PyInstaller documentation.

PyInstaller支持许多受欢迎的软件包,例如NumPy , PyQt和Matplotlib,而无需您进行任何其他工作。 您可以通过参考PyInstaller文档了解有关PyInstaller正式支持的软件包列表的更多信息。

Don’t worry if some of your dependencies aren’t listed in the official docs. Many Python packages work fine. In fact, PyInstaller is popular enough that many projects have explanations on how to get things working with PyInstaller.

如果您的某些依赖项未在官方文档中列出,请不要担心。 许多Python软件包都可以正常工作。 实际上,PyInstaller非常受欢迎,以至于许多项目都有关于如何使PyInstaller正常运行的解释。

In short, the chances of your project working out of the box are high.

简而言之,您的项目开箱即用的机会很高。

To try creating an executable with all the defaults, simply give PyInstaller the name of your main entry-point script.

要尝试创建具有所有默认设置的可执行文件,只需为PyInstaller指定主入口点脚本的名称即可。

First, cd in the folder with your entry-point and pass it as an argument to the pyinstaller command that was added to your PATH when PyInstaller was installed.

首先,在带有入口点的文件夹中cd并将其作为参数传递给安装pyinstaller时添加到PATHpyinstaller命令。

For example, type the following after you cd into the top-level reader directory if you’re following along with the feed reader project:

例如,键入以下命令后你cd到顶层reader目录,如果你使用的feed阅读器项目沿如下:

 $ pyinstaller cli.py
$ pyinstaller cli.py

Don’t be alarmed if you see a lot of output while building your executable. PyInstaller is verbose by default, and the verbosity can be cranked way up for debugging, which you’ll see later.

如果在生成可执行文件时看到大量输出,请不要惊慌。 默认情况下,PyInstaller是冗长的,并且可以将冗长的方式提高为进行调试,您将在稍后看到。

深入了解PyInstaller工件 (Digging Into PyInstaller Artifacts)

PyInstaller is complicated under the hood and will create a lot of output. So, it’s important to know what to focus on first. Namely, the executable you can distribute to your users and potential debugging information. By default, the pyinstaller command will create a few things of interest:

PyInstaller在后台很复杂,会产生很多输出。 因此,重要的是要先了解什么。 即,可以分发给用户的可执行文件和潜在的调试信息。 默认情况下, pyinstaller命令将创建一些有趣的东西:

  • A *.spec file
  • A build/ folder
  • A dist/ folder
  • *.spec文件
  • build/文件夹
  • dist/文件夹

规格文件 (Spec File)

The spec file will be named after your CLI script by default. Sticking with our previous example, you’ll see a file called cli.spec. Here’s what the default spec file looks like after running PyInstaller on the cli.py file:

默认情况下,spec文件将以您的CLI脚本命名。 继续前面的示例,您将看到一个名为cli.spec的文件。 cli.py文件上运行PyInstaller之后,默认的规范文件如下cli.py

This file will be automatically created by the pyinstaller command. Your version will have different paths, but the majority should be the same.

该文件将由pyinstaller命令自动创建。 您的版本将具有不同的路径,但大多数路径应相同。

Don’t worry, you don’t need to understand the above code to effectively use PyInstaller!

不用担心,您不需要了解上面的代码即可有效地使用PyInstaller!

This file can be modified and re-used to create executables later. You can make future builds a bit faster by providing this spec file instead of the entry-point script to the pyinstaller command.

可以修改此文件并在以后重新使用它来创建可执行文件。 通过提供此spec文件而不是pyinstaller命令的入口点脚本,可以使以后的构建更快pyinstaller

There are a few specific use-cases for PyInstaller spec files. However, for simple projects, you won’t need to worry about those details unless you want to heavily customize how your project is built.

PyInstaller规范文件有一些特定的用例 。 但是,对于简单的项目,除非您想大量自定义项目的构建方式,否则无需担心这些细节。

建立资料夹 (Build Folder)

The build/ folder is where PyInstaller puts most of the metadata and internal bookkeeping for building your executable. The default contents will look something like this:

build/文件夹中,PyInstaller将大部分元数据和内部簿记用于构建可执行文件。 默认内容如下所示:

build/
|
└── cli/
    ├── Analysis-00.toc
    ├── base_library.zip
    ├── COLLECT-00.toc
    ├── EXE-00.toc
    ├── PKG-00.pkg
    ├── PKG-00.toc
    ├── PYZ-00.pyz
    ├── PYZ-00.toc
    ├── warn-cli.txt
    └── xref-cli.html
build/
|
└── cli/
    ├── Analysis-00.toc
    ├── base_library.zip
    ├── COLLECT-00.toc
    ├── EXE-00.toc
    ├── PKG-00.pkg
    ├── PKG-00.toc
    ├── PYZ-00.pyz
    ├── PYZ-00.toc
    ├── warn-cli.txt
    └── xref-cli.html

The build folder can be useful for debugging, but unless you have problems, this folder can largely be ignored. You’ll learn more about debugging later in this tutorial.

build文件夹对于调试非常有用,但是除非遇到问题,否则在很大程度上可以忽略此文件夹。 您将在本教程的后面部分了解有关调试的更多信息。

分区文件夹 (Dist Folder)

After building, you’ll end up with a dist/ folder similar to the following:

构建完成后,您将得到一个类似于以下内容的dist/文件夹:

The dist/ folder contains the final artifact you’ll want to ship to your users. Inside the dist/ folder, there is a folder named after your entry-point. So in this example, you’ll have a dist/cli folder that contains all the dependencies and executable for our application. The executable to run is dist/cli/cli or dist/cli/cli.exe if you’re on Windows.

dist/文件夹包含您要交付给用户的最终工件。 dist/文件夹中,有一个以您的入口点命名的文件夹。 因此,在此示例中,您将有一个dist/cli文件夹,其中包含我们应用程序的所有依赖关系和可执行文件。 如果您使用的是Windows, dist/cli/cli.exe运行的可执行文件是dist/cli/clidist/cli/cli.exe

You’ll also find lots of files with the extension .so, .pyd, and .dll depending on your Operating System. These are the shared libraries that represent the dependencies of your project that PyInstaller created and collected.

根据您的操作系统,您还会发现许多扩展名为.so.pyd.dll的文件。 这些是共享库,表示PyInstaller创建和收集的项目的依赖项。

Note: You can add *.spec, build/, and dist/ to your .gitignore file to keep git status clean if you’re using git for version control. The default GitHub gitignore file for Python projects already does this for you.

注意:如果使用git进行版本控制,则可以在.gitignore文件中添加*.specbuild/dist/ ,以保持git status干净。 Python项目的默认GitHub gitignore文件已为您完成此操作。

You’ll want to distribute the entire dist/cli folder, but you can rename cli to anything that suits you.

您将希望分发整个dist/cli文件夹,但是您可以将cli重命名为适合您的名称。

At this point you can try running the dist/cli/cli executable if you’re following along with the feed reader example.

此时,如果要遵循提要阅读器示例,则可以尝试运行dist/cli/cli可执行文件。

You’ll notice that running the executable results in errors mentioning the version.txt file. This is because the feed reader and its dependencies require some extra data files that PyInstaller doesn’t know about. To fix that, you’ll have to tell PyInstaller that version.txt is required, which you’ll learn about when testing your new executable.

您会注意到,运行可执行文件会导致提及version.txt文件的错误。 这是因为提要阅读器及其依赖项需要一些PyInstaller不知道的额外数据文件。 要解决此问题,您必须告诉PyInstaller需要version.txt ,这将在测试新的可执行文件时了解。

自定义构建 (Customizing Your Builds)

PyInstaller comes with lots of options that can be provided as spec files or normal CLI options. Below, you’ll find some of the most common and useful options.

PyInstaller带有许多选项,可以作为规范文件或常规CLI选项提供。 在下面,您将找到一些最常见和有用的选项。

--name

--name

Change the name of your executable.

更改可执行文件的名称。

This is a way to avoid your executable, spec file, and build artifact folders being named after your entry-point script. --name is useful if you have a habit of naming your entry-point script something like cli.py, as I do.

这是避免您的可执行文件,规范文件和构建工件文件夹以入口点脚本命名的方法。 如果您习惯于像cli.py这样命名入口点脚本,则--name很有用。

You can build an executable called realpython from the cli.py script with a command like this:

您可以使用以下命令从cli.py脚本构建名为realpython的可执行文件:

 $ pyinstaller cli.py --name realpython
$ pyinstaller cli.py --name realpython

--onefile

--onefile

Package your entire application into a single executable file.

将整个应用程序打包到一个可执行文件中。

The default options create a folder of dependencies and and executable, whereas --onefile keeps distribution easier by creating only an executable.

默认选项创建一个包含依赖项和可执行文件的文件夹,而--onefile通过仅创建一个可执行文件--onefile使分发更加容易。

This option takes no arguments. To bundle your project into a single file, you can build with a command like this:

此选项不带参数。 要将项目捆绑到一个文件中,可以使用以下命令进行构建:

With the above command, your dist/ folder will only contain a single executable instead of a folder with all the dependencies in separate files.

使用上面的命令,您的dist/文件夹将只包含一个可执行文件,而不是所有依赖关系都位于单独文件中的文件夹。

--hidden-import

--hidden-import

List multiple top-level imports that PyInstaller was unable to detect automatically.

列出PyInstaller无法自动检测到的多个顶级导入。

This is one way to work around your code using import inside functions and __import__(). You can also use --hidden-import multiple times in the same command.

这是使用内部函数import__import__()解决代码的一种方法。 您也可以在同一命令中多次使用--hidden-import

This option requires the name of the package that you want to include in your executable. For example, if your project imported the requests library inside of a function, then PyInstaller would not automatically include requests in your executable. You could use the following command to force requests to be included:

此选项需要您要包含在可执行文件中的软件包的名称。 例如,如果您的项目将请求库导入到函数内部,则PyInstaller不会自动将requests包括在可执行文件中。 您可以使用以下命令来强制包含requests

 $ pyinstaller cli.py --hiddenimport$ pyinstaller cli.py --hiddenimport =requests
= requests

You can specify this multiple times in your build command, once for each hidden import.

您可以在构建命令中多次指定此选项,每次隐藏导入一次。

--add-data and --add-binary

--add-data--add-binary

Instruct PyInstaller to insert additional data or binary files into your build.

指示PyInstaller将其他数据或二进制文件插入构建中。

This is useful when you want to bundle in configuration files, examples, or other non-code data. You’ll see an example of this later if you’re following along with the feed reader project.

当您希望捆绑配置文件,示例或其他非代码数据时,这很有用。 如果您跟随提要阅读器项目,则稍后将看到一个示例。

--exclude-module

--exclude-module

Exclude some modules from being included with your executable

从可执行文件中排除某些模块

This is useful to exclude developer-only requirements like testing frameworks. This is a great way to keep the artifact you give users as small as possible. For example, if you use pytest, you may want to exclude this from your executable:

这对于排除仅开发人员的要求(例如测试框架)很有用。 这是使您给用户的工件尽可能小的好方法。 例如,如果使用pytest ,则可能要从可执行文件中排除它:

-w

-w

Avoid automatically opening a console window for stdout logging.

避免自动打开用于stdout日志记录的控制台窗口。

This is only useful if you’re building a GUI-enabled application. This helps your hide the details of your implementation by allowing users to never see a terminal.

仅在构建支持GUI的应用程序时,此功能才有用。 通过允许用户从不查看终端,这可以帮助您隐藏实现的细节。

Similar to the --onefile option, -w takes no arguments:

--onefile选项类似, -w带任何参数:

 $ pyinstaller cli.py -w
$ pyinstaller cli.py -w

.spec file

.spec file

As mentioned earlier, you can reuse the automatically generated .spec file to further customize your executable. The .spec file is a regular Python script that implicitly uses the PyInstaller library API.

如前所述,您可以重用自动生成的.spec文件来进一步自定义可执行文件。 .spec文件是一个常规的Python脚本,它隐式使用PyInstaller库API。

Since it’s a regular Python script, you can do almost anything inside of it. You can refer to the official PyInstaller Spec file documentation for more information on that API.

由于它是常规的Python脚本,因此您几乎可以在其中执行任何操作。 您可以参考官方的PyInstaller Spec文件文档以获取有关该API的更多信息。

测试新的可执行文件 (Testing Your New Executable)

The best way to test your new executable is on a new machine. The new machine should have the same OS as your build machine. Ideally, this machine should be as similar as possible to what your users use. That may not always be possible, so the next best thing is testing on your own machine.

测试新可执行文件的最佳方法是在一台新计算机上。 新计算机应与构建计算机具有相同的操作系统。 理想情况下,此机器应与用户使用的机器尽可能相似。 这可能并不总是可能的,所以下一个最好的事情就是在自己的机器上进行测试。

The key is to run the resulting executable without your development environment activated. This means run without virtualenv, conda, or any other environment that can access your Python installation. Remember, one of the main goals of a PyInstaller-created executable is for users to not need anything installed on their machine.

关键是在不激活开发环境的情况下运行生成的可执行文件。 这意味着在没有virtualenvconda或任何其他可以访问您的Python安装程序的环境下运行。 请记住,PyInstaller创建的可执行文件的主要目标之一是使用户不需要在其计算机上安装任何东西。

Picking up with the feed reader example, you’ll notice that running the default cli executable in the dist/cli folder fails. Luckily the error points you to the problem:

在提要feed阅读器示例中,您会注意到在dist/cli文件夹中运行默认的cli可执行文件失败。 幸运的是,错误指出了问题所在:

The importlib_resources package requires a version.txt file. You can add this file to the build using the --add-data option. Here’s an example of how to include the required version.txt file:

importlib_resources软件包需要一个version.txt文件。 您可以使用--add-data选项将此文件添加到构建中。 这是一个如何包含所需的version.txt文件的示例:

 $ pyinstaller cli.py $ pyinstaller cli.py 
    --add-data venv/reader/lib/python3.6/site-packages/importlib_resources/version.txt:importlib_resources

    --add-data venv/reader/lib/python3.6/site-packages/importlib_resources/version.txt:importlib_resources

This command tells PyInstaller to include the version.txt file in the importlib_resources folder in a new folder in your build called importlib_resources.

该命令告诉PyInstaller将version.txt文件包含在importlib_resources文件夹中,该文件位于您的构建中名为importlib_resources的新文件夹中。

Note: The pyinstaller commands use the character to make the command easier to read. You can omit the when running commands on your own or copy and paste the commands as-is below provided you’re using the same paths.

注意: pyinstaller命令使用 字符,使命令更易于阅读。 您可以省略 如果您使用相同的路径,则在自己运行命令或按原样复制并粘贴命令时,如下所示。

You’ll want to adjust the path in the above command to match where you installed the feed reader dependencies.

您将需要在上述命令中调整路径,以匹配安装Feed阅读器依赖项的位置。

Now running the new executable will result in a new error about a config.cfg file.

现在,运行新的可执行文件将导致有关config.cfg文件的新错误。

This file is required by the feed reader project, so you’ll need to make sure to include it in your build:

提要阅读器项目需要此文件,因此您需要确保将其包括在构建中:

Again, you’ll need to adjust the path to the file based on where you have the feed reader project.

同样,您将需要根据您的Feed阅读器项目的位置来调整文件的路径。

At this point, you should have a working executable that can be given directly to users!

此时,您应该有一个可以直接提供给用户的有效可执行文件!

调试PyInstaller可执行文件 (Debugging PyInstaller Executables)

As you saw above, you might encounter problems when running your executable. Depending on the complexity of your project, the fixes could be as simple as including data files like the feed reader example. However, sometimes you need more debugging techniques.

如上所述,运行可执行文件时可能会遇到问题。 根据项目的复杂程度,修复可能很简单,例如像供稿阅读器示例一样包含数据文件。 但是,有时您需要更多的调试技术。

Below are a few common strategies that are in no particular order. Often times one of these strategies or a combination will lead to a break-through in tough debugging sessions.

以下是一些没有特定顺序的常见策略。 通常,这些策略之一或二者结合会导致艰难的调试会话取得突破。

使用终端 (Use the Terminal)

First, try running the executable from a terminal so you can see all the output.

首先,尝试从终端运行可执行文件,以便可以看到所有输出。

Remember to remove the -w build flag to see all the stdout in a console window. Often, you’ll see ImportError exceptions if a dependency is missing.

记住要删除-w build标志,以在控制台窗口中查看所有stdout 如果缺少依赖项,通常会看到ImportError异常。

调试文件 (Debug Files)

Inspect the build/cli/warn-cli.txt file for any problems. PyInstaller creates lots of output to help you understand exactly what it’s creating. Digging around in the build/ folder is a great place to start.

检查build/cli/warn-cli.txt文件是否存在问题。 PyInstaller会创建大量输出,以帮助您准确了解其创建的内容。 build/文件夹中挖掘是一个很好的起点。

单一目录构建 (Single Directory Builds)

Use the --onedir distribution mode of creating distribution folder instead of a single executable. Again, this is the default mode. Building with --onedir gives you the opportunity to inspect all the dependencies included instead of everything being hidden in a single executable.

使用--onedir分发模式创建分发文件夹,而不是单个可执行文件。 同样,这是默认模式。 使用--onedir使您有机会检查所有包含的依赖项,而不是将所有隐藏在单个可执行文件中的依赖项。

--onedir is useful for debugging, but --onefile is typically easier for users to comprehend. After debugging you may want to switch to --onefile mode to simplify distribution.

--onedir对于调试很有用,但--onefile通常更易于用户理解。 调试后,您可能需要切换到--onefile模式以简化分发。

其他CLI选项 (Additional CLI Options)

PyInstaller also has options to control the amount of information printed during the build process. Rebuild the executable with the --log-level=DEBUG option to PyInstaller and review the output.

PyInstaller还具有控制构建过程中打印的信息量的选项。 使用PyInstaller的--log-level=DEBUG选项重建可执行文件,并查看输出。

PyInstaller will create a lot of output when increasing the verbosity with --log-level=DEBUG. It’s useful to save this output to a file you can refer to later instead of scrolling in your Terminal. To do this, you can use your shell’s redirection functionality. Here’s an example:

当使用--log-level=DEBUG增加详细程度时,PyInstaller将创建大量输出。 将输出保存到以后可以参考的文件中很有用,而不是在终端中滚动。 为此,您可以使用外壳程序的重定向功能 。 这是一个例子:

 $ pyinstaller --log-level$ pyinstaller --log-level =DEBUG cli.py = DEBUG cli.py 2> build.txt
2 > build.txt

By using the above command, you’ll have a file called build.txt containing lots of additional DEBUG messages.

通过使用以上命令,您将拥有一个名为build.txt的文件, build.txt包含许多其他的DEBUG消息。

Note: The standard redirection with > is not sufficient. PyInstaller prints to the stderr stream, not stdout. This means you need to redirect the stderr stream to a file, which can be done using a 2 as in the previous command.

注意:使用>的标准重定向是不够的。 PyInstaller打印到stderr流,而不是stdout 这意味着您需要将stderr流重定向到文件,可以使用上一个命令中的2来完成。

Here’s a sample of what your build.txt file might look like:

这是您的build.txt文件可能看起来的示例:

This file will have a lot of detailed information about what was included in your build, why something was not included, and how the executable was packaged.

该文件将提供有关构建中包含的内容,为什么不包含某些内容以及如何打包可执行文件的大量详细信息。

You can also rebuild your executable using the --debug option in addition to using the --log-level option for even more information.

除了使用--log-level选项之外,您还可以使用--debug选项重建可执行文件,以获取更多信息。

Note: The -y and --clean options are useful when rebuilding, especially when initially configuring your builds or building with Continuous Integration. These options remove old builds and omit the need for user input during the build process.

注意: -y--clean选项在重建时非常有用,尤其是在最初配置构建或使用Continuous Integration构建时。 这些选项可删除旧版本,并在构建过程中无需用户输入。

其他PyInstaller文件 (Additional PyInstaller Docs)

The PyInstaller GitHub Wiki has lots of useful links and debugging tips. Most notably are the sections on making sure everything is packaged correctly and what to do if things go wrong.

PyInstaller GitHub Wiki具有许多有用的链接和调试技巧。 最值得注意的是都在部分确保一切正确包装 ,做些什么,如果出了问题 。

协助依赖性检测 (Assisting in Dependency Detection)

The most common problem you’ll see is ImportError exceptions if PyInstaller couldn’t properly detect all your dependencies. As mentioned before, this can happen if you’re using __import__(), imports inside functions, or other types of hidden imports.

如果PyInstaller无法正确检测所有依赖项,您将看到的最常见问题是ImportError异常。 如前所述,如果您使用__import__() ,函数内部的导入或其他类型的隐藏导入 ,则可能会发生这种情况。

Many of these types of problems can be resolved by using the --hidden-import PyInstaller CLI option. This tells PyInstaller to include a module or package even if it doesn’t automatically detect it. This is the easiest way to work around lots of dynamic import magic in your application.

通过使用--hidden-import PyInstaller CLI选项,可以解决许多这类问题。 这告诉PyInstaller包括一个模块或软件包,即使它没有自动检测到它也是如此。 这是解决应用程序中许多动态导入魔术的最简单方法。

Another way to work around problems is hook files. These files contain additional information to help PyInstaller package up a dependency. You can write your own hooks and tell PyInstaller to use them with the --additional-hooks-dir CLI option.

解决问题的另一种方法是挂钩文件 。 这些文件包含其他信息,以帮助PyInstaller打包依赖性。 您可以编写自己的钩子,并告诉PyInstaller通过--additional-hooks-dir CLI选项使用它们。

Hook files are how PyInstaller itself works internally so you can find lots of example hook files in the PyInstaller source code.

挂钩文件是PyInstaller本身在内部工作的方式,因此您可以在PyInstaller源代码中找到许多示例挂钩文件。

局限性 (Limitations)

PyInstaller is incredibly powerful, but it does have some limitations. Some of the limitations were discussed previously: hidden imports and relative imports in entry-point scripts.

PyInstaller功能强大,但确实有一些限制。 前面已经讨论了一些限制:隐藏导入和入口点脚本中的相对导入。

PyInstaller supports making executables for Windows, Linux, and macOS, but it cannot cross compile. Therefore, you cannot make an executable targeting one Operating System from another Operating System. So, to distribute executables for multiple types of OS, you’ll need a build machine for each supported OS.

PyInstaller支持制作适用于Windows,Linux和macOS的可执行文件,但不能交叉编译 。 因此,您不能使可执行文件针对另一个操作系统中的一个操作系统。 因此,要为多种类型的操作系统分发可执行文件,您需要为每个受支持的操作系统构建机器。

Related to the cross compile limitation, it’s useful to know that PyInstaller does not technically bundle absolutely everything your application needs to run. Your executable is still dependent on the users’ glibc. Typically, you can work around the glibc limitation by building on the oldest version of each OS you intend to target.

与交叉编译的限制有关,知道PyInstaller从技术上讲绝对不会捆绑您的应用程序需要运行的所有内容,这很有用。 您的可执行文件仍取决于用户的glibc 通常,您可以通过构建要定位的每个操作系统的最旧版glibc解决glibc限制。

For example, if you want to target a wide array of Linux machines, then you can build on an older version of CentOS. This will give you compatibility with most versions newer than the one you build on. This is the same strategy described in PEP 0513 and is what the PyPA recommends for building compatible wheels.

例如,如果要针对各种各样的Linux机器,则可以在较早版本的CentOS上构建。 这将使您与大多数比您所构建的版本更新的版本兼容。 这与PEP 0513中描述的策略相同,也是PyPA建议的用于制造兼容车轮的策略。

In fact, you might want to investigate using the PyPA’s manylinux docker image for your Linux build environment. You could start with the base image then install PyInstaller along with all your dependencies and have a build image that supports most variants of Linux.

实际上,您可能想研究针对Linux构建环境使用PyPA的manylinux docker映像 。 您可以从基础映像开始,然后安装PyInstaller及其所有依赖项,并拥有一个支持大多数Linux变体的构建映像。

结论 (Conclusion)

PyInstaller can help make complicated installation documents unnecessary. Instead, your users can simply run your executable to get started as quickly as possible. The PyInstaller workflow can be summed up by doing the following:

PyInstaller可以使复杂的安装文档变得不必要。 相反,您的用户只需运行您的可执行文件即可尽快上手。 通过执行以下操作可以总结PyInstaller工作流程:

  1. Create an entry-point script that calls your main function.
  2. Install PyInstaller.
  3. Run PyInstaller on your entry-point.
  4. Test your new executable.
  5. Ship your resulting dist/ folder to users.
  1. 创建一个调用主函数的入口点脚本。
  2. 安装PyInstaller。
  3. 在您的入口点运行PyInstaller。
  4. 测试新的可执行文件。
  5. 将生成的dist/文件夹发送给用户。

Your users don’t have to know what version of Python you used or that your application uses Python at all!

您的用户不必知道您使用的是哪个版本的Python或您的应用程序完全使用Python!

翻译自: https://www.pybloggers.com/2019/03/using-pyinstaller-to-easily-distribute-python-applications/

你可能感兴趣的:(使用PyInstaller轻松分发Python应用程序)