【问题标题】:How do you get the filename of a Python wheel when running setup.py?运行 setup.py 时如何获取 Python 轮子的文件名?
【发布时间】:2019-01-27 02:03:39
【问题描述】:

我有一个使用以下命令创建 Python 轮子的构建过程:

python setup.py bdist_wheel

构建过程可以在许多平台(Windows、Linux、py2、py3 等)上运行,我想保留默认输出名称(例如mapscript-7.2-cp27-cp27m-win_amd64.whl)以上传到 PyPI。

是否有办法获取生成的轮子的文件名(例如mapscript-7.2-cp27-cp27m-win_amd64.whl)并保存到变量中,以便稍后在脚本中安装轮子进行测试?

理想的解决方案是跨平台。我目前的方法是尝试清除文件夹,列出所有文件并选择列表中的第一个(也是唯一一个)文件,但这似乎是一个非常hacky的解决方案。

【问题讨论】:

  • 您需要在设置脚本中(简单)还是在一些自定义代码中(困难)中提供此信息?
  • 主要目的是随后能够复制生成的文件,并在命令行上安装轮子 - --find-links 选项解决了这个问题,而无需知道文件名。如果不获取文件列表和解析名称就可以实现它,我仍然很感兴趣
  • 我需要这个,所以我可以将轮文件推送到我的私有包索引
  • @cowlicks - twine 可以指向上传包的文件夹 - 查看当前答案
  • @hoefling 你能分享一下简单的解决方案吗?我可能可以从那里开始工作。

标签: python cross-platform setup.py python-wheel


【解决方案1】:

setuptools

如果您使用setup.py 脚本来构建wheel 分发,您可以使用bdist_wheel 命令查询wheel 文件名。此方法的缺点是它使用bdist_wheel 的私有API,因此如果作者决定更改wheel 包更新,代码可能会中断。

from setuptools.dist import Distribution


def wheel_name(**kwargs):
    # create a fake distribution from arguments
    dist = Distribution(attrs=kwargs)
    # finalize bdist_wheel command
    bdist_wheel_cmd = dist.get_command_obj('bdist_wheel')
    bdist_wheel_cmd.ensure_finalized()
    # assemble wheel file name
    distname = bdist_wheel_cmd.wheel_dist_name
    tag = '-'.join(bdist_wheel_cmd.get_tag())
    return f'{distname}-{tag}.whl'

wheel_name 函数接受您传递给setup() 函数的相同参数。用法示例:

>>> wheel_name(name="mydist", version="1.2.3")
mydist-1.2.3-py3-none-any.whl
>>> wheel_name(name="mydist", version="1.2.3", ext_modules=[Extension("mylib", ["mysrc.pyx", "native.c"])])
mydist-1.2.3-cp36-cp36m-linux_x86_64.whl

请注意,本机库的源文件(上例中的mysrc.pyxnative.c)不必存在即可组装车轮名称。这在本机库的源不存在的情况下很有帮助(例如,您稍后通过 SWIG、Cython 或其他方式生成它们)。

这使得wheel_name 可以在您定义分发元数据的setup.py 脚本中轻松重用:

# setup.py
from setuptools import setup, find_packages, Extension
from setup_helpers import wheel_name

setup_kwargs = dict(
    name='mydist',
    version='1.2.3',
    packages=find_packages(),
    ext_modules=[Extension(...), ...],
    ...
)
file = wheel_name(**setup_kwargs)
...
setup(**setup_kwargs)

如果您想在设置脚本之外使用它,您必须自己组织对 setup() args 的访问(例如,从 setup.cfg 脚本或其他方式中读取它们)。

这部分大致基于我对setuptools, know in advance the wheel filename of a native library的其他回答

poetry

如果您使用poetry,事情可以大大简化(实际上是单行),因为所有相关元数据都存储在pyproject.toml 中。同样,这使用了一个未记录的 API:

from clikit.io import NullIO

from poetry.factory import Factory
from poetry.masonry.builders.wheel import WheelBuilder
from poetry.utils.env import NullEnv


def wheel_name(rootdir='.'):
    builder = WheelBuilder(Factory().create_poetry(rootdir), NullEnv(), NullIO())
    return builder.wheel_filename

rootdir 参数是包含您的pyproject.toml 脚本的目录。

flit

AFAIK flit 无法使用本机扩展构建轮子,因此它只能为您提供 purelib 名称。不过,如果您的项目使用flit 进行分发构建,它可能会很有用。请注意,这也使用了未记录的 API:

from flit_core.wheel import WheelBuilder
from io import BytesIO
from pathlib import Path


def wheel_name(rootdir='.'):
    config = str(Path(rootdir, 'pyproject.toml'))
    builder = WheelBuilder.from_ini_path(config, BytesIO())
    return builder.wheel_filename

实施您自己的解决方案

我不确定这是否值得。不过,如果您想选择这条路径,请考虑使用packaging.tags,然后再找到一些旧的已弃用的东西,甚至决定自己查询平台。不过,您仍然需要使用私人物品来组装正确的车轮名称。

【讨论】:

    【解决方案2】:

    我目前安装轮子的方法是将 pip 指向包含轮子的文件夹并让它自行搜索:

    python -m pip install --no-index --find-links=build/dist mapscript
    

    twine 也可以直接指向一个文件夹,而无需知道确切的轮子名称。

    【讨论】:

    • 这实际上并没有回答关于如何以编程方式确定 setup.py 脚本的输出文件名称的问题。
    • 技术上没有——这就是我接受另一个答案的原因。但是,如果有人想知道要安装或上传他们刚刚创建的轮子的文件名,那么这个答案可能会对某人有所帮助。它无需完全知道文件名。
    【解决方案3】:

    我使用了 hoefling 解决方案的修改版本。我的目标是将构建复制到“最新”轮文件。 setup() 函数将返回一个包含您需要的所有信息的对象,因此您可以找出它实际构建的内容,这似乎比上面的解决方案更简单。假设你有一个变量version在使用中,下面会得到我刚刚建立的文件名,然后复制它。

    setup = setuptools.setup(
        # whatever options you currently have
        )
    wheel_built = 'dist/{}-{}.whl'.format(
        setup.command_obj['bdist_wheel'].wheel_dist_name,
        '-'.join(setup.command_obj['bdist_wheel'].get_tag()))
    wheel_latest = wheel_built.replace(version, 'latest')
    shutil.copy(wheel_built, wheel_latest)
    print('Copied {} >> {}'.format(wheel_built, wheel_latest))
    

    我想一个可能的缺点是您必须实际进行构建才能获得名称,但由于这是我工作流程的一部分,我对此表示满意。 hoefling 的解决方案的好处是可以让您在不进行构建的情况下规划名称,但它似乎更复杂。

    【讨论】:

    • 如果您运行除 bdist_wheel 之外的其他 setup.py 命令(例如 clean),那么 command_obj 将不包含“bdist_wheel”键,您将收到错误消息。
    猜你喜欢
    • 2019-07-01
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 2014-01-23
    相关资源
    最近更新 更多