使用PEX打包Python可执行文件

pex(https://github.com/pantsbuild/pex)代表 Python EXecutable,是一种生成易于分发的 python 包的方法。需要注意的一件重要事情是 pex 没有可靠的 Windows 支持。因此,您需要在 *NIX 系统上运行 pex。本文将展示您可以使用 pex 执行的一些操作,以分发不同类型的 python 项目。

基本用法

鉴于用于 pex 打包的 python 解释器很重要,强烈建议使用虚拟环境。作为示例,我将使用 python 3.11 环境:

$ virtualenv --python=python3.11 venv
$ source venv/bin/activate
$ python -m pip install pex
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple
Collecting pex
  Using cached https://www.piwheels.org/simple/pex/pex-2.1.144-py2.py3-none-any.whl (2.9 MB)
Installing collected packages: pex
Successfully installed pex-2.1.144

pex CLI 执行的一般格式为:

pex [MODULES] [OPTIONS]

其中[MODULES]是 pip 样式依赖项声明字符串中以空格分隔的模块列表:

$ pex "requests" "setproctitle==1.3.2" "uvicorn[standard]"
Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

如果没有任何其他选项,pex 将进入交互式 shell,并且提供的模块将在以下位置可用:

>>> import requests
>>> import setproctitle
>>> import uvicorn
>>>

关闭控制台后我们可以看到虚拟环境包完全不受影响:

$ pip list
Package    Version
---------- -------
pex        2.1.144
pip        23.2.1
setuptools 65.5.0
$

需求管理

由于列出每个模块通常并不理想,因此可以使用两种替代方法来传递需求。第一个解决方案是使用requirements.txt文件:

requirements.txt

requests
setproctitle==1.3.2
uvicorn[standard]

然后可以使用传入的-r选项和requirements.txt文件运行 pex:

$ pex -r requirements.txt 
Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

-r如果您捆绑了多个项目,也可以多次传递参数。如果您已经设置了虚拟环境,那么您可以传递pip freeze到pex:

$ pex $(pip freeze)
Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.(InteractiveConsole)
>>>

requirements.txt如果您有很多模块需要使用,那么该方法会很好。pip freeze对于已经设置了 virtualenv 的情况很有用。

Python 项目结构化模块

pex 还支持 python 包作为模块,其结构类似于python 打包文档中的基本结构。对于此示例,我将使用此 git 存储库中的项目布局(https://github.com/cwgem/pex_simple)。它包括一个带有自述文件、许可证、简单模块和 pyproject.toml 的基本布局。这足以让它被pex像开发模式 pip install 一样识别:

$ pex .
Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from simple_pex import simple_math
>>> simple_math(3,4)
7
>>>

这一切都是在无需构建项目本身的情况下实现的。

资源目录

pex还可以添加重要项目的目录,例如测试数据和配置。在应用程序存储库中有一个resources目录,其中包含一个test_data.json如下所示的文件:

{
    "a": 1,
    "b": 2
}

我们可以使用pex参数-D来添加用于捆绑的特定目录。然后可以在脚本/交互式提示中使用它,如下所示:

$ pex . -D resources
Python 3.11.4 (main, Aug 17 2023, 03:18:09) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)>>> from simple_pex import simple_math
>>> import json
>>> fp = open('resources/test_data.json', 'r')
>>> data = json.load(fp)
>>> fp.close()
>>> simple_math(data['a'], data['b'])
3
>>>

正如您所看到的,JSON 数据被加载,然后传递给simple_math返回正确结果的函数。

切入点

python 脚本的一项功能是能够像运行基本程序一样设置入口点。对于此示例,我将使用此存储库中托管的代码(https://github.com/cwgem/pex_simple_cli)。使这项工作有效的是控制台脚本的声明,如下所示:

[project.scripts]adder = "cli_pex:run"

这将生成一个名为“adder”的脚本,该脚本将从包run中执行cli_pex:

import argparse
def run():
    parser = argparse.ArgumentParser()
    parser.add_argument("--integer1", type=int, help="First Integer")
    parser.add_argument("--integer2", type=int, help="Second Integer")
    args = parser.parse_args()
    print(args.integer1 + args.integer2)

虽然不是一个非常实用的程序,但它可以完成展示 pex 如何与控制台脚本一起工作的工作。为了展示这一点:

$ pex . -o adder.pex -c adder
$ ./adder.pex --integer1 3 --integer2 4
7

using-c告诉 pex 我们要adder使用pyproject.toml. 现在,当我们打包所有内容时,它就像一个基本程序一样。还有一个使用固定参数的选项,因此只.pex需要执行文件:

$ pex . -o adder.pex -c adder --inject-args "--integer1 3 --integer2 4"
$ ./adder.pex 
7

这对于轻松部署采用绑定端口和主机名等参数的服务器脚本非常有用。

Docker 部署

为了将这一切放在一起,我将对 pex Web 应用程序进行 Docker 部署。它将把 Gunicorn 与 Flask 应用程序捆绑在一起,该应用程序将充当容器的入口点。可以在此处找到此示例中使用的代码(https://github.com/cwgem/pex_web_example)。在此设置中,有一个简单的 Flask 应用程序、一个 Gunicorn 配置文件和一个用于启用部署的 Dockerfile。这次pyproject.toml声明了一些依赖项:

dependencies = [
    "flask",
    "gunicorn",
    "setproctitle",
]

另一件需要考虑的事情是,pex 需要将其打包的系统设置与目标系统相当接近。这意味着我将在 Unbuntu 盒子上构建,而我的容器将基于 Debian(更精简,并且系统足够接近)。其他一些需要完成的事情:

  • pex可执行文件需要指向gunicorn控制台脚本才能运行服务器

  • Gunicorn 配置文件需要复制到系统中

  • --inject-args需要将--config参数设置为gunicorn配置

  • 生成的.pex文件需要设置为入口点

查看需求,结果pex调用将是:

pex . -o web_pex.pex -c gunicorn --inject-args "--config /home/gunicorn/app/gunicorn.config.py"

虽然 Dockerfile 看起来像:

FROM python:3.11.4-bullseye

USER root
RUN useradd -d /home/gunicorn -r -m -U -s /bin/bash gunicorn

USER gunicorn
RUN mkdir /home/gunicorn/app
COPY config/gunicorn.config.py /home/gunicorn/app
COPY web_pex.pex /home/gunicorn/app

ENTRYPOINT /home/gunicorn/app/web_pex.pex
EXPOSE 8000

鉴于构建.pex捆绑包的解释器是 python 3.11,我将其设置为基础映像。现在剩下的就是构建 Dockerfile,然后运行生成的映像:

$ docker buildx build  -f Dockerfile -t flask/web-pex:latest .
$ docker run -it -p 8000:8000 flask/web-pex:latest
[2023-08-25 00:13:11 +0000] [7] [INFO] Starting gunicorn 21.2.0
[2023-08-25 00:13:11 +0000] [7] [INFO] Listening at: http://0.0.0.0:8000 (7)
[2023-08-25 00:13:11 +0000] [7] [INFO] Using worker: sync
[2023-08-25 00:13:11 +0000] [8] [INFO] Booting worker with pid: 8
[2023-08-25 00:13:11 +0000] [9] [INFO] Booting worker with pid: 9

这将运行新创建的flask/web-pex:latest映像并公开端口 8000。现在使用curl 进行测试:

$ curl http://127.0.0.1:8000 
Hello World

感谢setproctitle进程列表也变得更清晰:

$ ps auxUSER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
gunicorn       1  0.0  0.0   2480   512 pts/0    Ss+  00:13   0:00 /bin/sh -c /home/gunicorn/app/web_pex.pex
gunicorn       7  4.5  0.2  53904 48244 pts/0    S+   00:13   0:00 gunicorn: master [gunicorn]
gunicorn       8  1.1  0.3  63244 52084 pts/0    S+   00:13   0:00 gunicorn: worker [gunicorn]
gunicorn       9  0.6  0.3  62024 51644 pts/0    S+   00:13   0:00 gunicorn: worker [gunicorn]
gunicorn      10  0.5  0.0   6052  3784 pts/1    Ss   00:13   0:00 /bin/bash
gunicorn      17  0.0  0.0   8648  3276 pts/1    R+   00:13   0:00 ps aux

这使得更容易辨别容器上的各种gunicorn进程。

工具

另一个有趣的功能是 pex 还提供了一些可用的工具,可以让我们创建性能更高的 docker 镜像。为了使这项工作正常进行,我们需要添加--include-tools到pex构建命令中:

$ pex . -o web_pex.pex -c gunicorn --inject-args "--config /home/gunicorn/app/gunicorn.config.py" --include-tools

Dockerfile 还将更新为多阶段构建以生成最终的映像:

FROM python:3.11.4-bullseye as deps
RUN mkdir -p /home/gunicorn/app
COPY web_pex.pex /home/gunicorn/
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /home/gunicorn/web_pex.pex venv --scope=deps --compile /home/gunicorn/app
FROM python:3.11.4-bullseye as srcs
RUN mkdir -p /home/gunicorn/app
COPY web_pex.pex /home/gunicorn
COPY config/gunicorn.config.py /home/gunicorn/app
RUN PEX_TOOLS=1 /usr/local/bin/python3.11 /home/gunicorn/web_pex.pex venv --scope=srcs --compile /home/gunicorn/app
FROM python:3.11.4-bullseyeRUN useradd -d /home/gunicorn -r -m -U -s /bin/bash gunicorn
COPY --from=deps --chown=gunicorn:gunicorn /home/gunicorn/app /home/gunicorn/app
COPY --from=srcs --chown=gunicorn:gunicorn /home/gunicorn/app /home/gunicorn/app
USER gunicorn
ENTRYPOINT /home/gunicorn/app/pex
EXPOSE 8000

这将分离依赖项和源编译。当 python 进行编译时,它将创建一组特定于解释器的字节码,因此不必在运行时完成。这使得事情运行得更快。docker 构建的唯一变化是 Dockerfile 不同,而运行命令保持不变:

$ docker buildx build  -f Dockerfile_pex_tools -t flask/web-pex:latest .
$ docker run -it -p 8000:8000 flask/web-pex:latest
[2023-08-25 01:25:47 +0000] [7] [INFO] Starting gunicorn 21.2.0
[2023-08-25 01:25:47 +0000] [7] [INFO] Listening at: http://0.0.0.0:8000 (7)
[2023-08-25 01:25:47 +0000] [7] [INFO] Using worker: sync
[2023-08-25 01:25:47 +0000] [8] [INFO] Booting worker with pid: 8
[2023-08-25 01:25:47 +0000] [9] [INFO] Booting worker with pid: 9

查看容器内部,您可以看到用户目录pex中的布局:~/appgunicorn

$ cd ~/app
$ ls
PEX-INFO  __main__.py  __pycache__  bin  gunicorn.config.py  include  lib  lib64  pex  pyvenv.cfg

并且缓存文件也显示在gunicorn工人生成之前的时间,以表明它们确实是编译输出,而不仅仅是Python自然生成它们:

$ ls -lah lib/python3.11/site-packages/flask/__pycache__/
total 388K
drwxr-xr-x 2 gunicorn gunicorn 4.0K Aug 25 01:03 .
drwxr-xr-x 4 gunicorn gunicorn 4.0K Aug 25 01:03 ..
-rw-r--r-- 1 gunicorn gunicorn 4.0K Aug 25 01:03 __init__.cpython-311.pyc
-rw-r--r-- 1 gunicorn gunicorn  249 Aug 25 01:03 __main__.cpython-311.pyc
-rw-r--r-- 1 gunicorn gunicorn  86K Aug 25 01:03 app.cpython-311.pyc
-rw-r--r-- 1 gunicorn gunicorn  32K Aug 25 01:03 blueprints.cpython-311.pyc

结论

pex对用于打包 Python 代码的了解到此结束。(https://github.com/pantsbuild/pex/issues/716)这是一个有趣的系统,从GitHub 问题来看也具有可重复构建的潜力。启用工具可以轻松地使用单个包部署,同时通过多阶段编译启用更高性能的选项。我鼓励您看看它如何增强您的 Python 项目。


文章来源地址https://www.toymoban.com/diary/python/301.html

到此这篇关于使用PEX打包Python可执行文件的文章就介绍到这了,更多相关内容可以在右上角搜索或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

原文地址:https://www.toymoban.com/diary/python/301.html

如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用
上一篇 2023年08月26日 16:22
下一篇 2023年08月26日 19:36

相关文章

  • Python使用最新版pyinstaller将项目或程序打包成exe或者mac中的可执行文件

    pyinstaller 能够在 Windows、Linux、Mac 等操作系统下将 Python 源文件打包,通过对源文件打包, Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个独立文件方便传递和管理。 PyInstaller 支持 Python 2.7 和 Python 3.3+。可以在 Windows、Mac 和 Linux 上使用,但是并不是跨平台的,

    2024年02月08日
    浏览(53)
  • Python3.9使用最新版pyinstaller将项目或程序打包成exe或者mac中的可执行文件

    pyinstaller 能够在 Windows、Linux、Mac 等操作系统下将 Python 源文件打包,通过对源文件打包, Python 程序可以在没有安装 Python 的环境中运行,也可以作为一个独立文件方便传递和管理。 PyInstaller 支持 Python 2.7 和 Python 3.3+。可以在 Windows、Mac 和 Linux 上使用,但是并不是跨平台的,

    2024年02月09日
    浏览(64)
  • 通过pyinstaller将python项目打包成exe执行文件

    目录 第一步:安装pyinstaller 第二步:获取一个ico图标(也即是自己这个exe文件最后的图标) 第三步:打包 pip install pyinstaller 先从这里获取一个png图片:iconfont-阿里巴巴矢量图标库 再转化成ico图片(推荐256 x 256):PNG转ICO - 在线转换图标文件  可以把得到的ico图片放在pytho

    2024年02月09日
    浏览(56)
  • python项目打包成exe可执行文件(pyinstaller库)

    前言:才入职新公司;进来工作内容,就是将之前的python脚本项目打包成.exe可执行文件;一来方便不同岗位的同事之间使用,二来源码信息不会改动和泄漏。 正因为python具有丰富的第三方库,目前已有数万之多;这里用到的是 \\\'pyinstaller\\\'库; 正文: 两种情况: Ⅰ、单独一个

    2024年02月06日
    浏览(49)
  • python 打包项目(包含.ui文件,.dll文件)为exe可执行文件

    目录 1. 背景 2. 生成.spec文件: 3. 编辑.spec文件: 4. 最后生成单个可执行文件.exe:  5 补充: 1. 背景         最近在项目中想做一个用于烧录MCU的上位机给工厂用。于是在某工程模板上简单开发了一个基于python 和pyQt5的上位机软件。项目包含多个.py文件,多个.dll文件,一

    2024年02月16日
    浏览(45)
  • 科普:python怎么使用Pyinstaller模块打包成可执行文件

    创建个虚拟环境来打包,以免把整个系统的乱七八糟的pip的都打包进去,建议每个项目创建对应的虚拟环境。 比如: conda create -n myenv python=3.10 PS:还需要安装项目依赖的其他模块,建议用requirements.txt文件安装 -h,–help 查看该模块的帮助信息 -F,-onefile 产生单个的可执行文

    2024年02月08日
    浏览(58)
  • Python使用pyinstaller打包成.exe文件执行后闪退的解决办法

    1、程序在PyChram中运行正常,但是用pyinstaller将程序打包成.exe文件执行后闪退; 2、使用cmd在在.exe文件处./执行后,发现提示 No module named ‘ttkbootstrap’ ,没有ttkbootstrap模块; 3、在工程文件的venvLibsite-packages下,确实存在ttkbootstrap包;这个包不知什么原因没打包进.exe文件,

    2024年02月12日
    浏览(65)
  • pycharm内如何打包py项目为.exe可执行文件

    1.通过命令:pip install pyinstaller 具体操作:打开pycharm下方的Terminal终端,输入:pip install pyinstaller,回车  2.在pycharm设置里添加 英文版具体操作:Pycharm左上角 File 选择Settings -  Project Interpreter - 点击图中第4步 “+” 号 -  检索pyinstaller ,选中点击安装 中文版具体操作:Pych

    2023年04月08日
    浏览(86)
  • python打包成mac可执行文件,mac系统怎么打包python

    大家好,小编为大家解答mac系统python程序打包成exe的问题。很多人还不知道python打包成mac可执行文件,现在让我们一起来看看吧! 文章目录 前言 一、pyinstaller是什么? 二、使用步骤 1.安装库 2.pyInstaller生成可执行程序 2.1带命令行的打包 2.2pyinstaller支持的选项 2.3带图形化程序

    2024年01月23日
    浏览(36)
  • Python代码打包成EXE可执行文件(避开打包文件太大的坑)

    ​​​​​​​ 目录 一、博主的成长经历  二、虚拟环境下打包的好处  三、pyinstaller的基础用法 四、虚拟环境打包操作实例 五、成果展示 欢迎大家来观栏~  ——随乔木凉夏 博主最初使用pyinstaller打包py文件的时候,用的很是顺心,命令行复制粘贴,回车键一敲,不用多久

    2024年02月09日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包