Creating noarch packages
noarch packages are packages that do not ship platform or architecture specific contents and therefore do not have to be built separately for each subdir.
For example, the tzdata package provides only data files that are installed into the same layout irrespective of the system used.
Rather than building a number of roughly the same linux-64, linux-aarch64, osx-64, etc. packages, we can build a single noarch package that can be installed on all of these platforms.
Declaring packages as noarch reduces the use of shared CI and CDN resources.
Therefore all packages that qualify to be noarch packages should be declared as such.
There are currently two types of noarch packages supported:
noarch: pythonthat is used for Python packages that feature no files specific to Python versionnoarch: genericthat is used for all other cases (e.g. R, Perl, data-only packages)
noarch: python
The noarch: python directive, in the build section, creates packages that are compatible with multiple platforms and multiple Python versions.
This is similar in spirit to the py3-none-any wheels.
When a non-noarch package is being built, a separate package is being built for every Python version on every supported platform.
For example, when a package supports Python 3.10 through 3.14, and linux-64, linux-arm64, osx-64, osx-arm64 and win-64 platforms, this means building 5 packages per platform times 5 platforms, which totals 25 packages.
For a pure Python package, this would actually mean 25 packages with the same contents.
Every package is built on the appropriate OS, using the matching Python version.
All build dependencies must be available for all platforms, and if the package needs build scripts, they also need to be available in appropriate variants.
Conversely, when noarch: python is enabled, a single noarch package is built for all supported Python versions and all platforms.
Typically, the build is performed on a Linux system using the oldest Python version supported, and the necessary adjustments to make it universal are performed automatically.
The advanced how-to covers the topic of building noarch packages on other platforms.
Requirements
In order to qualify as a noarch: python package, all of the following criteria must be fulfilled:
- The package contents must be invariant across Python versions and platforms.
- This means that the package must not compile any extensions.
For packages with
abi3extensions, see ABI3 packages. - Typically, the package must not rely on platform-specific build scripts, unless they produce the same results.
- This means that the package must not compile any extensions.
For packages with
- No post-link or pre-link or pre-unlink scripts may be used.
- The recipe must not use selectors.
- Requirements that are version-restricted upstream can be listed unconditionally in the recipe instead.
- If the specific requirement is incompatible with a newer Python version, the package will built successfully. The package manager will display an appropriate error if one attempts to install this package along with the newer Python version. However, when the dependency is rebuilt for the new Python version, your package will become installable immediately, with no need to build a new version.
- Instead of
skip: match(python, ...),python_minneeds to be overridden, see overriding the minimum Python version. - The advanced how-to explains how to express OS-specific dependencies.
scriptsargument insetup.pymust not be used.- It is recommended to replace explicit scripts with entry points upstream.
- If
console_scriptsentry points are used, they must be listed in thebuildsection of the recipe: asentry_pointsin v0 format orpython.entry_pointsin v1 format. This is necessary for the package manager to generate the correct platform-appropriate scripts.- These entry points can be found in
[project.scripts]table inpyproject.toml, or inentry_points→console_scriptsinsetup.pyorsetup.cfgfiles. - Other types of entry points do not require special treatment.
- These entry points can be found in
Package type comparison
noarch: python | regular Python package |
|---|---|
| A single package, with optional OS variants. | Packages for every platform, with variants for every Python version. |
| Can be installed on any platform, on any Python version that meets the constraints. | Can be installed only on platform and Python version combinations it was built for. |
Built on Linux, using python_min. | Built on every supported OS, using every supported Python version. |
| Cannot include Python extensions or files specific to platform or Python version. | Can install any files. |
| Has to use entry points. | Can use entry points and setuptools scripts. |
| Dependencies must be the same for all Python versions (but they do not have to be satisfiable on all of them). | Dependencies can be conditional to Python versions. |
Expressing Python version requirements
All recipes employing noarch: python must use the python_min variable as follows:
- The host and test requirements must pin to
{{ python_min }}.*. This ensures that the build will fail if the package actually requires newer Python version than the one specified inpython_min. - The run requirement must list
python_min >={{ python_min }}, permitting the whole range of supported versions at runtime.
- v0 (meta.yaml)
- v1 (recipe.yaml)
name: package
source:
# ...
build:
noarch: python
# ...
requirements:
host:
- python {{ python_min }}.*
# ...
run:
- python >={{ python_min }}
# ...
test:
requires:
- python {{ python_min }}.*
# ...
name: package
source:
# ...
build:
noarch: python
# ...
requirements:
host:
- python ${{ python_min }}.*
# ...
run:
- python >=${{ python_min }}
# ...
tests:
- python:
python_version:
- ${{ python_min }}.*
- "*"
# ...
- requirements:
run:
- python ${{ python_min }}.*
script:
# ...
See CFEP-25 for more details on this syntax.
Overriding the minimum Python version
If you need to override the minimum Python version, you can add a Jinja2 set statement (or equivalent context variable for v1 recipes) at the top of your recipe:
- v0 (meta.yaml)
- v1 (recipe.yaml)
{% set python_min = "3.12" %}
context:
python_min: "3.12"
It also possible to achieve the same effect by adding a conda_build_config.yaml file to your recipe that
contains a map like
python_min:
- "3.12"
If you go that route, you will need to rerender the feedstock
after adding the conda_build_config.yaml file.
If the minimum Python version supported by the package is older or the same as the minimum version supported by conda-forge (python_min in conda-forge-pinning), please remove the python_min override, so that the global setting (and any subsequent updates to it) take effect.
Converting existing packages to noarch
If an existing python package qualifies to be converted to a noarch package, you can request the required changes by opening a new issue and including @conda-forge-admin, please add noarch: python (see examples).
noarch: generic
add some information on r packages which make heavy use of noarch: generic