具有 OS 特定依赖项的 pip 包

pip package with OS specififc dependency

我想创建一个依赖于某些 OS 特定文件的 pip 包:

假设有:

我不想将所有三个存档都包含在一个包项目中,而是在 pip install my-package 期间根据用户的 OS 动态下载它们。我怎样才能做到这一点 ?我应该把负责 downloading/unzipping 这些文件的代码放在哪里?

我的setup.py看起来像这样:

from setuptools import setup 

setup(
  name='my-package',
  version='0.0.1',
  description='Package description',
  py_modules=['my_package'],
  package_dir={'': 'src'},
  classifiers=[
    'Intended Audience :: Developers',
    'License :: OSI Approved :: MIT License',
    'Operating System :: POSIX :: Linux',
    'Operating System :: Microsoft :: Windows',
    'Operating System :: MacOS',
    'Programming Language :: Python :: 3',
    'Programming Language :: Python :: 3.7'
  ],
  python_requires='>=3.7'
)

第一个答案是放弃并使用 setuptools。查看 Platform specific dependencies 以详细了解该怎么做。

第二个答案是制作单独的包,例如'mylib-mac'、'mylib-win'、'mylib-linux'。

第三个答案是使用 "console_script" 方法。这会破裂。虽然它在 Windows 上生成 .exe 文件,但它有奇怪的故障模式。此外,一些用户将无法动态下载文件,因为他们从存储库的内部克隆工作。生产环境中随机 运行 来自 Internet 的代码会吓到人。

希望对您有所帮助!

一个解决方案可能是发布您项目的平台特定 Python wheels。可以通过自定义 setuptools 命令(可能是 build 的子命令,或者 安装).

这不是一个完整的解决方案,但这样的事情可能是一个好的开始:

#!/usr/bin/env python3

import distutils.command.build
import setuptools

class build_something(setuptools.Command):
    user_options = [
        ('plat-name=', 'p', "platform name to build for"),
    ]
    def initialize_options(self):
        self.plat_name = None
    def finalize_options(self):
        self.set_undefined_options('bdist_wheel', ('plat_name', 'plat_name'))
    def run(self):
        print(" *** plat_name: {} ***".format(self.plat_name))
        print(" *** download the platform specific bits to 'build' ***")

class build(distutils.command.build.build):
    sub_commands = [(
        'build_something',
        None,
    )] + distutils.command.build.build.sub_commands

setuptools.setup(
    cmdclass={
        'build_something': build_something,
        'build': build,
    },
    # ...
)

然后 Python 轮子可以这样构建:

$ ./setup.py bdist_wheel -p win_amd64

平台特定的依赖项可以保存在单独的 Python 项目中(围绕仅数据包的包装器),然后从主项目中需要,如下所示:

# setup.cfg
# ...
[options]
install_requires =
    my_package_win_amd64 ; platform_system=="Windows" and platform_machine=="x86_64"
    my_package_linux-x86_64 ; platform_system=="Linux" and platform_machine=="x86_64"

此方法不依赖于 setuptools,可以与其他构建系统一起使用。