运行setup.py时,如何获取Python控制盘的文件名?

运行setup.py时,如何获取Python控制盘的文件名?,python,cross-platform,setup.py,python-wheel,Python,Cross Platform,Setup.py,Python Wheel,我有一个使用以下命令创建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)并将其保存到变量中,以便稍后在脚本中安装控制盘进行测试 理想情况下

我有一个使用以下命令创建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
)并将其保存到变量中,以便稍后在脚本中安装控制盘进行测试


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

我当前安装控制盘的方法是将pip指向包含控制盘的文件夹,让它自己搜索:

python -m pip install --no-index --find-links=build/dist mapscript
绳线也可以直接指向文件夹,而无需知道确切的滚轮名称

setuptools
如果使用
setup.py
脚本来构建控制盘分发,则可以使用
bdist\u 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\u 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
请注意,本机libs的源文件(
mysrc.pyx
或上例中的
native.c
)不必存在,就可以组合控制盘名称。如果本机库的源还不存在(例如,您稍后将通过SWIG、Cython或其他方式生成它们),这将非常有用

这使得
wheel\u 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
脚本或任何内容中读取它们)

这一部分大致基于我对这个问题的另一个答案

诗歌
如果您使用
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
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
rootdir
参数是包含
pyproject.toml
脚本的目录

flit
AFAIK
flit
无法使用本机扩展构建控制盘,因此它只能为您提供purelib名称。然而,如果您的项目将
flit
用于分发构建,那么它可能会很有用。请注意,这也使用了未记录的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
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
实现您自己的解决方案
我不确定这是否值得。不过,如果你想选择这条路径,在找到一些旧的被废弃的东西之前,考虑一下使用,甚至决定自己去查询这个平台。不过,您仍然需要使用私人工具来组装正确的车轮名称。

我使用了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的解决方案的好处是让您可以在不进行构建的情况下规划名称,但它似乎更复杂

在安装脚本(简单)或某些自定义代码(硬)中是否需要此信息?主要目的是能够复制生成的文件,并在命令行上安装控制盘--find links选项解决了此问题,而无需知道文件名。我仍然感兴趣的是,如果不获取文件列表和解析名称就可以实现它,那么我需要它,这样我就可以将wheel文件推送到我的私有包中index@cowlicks-可以将捆绳指向文件夹以上载包-请参阅当前answer@hoefling你能分享一下简单的解决方案吗?我可能会从那里开始工作。如果您运行的是其他setup.py命令,而不是bdist_wheel(例如clean),然后,command_obj将不包含“bdist_wheel”键,您将收到一条错误消息。这实际上没有回答有关如何通过编程确定setup.py脚本的输出文件名的问题。技术上没有-这就是我接受另一个答案的原因。但是,如果有人想知道安装或上传他们刚刚创建的控制盘的文件名,那么这个答案可能会对其他人有所帮助。它不必完全知道文件名。