从源文件获取 conda meta.yaml 的包版本

Get package version for conda meta.yaml from source file

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

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

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

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

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

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

in 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 is a call to the auxlib.packaging.get_version()的功能。此函数按顺序执行以下操作

  1. 首先查找文件 conda/.version,如果找到 return 则内容作为版本标识符
  2. 接下来寻找 VERSION 环境变量,如果将 return 值设置为版本标识符
  3. 最后查看 git describe --tags 输出,如果可能的话 return 版本标识符(必须安装 git,必须是 git 存储库,等等)
  4. 如果上面的 none 产生版本​​标识符,return None

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

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

这些特殊命令 类 实际上修改了 built/installed 包中的 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

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

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

一个。点击 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

乙。 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.

手动__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 你可以做这样的事情。 这也是我在 sphinx 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/<my_package>/_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/<my_package>/__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"