【问题标题】:Get package version for conda meta.yaml from source file从源文件获取 conda meta.yaml 的包版本
【发布时间】:2016-08-12 13:58:13
【问题描述】:

我正在尝试重新组织我的 python 包版本控制,因此我只需在一个地方更新版本,最好是 python 模块或文本文件。对于我需要我的版本的所有地方,似乎有一种方法可以从源 from mypkg import __version__ 加载它,或者至少将它作为文本从文件中解析出来。不过,我似乎找不到使用 conda meta.yaml 文件的方法。有没有办法在 meta.yaml 文件中从外部源加载版本?

我知道有 git 环境变量,但我不想标记通过本地 conda 存储库测试的每个 alpha/beta/rc 提交。我可以在 pyyaml 中使用 !!python/object 加载 python 对象,但 conda 不支持任意 python 执行。我看不到任何其他 jinja2 功能的方法。我也可以编写一个脚本来更新多个地方的版本号,但我真的希望只修改一个文件作为最终版本号。感谢您的帮助。

【问题讨论】:

  • 仅供参考,在得到更好的答案之前,任何人都可以这样做:我已经确定了 git 标签 并且 我在 setup.py 中添加了一个特殊命令,用于增加版本我正在使用的一些打包工具(Windows 的 Inno Setup),我的 version.py,以及执行所需的 git 提交和标记。

标签: python conda


【解决方案1】:

截至conda-build-3.16.1(2018 年 11 月),这是在 conda 配方中以编程方式设置 version 的方法。

这些示例是您传递给conda-buildmeta.yaml 的一部分,如here 所述。

A.进入setup.py的版本:

如果你构建一个 python 包,这个秘诀是完美的,因为setup.py 无论如何都需要它,所以你一定已经想好了。

{% set data = load_setup_py_data() %}

package:
  name: mypackage
  version: {{ data.get('version') }}

请注意,有时您必须明确告诉 conda 配方在哪里找到它,如果它与 setup.py 不在同一个目录中:

{% set data = load_setup_py_data(setup_file='../setup.py', from_recipe_dir=True) %}

现在继续:

$ conda-build conda-recipe

B. Git 环境变量

如果您的项目在 git 中被标记,并且您使用 conda 接受作为有效版本号的标记格式(例如 2.5.1v2.5.1),则此方法很好。

package:
  name: hub
  version: {{ GIT_DESCRIBE_TAG }}

现在继续:

$ conda-build conda-recipe

C.传递环境变量:

这对于非 python conda 包很有用,其中版本来自各种不同的地方,你可以完善它的价值——例如将v2.5.1 转换为2.5.1

package:
  name: mypkg
  version: {{ environ.get('MYPKG_VERSION', '') }}

然后创建一个获取版本的可执行脚本,我们称之为script-to-get-mypkg-version

现在继续加载将设置版本的环境变量:

$ MYPKG_VERSION=`script-to-get-mypkg-version` conda-build conda-recipe

根据 conda-build 版本,您可能必须使用 os.environ.get 而不是 environ.getdocs 使用后者。


这不起作用

请注意,如果这在过去可以正常工作,如 2016 年的答案之一所述,那么现在将无法正常工作。

package:
  name: mypkg
build:
  script_env:
    - VERSION

$ VERSION=`script-to-get-mypkg-version` conda-build conda-recipe

conda-build 在这种情况下会忽略环境变量VERSION

source.

【讨论】:

  • 对于C,我认为应该是os.environ.getenviron.get 对我不起作用。
  • 谢谢,增加了这种可能性。 docs 在没有 os 的情况下使用它,并且它在没有它的情况下对我有用,也许他们最近停止导入 from os
【解决方案2】:

有很多方法可以到达您的端点。这就是 conda 本身的作用......

conda 版本信息的真实来源是__version__ in conda/__init__.py。它可以按照您的建议在 python 代码中以from conda import __version__ 的形式以编程方式加载。它也被硬连线到setup.pyhere(也请注意this code),所以从命令行python setup.py --version 是获取该信息的规范方式。

在 conda-build 的 1.x 版本中,加一行

$PYTHON setup.py --version > __conda_version__.txt

build.sh 将使用我们的真实来源设置构建包的版本。 __conda_version__.txt 文件已弃用,但是,它可能会随着 conda-build 2.0 的发布而被删除。在最新版本的 conda-build 中,首选的方法是在 jinja2 上下文中使用 load_setup_py_data(),这将使您能够访问来自 setup.py 的所有元数据。具体来说,在meta.yaml 文件中,我们会有这样的内容

package:
  name: conda
  version: "{{ load_setup_py_data().version }}"

现在,__version__ 变量是如何在conda/__init__.py 中设置的...

see in the source code 是对 auxlib.packaging.get_version() 函数的调用。该函数按顺序执行以下操作

  1. 首先查找文件conda/.version,如果找到则返回内容作为版本标识符
  2. 接下来查找VERSION 环境变量,如果设置则返回值作为版本标识符
  3. 最后查看git describe --tags 输出,并尽可能返回版本标识符(必须安装 git,必须是 git repo 等)
  4. 如果以上都没有产生版本标识符,则返回None

现在还有最后一招。在 conda 的setup.py file 中,我们将cmdclassbuild_pysdist 设置为auxlib.packaging 提供的那些。基本上我们有

from auxlib import packaging
setup(
    cmdclass={
        'build_py': packaging.BuildPyCommand,
        'sdist': packaging.SDistCommand,
    }
)

这些特殊的命令类实际上修改了内置/安装包中的conda/__init__.py 文件,因此__version__ 变量被硬编码为字符串文字,并且不使用auxlib.packaging.get_version() 函数。


在您的情况下,不想标记每个版本,您可以使用以上所有方法,并从命令行使用VERSION 环境变量设置版本。类似的东西

VERSION=1.0.0alpha1 conda build conda.recipe

在您的 build 部分 meta.yaml 配方中,您需要添加一个 script_env 键来告诉 conda-build 将 VERSION 环境变量一直传递到构建环境。

build:
  script_env:
    - VERSION

【讨论】:

  • 我要补充一点,github.com/conda/conda-build/tree/master/tests/test-recipes/… 中有这样的示例,并且这适用于在 setup.py 中设置版本的任何方式 - versioneer、setuptools-scm 或其他任何方式。另请注意,load_setup_py_data 曾经被命名为 load_setuptools。这在 1.21.12 中发生了变化。这两个名称现在都有效,但 load_setuptools 会输出一条关于被弃用的警告消息。
  • 太棒了。从load_setup_py_data 的 PR 看来,这似乎已经很久没有可用了(至少现在这样命名)。感谢帮助,我今天去试试。 ...但是当我引起您的注意时,来自 anaconda 的软件包的错误报告(段错误等)应该放在 conda/condaContinuumIO/anaconda-recipes 中吗?
  • 包的错误报告通常应该去 ContinuumIO/anaconda-issues 。如果您对配方有特定改进,请在 ContinuumIO/anaconda-recipes 上提交 PR 或问题。 conda/conda 专门用于解决包管理工具 conda 的问题。
  • @msarahan 这就是我的想法,但对于我不确定的软件包,conda/conda 似乎有很多问题。
  • @kalefranz 感谢您让我知道load_setup_py_data,这正是我所需要的。有没有计划将此记录在案?
【解决方案3】:

手册__version__

如果您在单独的_version.py 中有版本,您可以在不加载整个包的情况下导入。

# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
version = '0.0.9.post2+g6481728.d20200518.dirty'

在我的情况下,这是自动生成的,但下一步保持不变。

__init__.py 中有一行from ._version import version as __version__

然后在setup.py 你可以做这样的事情。 这也是我在狮身人面像中导入版本的方式conf.py

source_dir = Path("src/<my_package>")
sys.path.insert(0, str(source_dir))

from _version import  version

setup(version=version)
...

或者,您可以尝试手动解析它,而不是导入_version 文件,这样您就不必在sys.path 中添加任何内容

然后在meta.yaml

{% set data = load_setup_py_data() %}
{% set version = data.get('version')  %}


package:
  name: <my_package>
  version: {{ version }}

我遇到了相反的问题。我忘记不时更新我的​​版本,所以一直在寻找一种将git 存储库作为包版本的单一来源的方法。我用setuptools_scm

我尝试了很多东西,无论是否符合 pep517 pyproject.toml 等等,但最终,这对我有用。

这样做的好处是您不需要那么大的versioneer.py,但它会在构建时写入_version.py

setup.py

from setuptools import setup
import setuptools_scm


def my_local_scheme(version: setuptools_scm.version.ScmVersion) -> str:
    """My local node and date version."""
    node_and_date = setuptools_scm.version.get_local_node_and_date(version)
    dirty = ".dirty" if version.dirty else ""
    return str(node_and_date) + dirty

version = setuptools_scm.get_version(
    write_to="src/<my_package>/_version.py",
    version_scheme="post-release",
    local_scheme=my_local_scheme,
)
setup(version=version,)

setup() 中的其余元数据和选项位于 setup.cfg 中。需要的一个是:

[options]
package_dir=
    =src
packages = <my_package>
install_requires = setuptools_scm

src/&lt;my_package&gt;/_version.py

生成:

# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
version = '0.0.3.post0+g887e418.d20200518.dirty'

然后我将它添加到我的.gitignore

src/&lt;my_package&gt;/__init__.py

"""<package_description>"""
from ._version import version as  __version__

meta.yaml

{% set data = load_setup_py_data() %}
{% set version = data.get('version')  %}


package:
  name: capacity_simulation
  version: {{ version }}

source:
  path: .

build:
  noarch: python
  number: {{ environ.get('GIT_DESCRIBE_NUMBER', 0) }}
  script: python -m pip install --no-deps --ignore-installed .
  include_recipe: False

requirements:
  build:
    - setuptools_scm
...

pyproject.toml

为了也能使用pip wheel .

你需要pyproject.toml中的这个部分

[build-system]
requires = ["setuptools>=34.4", "wheel", "setuptools_scm"]
build-backend = "setuptools.build_meta"

【讨论】:

  • 所以对于我最初的问题的答案,您是在重复@stason 在他们的答案(A 部分)中的内容,对吧?
  • 是的,但是setup.py 获取版本的来源是从 CVS 自动获取的。我一直在寻找这个很多,所以我想分享我的解决方案。如果您在__init__.py 中手动设置它。您可以将其加载到您的setup.py
  • 我好像有点误读了你的问题。我添加了如何从另一个文件中获取它。我在我的狮身人面像中使用它conf.py
猜你喜欢
  • 1970-01-01
  • 2020-08-12
  • 1970-01-01
  • 2016-09-29
  • 1970-01-01
  • 1970-01-01
  • 2015-01-09
  • 1970-01-01
相关资源
最近更新 更多