Common basics¶
The various eclasses in python-r1 try to follow a single design. You will probably use more than one of them, so it is worthwhile to shortly explain the common bits used by all of them, as well as the non-obvious differences between them.
PYTHON_COMPAT¶
The PYTHON_COMPAT variable is used by all Python eclasses, and must
be declared in all ebuilds before they are inherited. It specifies
the list of Python implementations supported by the package.
The valid values are:
pythonX_Yfor CPython X.YpythonX_Ytfor CPython X.Y freethreadingpypy3for PyPy3.10pypy3_Yfor PyPy3.Y (used with PyPy 3.11 and newer)
Typical use:
PYTHON_COMPAT=( python3_{10..13} pypy3 pypy3_11 )
inherit python-single-r1
PYTHON_DEPS and PYTHON_REQUIRED_USE¶
The python-any-r1, python-single-r1 and python-r1 eclasses
all assume that the developer is responsible for explicitly putting
the dependency strings and USE requirements in correct variables.
This is meant to consistently cover packages that use Python
unconditionally and conditionally, at build time and at runtime.
For python-single-r1 and python-r1, the most basic form to use
Python unconditionally is to define the following:
REQUIRED_USE=${PYTHON_REQUIRED_USE}
RDEPEND=${PYTHON_DEPS}
BDEPEND=${RDEPEND}
For python-any-r1, only build-time dependencies are used:
BDEPEND=${PYTHON_DEPS}
This does not apply to distutils-r1 as it does the above assignment
by default.
Python environment¶
The eclasses commonly use the concept of Python environment. This means a state of environment enforcing a particular Python implementation. Whenever the ebuild code is run inside this environment, two variables referring to the specific Python interpreter are being exported:
EPYTHONcontaining the interpreter’s basename (also used as the implementation identifier), e.g.python3.10PYTHONcontaining the absolute final path to the interpreter, e.g./usr/bin/python3.10
The full path should only be used to provide the value that should
be embedded in the installed programs, e.g. in the shebangs.
For spawning Python during the build, EPYTHON is preferable.
Warning
Using full path rather than the basename will bypass the virtualenv
created by distutils-r1.eclass in PEP 517 mode. This may cause
failures to import Python modules, or use of the previous installed
version rather than the just-built one. Using ${EPYTHON}
resolves these problems.
Wrappers for python, pythonN and some common tools are provided
in PATH, and /usr/bin/python etc. also enforce the specific
implementation via python-exec (for programs that hardcode full path).
The environment can be either established in local scope, or globally.
The local scope generally applies to multi-impl packages, and is created
either by calls to python_foreach_impl from python-r1, or inside
sub-phase functions in distutils-r1. The global scope setup is done
via calling python_setup, either directly or via default
pkg_setup in python-any-r1 and python-single-r1.
Dependencies in Python packages¶
Note
The following sections focus specifically on dependencies that are Python packages. Python software often depends on external tools, libraries written in other programming languages, etc. For these dependencies, the usual Gentoo rules apply.
The most common dependency types¶
The dependencies found in Python packages can usually be classified into two categories: runtime dependencies and build-time dependencies.
Runtime dependencies are packages that are required to be present
in order for the installed Python modules and scripts to be usable.
In general, these are all packages whose modules are imported
in the installed Python files. Generally runtime dependencies
are not needed at build time and therefore the build systems
do not verify whether they are installed. However, modern Python
scripts based on entry points often refuse to run if their dependencies
are not satisfied. Runtime dependencies should be placed
in RDEPEND.
A special subclass of runtime dependencies are optional runtime dependencies (often called ‘extra’ dependencies). The dependencies are optional if the package can still be meaningfully functional when they are not installed. This usually means that the package either handles failing imports gracefully, or that they are imported only in a subset of package’s installed modules and that the package can still be meaningfully used without importing these modules.
There are multiple approaches to handling optional dependencies. Depending on the specifics, they can:
be added unconditionally to
RDEPEND(if they are considered important and/or light enough);be listed as an informational message in
pkg_postinst(usually utilizingoptfeature.eclass);be added to
RDEPENDconditionally to USE flags (this is only acceptable if the package is cheap to rebuild).
Build-time dependencies are the packages needed for the package
to be built and installed. In general, they include the packages
providing the build system. In some cases, they may also include some
runtime dependencies, e.g. when they are needed to import
the __init__.py of the package. As a rule of thumb, if the package
can be built correctly when the specific dependency is not installed,
it does not need to be listed as a build dependency. Most of the time,
build dependencies belong in BDEPEND.
The distutils-r1 class generally takes care of adding the dependency
on the build system and basic tooling. However, additional plugins
(e.g. dev-python/setuptools_scm) need to be listed explicitly.
A special class of build-time dependencies are requirements specific
to running the test suite and building documentation. Most of the time
the former include not only the test runner but also all runtime
dependencies of the package (since the test suite runs its code).
Sometimes this is also required to build documentation. These classes
of dependencies go into BDEPEND under test and doc USE flags
respectively.
Note that sometimes test dependencies can also be optional (including optional runtime dependencies). They should generally be added unconditionally to ensure maximum test coverage. Also note that (as explained further in the Guide), some test dependencies (e.g. on linters or coverage reporting tools) may actually be undesirable.
Again, distutils-r1 provides functions to conveniently add support
for common test runner and Sphinx-based documentation. The former also
takes care of copying RDEPEND into test dependencies.
Some Python packages include C extensions that depend on external
libraries. In this case, similarly to non-Python packages,
the dependency on packages providing these libraries needs to go
into RDEPEND and DEPEND (not BDEPEND).
Finally, there are Python packages providing C headers such
as dev-python/numpy. If the package in question uses both headers
and Python code from NumPy, the dependency may need to be included
in all three of RDEPEND, DEPEND and BDEPEND (unconditionally
or for tests).
Finding dependency lists from build systems¶
Most of the modern Python build systems include all the package metadata
in the pyproject.toml file. Setuptools are using setup.cfg
and/or setup.py. Some packages also include custom code to read
dependencies from external files; it is usually worthwhile to look
for requirements in the name.
Warning
Unconditional runtime dependencies and unconditional build-time dependencies are often enforced by the script wrappers and build systems respectively. If upstream lists spurious dependencies, they often need to be explicitly stripped rather than just ommitted from ebuild.
The keys commonly used to list specific kinds of dependencies in common Python build systems:
Runtime dependencies (unconditional):
PEP 621 metadata:
project.dependenciesolder flit versions:
tool.flit.metadata.requirespoetry:
tool.poetry.dependencies(note: this also includes specialpythonentry to indicate compatible Python versions)setuptools:
install_requires
Optional runtime and/or build-time dependencies:
PEP 621 metadata:
project.optional-dependenciesolder flit versions:
tool.flit.metadata.requires-extrapoetry:
tool.poetry.dependencieswithoptional = true, sometimes grouped usingtool.poetry.extrassetuptools:
extras_require
Build-time dependencies (unconditional):
all
pyproject.tomlbuild systems:build-system.requirespoetry:
tool.poetry.dev-dependenciessetuptools:
setup_requires(deprecated)
Test dependencies (in addition to
RDEPEND):often listed as
testkey in optional dependenciessetuptools:
tests_require(deprecated)in some cases they can also be found in
tox.iniornoxfile.py
Doc building dependencies:
often listed as
dockey in optional dependencies
Python version compatibility:
PEP 621 metadata:
project.requires-pythonolder flit versions:
tool.flit.metadata.requires-pythonpoetry:
pythonintool.poetry.dependenciessetuptools:
python_requires