【问题标题】:how to use distutils to create executable .zip file?如何使用 distutils 创建可执行的 .zip 文件?
【发布时间】:2011-05-31 21:52:14
【问题描述】:

如果 zip 文件在 zip 存档的顶部包含 __main__.py 文件,Python 2.6 及更高版本可以直接执行 .zip 文件。我想利用这个特性来提供我正在开发的工具的预览版本,除了将 .zip 文件复制到他们的磁盘之外,它不需要用户安装任何东西。是否有创建此类 zip 文件的标准方法?我正在寻找适用于 python 2.6 和 python 2.7 的解决方案。

理想情况下,我想使用 distutils,因为当我想进行正常安装时,它已经可以工作了。有没有一种规范的方式来使用(或扩展)distutils 来创建这样的 .zip 文件?

distutils 提供了一个sdist 命令,它创建了一个几乎正确的源分布,但创建的结构有点太深了。

例如,我的源代码树如下所示:

my_package/
  - setup.py
  - src/
      - __main__.py
      - module1/
      - module2/
      - module3/

当我执行python setup.py sdist 时,我最终会得到一个具有以下结构的 .zip 文件:

my_package-0.1.zip
  - my_package-0.1/
      - README.txt
      - PKG_INFO
      - src/
          - __main__.py
          - module1/
          - module2/
          - module3/

这是不可执行的,因为__main__.py 不在分发的顶部。实际上,我想要的是一个不包含src,而只包含src 下的文件的src 发行版。那个,或者正是 sdist 给我的,但在存档顶部有一个额外的 __main__.py

【问题讨论】:

    标签: python distutils python-2.6


    【解决方案1】:

    更新:由于setup.cfg 是全局的,它会影响所有命令的“install-lib”设置,这不是我们想要的。不幸的是,(据我所知)无法通过命令行将选项传递给子命令,例如如果您指定bdist --install-lib=/,它将引发错误,而不是将其传递给子命令。

    要为install 子命令自定义install-libbdist 运行时,您可以将bdist_dumb 命令子类化并在install 子命令之后手动设置路径构造/重新初始化:

    setup.py

    from distutils.core import setup
    from distutils.command.bdist_dumb import bdist_dumb
    
    class custom_bdist_dumb(bdist_dumb):
    
        def reinitialize_command(self, name, **kw):
            cmd = bdist_dumb.reinitialize_command(self, name, **kw)
            if name == 'install':
                cmd.install_lib = '/'
            return cmd
    
    if __name__ == '__main__':
        setup(
            # our custom class override
            cmdclass = {'bdist_dumb': custom_bdist_dumb},
            name='my_package',
            py_modules = ['__main__'],
            packages = ['module1', 'module2'],
            package_dir = {'': 'src'}
        )
    

    跑步:

    % python setup.py bdist --format=zip
    % unzip -l dist/my_package-0.0.0.linux-x86_64.zip
    Archive:  dist/my_package-0.0.0.linux-x86_64.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
          184  2011-05-31 20:34   my_package-0.0.0.egg-info
           30  2011-05-31 20:34   __main__.py
          128  2011-05-31 20:34   __main__.pyc
          107  2011-05-31 20:34   module1/__init__.pyc
            0  2011-05-31 20:27   module1/__init__.py
          107  2011-05-31 20:34   module2/__init__.pyc
            0  2011-05-31 20:27   module2/__init__.py
    ---------                     -------
          556                     7 files
    
    % python dist/my_package-0.0.0.linux-x86_64.zip
    my_package working.
    

    【讨论】:

    • 然而,我发现这样做意味着“setup.py install”会失败,因为它试图写入“/”。我需要能够创建 .zip 文件并以正常方式安装。
    • @Bryan 我已经更新了解决此问题的答案,您可以删除 setup.cfg 更改。希望该解决方案对您有用。
    • FWIW,当我在 cygwin shell 中的 windows 上运行它时(不确定这是否重要......)我得到了 'ValueError: path '/' cannot be absolute'。将 cmd.install_lib = '/' 更改为 cmd.install_lib = '\\' 可以解决这个问题。
    【解决方案2】:

    也可以通过将以下__main__.py 文件放到.zip 的根目录中来使sdist 可执行:

    import os
    import sys
    
    # add package .zip to python lookup path
    __dir__ = os.path.dirname(__file__)
    path = os.path.join(__dir__, 'my_package-0.1', 'src')
    sys.path.insert(0, path)
    
    import module1
    module1.main()
    

    这会将存档中的源子目录添加到sys.path,以便可以从module1 导入。

    我现在不知道如何修补 distutils sdist 命令以自动将此 __main__.py 注入 .zip,但这绝对是真实的。

    【讨论】:

      猜你喜欢
      • 2011-10-22
      • 1970-01-01
      • 2010-12-29
      • 1970-01-01
      • 1970-01-01
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 2011-04-12
      相关资源
      最近更新 更多