init()¶
This is an optional method for initializing conanfile values, designed for inheritance from python_requires.
Assuming we have a base/1.1 recipe:
from conan import ConanFile
class MyConanfileBase:
license = "MyLicense"
settings = "os", # tuple!
class PyReq(ConanFile):
name = "base"
version = "1.1"
package_type = "python-require"
We could reuse and inherit from it with:
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
The final Pkg conanfile will have both os and arch as settings, and MyLicense as license.
To extend the options of the base class, it is necessary to call the self.options.update() method:
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"
When the init() is called, the self.options object is already initialized. Then, updating the
self.default_options is useless, and it is necessary to update the self.options with both the
base class options and the base class default options values:
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)
This method can also be useful if you need to unconditionally initialize class attributes like
license or description or any other from datafiles other than
conandata.yml. For example, you can have a json file containing the information about the
license, description and author for the library:
{"license": "MIT", "description": "This is my awesome library.", "author": "Me"}
Then, you can load that information from the init() method:
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"]
Note
Best practices
Try to keep your
python_requiresas simple as possible, and do not reuse attributes from them (the main need for theinit()method), trying to avoid the complexity of thisinit()method. In general inheritance can have more issues than composition (or in other words “use composition over inheritance” as a general programming good practice), so try to avoid it if possible.Do not abuse
init()for other purposes other than listed here, nor use the Python privateConanFile.__init__constructor.The
init()method executes at recipe load time. It cannot contain conditionals on settings, options, conf, or use any dependencies information other than the abovepython_requires.