【问题标题】:How do I create and load an egg-file in Python?如何在 Python 中创建和加载 egg 文件?
【发布时间】:2018-04-27 10:55:27
【问题描述】:

我正在研究一种将 python 模块作为单个 egg 文件分发的方法。假设我有一个名为my_module 的python 模块,并且我想编写一个python 脚本来为我的模块生成一个egg 文件。于是我找到了setuptools

from setuptools import setup

setup(
    name="my_module",
    packages=[my_package],
    version="1.0",
)

在这些问题上我有一些缺点:

  1. 此脚本应以python setup.py install 运行。换句话说,我需要指定命令行参数。相反,我想在我的 python 代码中自动生成我的 egg 文件,它可以自己控制命令行参数。
  2. 结果文件被输出到安装程序的文件目录中。我想控制脚本中的输出目录路径。
  3. 脚本创建了我实际上并不需要的builddist 文件夹。也许,我可以通过在调用setup 后删除文件夹来解决它。

我应该如何使用setuptools 来解决上述问题?

还有如何从给定的 egg-file 加载我的模块?


假设我有以下模块:

# my_module.py

class MyClass:
    def __init__(self):
        self._x = None

    def set_x(self, x):
        self._x = x

    def get_x(self):
        return self._x

我写了这个脚本来创建一个鸡蛋文件:

# create_egg.py

from setuptools import setup

setup(
    name="my_module",
    packages=['my_module'],
    version="1.0",
)

当我运行 creage_egg.py: 时出现这样的错误:

$ python3 create_egg.py
usage: create_egg.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
   or: create_egg.py --help [cmd1 cmd2 ...]
   or: create_egg.py --help-commands
   or: create_egg.py cmd --help

error: no commands supplied

【问题讨论】:

  • 这是一个很好的问题,但对于这个网站来说有点“过于宽泛”。如果你在尝试实现你想要的东西时对问题进行细分并询问具体问题,你会得到更好的答案。
  • @PauloScardine 感谢您的建议。稍后我会修改我的问题。
  • 你应该运行python3 create_egg.py bdist_egg。运行 python3 create_egg.py --help-commands 以获取其他命令

标签: python setuptools egg


【解决方案1】:

我发现的第一件事是一个包必须是一个目录。所以有必要保持这样的结构:

my_project/
    my_module/
        __init__.py
    output/
    create_egg.py
test_egg.py

要跳过指定命令行参数的必要性,有一个特殊选项script_args。我在这里找到了它:http://peak.telecommunity.com/DevCenter/setuptools

我的__init__.py

class MyClass:
    def __init__(self):
        self._x = None

    def set_x(self, x):
        self._x = x

    def get_x(self):
        return self._x

我的create_egg.py

import os
import shutil
from setuptools import setup


OUTPUT_DIR = 'output'


if __name__ == "__main__":
    setup(
        name="my_module",
        packages=['my_module'],
        version="1.0",
        script_args=['--quiet', 'bdist_egg'], # to create egg-file only
    )

    egg_name = os.listdir('dist')[0]

    os.rename(
        os.path.join('dist', egg_name),
        os.path.join(OUTPUT_DIR, egg_name)
    )

    shutil.rmtree('build')
    shutil.rmtree('dist')
    shutil.rmtree('my_module.egg-info')

我的test_egg.py

import sys
sys.path.append('my_project/output/my_module-1.0-py3.5.egg')

import my_module


obj = my_module.MyClass()
obj.set_x(29)
print(obj.get_x())

创建 egg 文件:

~/Stuff/my_project $ python3 create_egg.py 
zip_safe flag not set; analyzing archive contents...

测试模块:

~/Stuff $ python3 test_egg.py 
29

【讨论】:

  • * 是一个优秀的 rubber-duck
  • 通常您将调用setup() 写入一个名为setup.py 的文件中,然后您将其作为python setup.py --quiet bdist_egg 调用,可能使用诸如make 之类的构建工具。在根目录中拥有这样一个 setup.py 文件是使您的项目可安装 Pip 的原因。如果你有 Pip(你应该在任何最近的 Python 版本上)你可以简单地做pip install ~/Stuff/my_project,只要setup.py 是 PIp 期望的内容和位置。作为额外的好处,您不再需要与sys.path 混淆。
  • 还可以考虑使用 Wheel 格式而不是 Egg 格式。请参阅here 进行比较(以及许多其他好的信息)。