init()

这是一个可选方法,用于初始化 conanfile 的值,专为从 python_requires 继承而设计。假设我们有一个 base/1.1 配方

base/conanfile.py
from conan import ConanFile

class MyConanfileBase:
    license = "MyLicense"
    settings = "os", # tuple!


class PyReq(ConanFile):
    name = "base"
    version = "1.1"
    package_type = "python-require"

我们可以通过以下方式重用并继承它:

pkg/conanfile.py
from conan import ConanFile

class Pkg(ConanFile):
    license = "MIT"
    settings = "arch", # tuple!
    python_requires = "base/1.1"
    python_requires_extend = "base.MyConanfileBase"

    def init(self):
        base = self.python_requires["base"].module.MyConanfileBase
        self.settings = base.settings + self.settings  # Note, adding 2 tuples = tuple
        self.license = base.license  # License is overwritten

最终的 Pkg conanfile 将同时具有 osarch 作为设置,以及 MyLicense 作为许可证。

要扩展基类的 options,有必要调用 self.options.update() 方法

base/conanfile.py
from conan import ConanFile

class BaseConan:
    options = {"base": [True, False]}
    default_options = {"base": True}

class PyReq(ConanFile):
    name = "base"
    version = "1.0.0"
    package_type = "python-require"

当调用 init() 时,self.options 对象已经初始化。然后,更新 self.default_options 是无用的,有必要同时使用基类选项和基类默认选项值来更新 self.options

pkg/conanfile.py
from conan import ConanFile

class DerivedConan(ConanFile):
    name = "derived"
    python_requires = "base/1.0.0"
    python_requires_extend = "base.BaseConan"
    options = {"derived": [True, False]}
    default_options = {"derived": False}

    def init(self):
        base = self.python_requires["base"].module.BaseConan
        # Note we pass the base options and default_options
        self.options.update(base.options, base.default_options)

如果您需要无条件地初始化类属性,例如 licensedescription,或者从 conandata.yml 以外的数据文件中加载其他属性,那么此方法也可能很有用。例如,您可以有一个 json 文件,其中包含关于库的 licensedescriptionauthor 的信息。

data.json
{"license": "MIT", "description": "This is my awesome library.", "author": "Me"}

然后,您可以在 init() 方法中加载该信息。

import os
import json
from conan import ConanFile
from conan.tools.files import load


class Pkg(ConanFile):
    exports = "data.json" # Important that it is exported with the recipe

    def init(self):
        data = load(self, os.path.join(self.recipe_folder, "data.json"))
        d = json.loads(data)
        self.license = d["license"]
        self.description = d["description"]
        self.author = d["author"]

注意

最佳实践

  • 尽量保持您的 python_requires 尽可能简单,并且不要重用它们的属性(init() 方法的主要需求),尽量避免 init() 方法的复杂性。总的来说,继承可能比组合(或者换句话说,“优先使用组合而非继承”,作为一种通用的编程良好实践)有更多的问题,所以如果可能的话,尽量避免它。

  • 不要滥用 init() 来处理此处未列出的其他目的,也不要使用 Python 私有的 ConanFile.__init__ 构造函数。

  • init() 方法在配方加载时执行。它不能包含对设置、选项、配置的条件判断,也不能使用除上述 python_requires 之外的任何依赖信息。