Python Packaging Guidelines
This version of Python Packaging Guidelines is in effect since 2021 and represents a major rewrite and paradigm shift. Not all packages are updated to reflect this. Older guidelines are kept as a historical reference, but new packages MUST NOT use them. Existing packages MUST migrate to the current Python guidelines:
-
“201x-era” Python packaging guidelines (Packages using these usually use the deprecated
%py3_installor%py3_install_wheelmacro or callsetup.py install.)
| These guidelines only support current Fedora releases. For older releases (such as in EPEL 8), consult the 201x-era guidelines. |
The two Distro-wide guidelines below apply to all software in Fedora that uses Python at build- or run-time.
The rest of the Guidelines apply to packages that ship code
that can be imported with Python’s import statement.
Specifically, that is all packages
that install files under /usr/lib*/python*/.
Except for the two “Distro-wide guidelines”, these Guidelines do not apply to simple one-file scripts or utilities, especially if these are included with software not written in Python. However, if an application (e.g. CLI tool, script or GUI app) needs a more complex Python library, the library SHOULD be packaged as an importable library under these guidelines.
A major goal for Python packaging in Fedora is to harmonize with the wider Python ecosystem, that is, the Python Packaging Authority (PyPA) standards and the Python Package Index (PyPI). Packagers SHOULD be prepared to get involved with upstream projects to establish best practices as outlined here. We wish to improve both Fedora and the wider Python ecosystem.
Some build tools (like CMake or autotools)
may not work with the latest PyPA standards yet.
(For example, they might generate .egg-info directories
rather than .dist-info.)
While this document’s normative points (MUST/SHOULD) are tool-agnostic,
many of the practical tips and helper macros will not be applicable.
If this affects you, consider contacting the
Python SIG
for guidance
and/or following the older guidelines
for the time being.
|
| Fedora’s Python SIG not only develops these guidelines, but it’s also involved in PyPA standards and Python packaging best practices. Check out the wiki or mailing list if you need help or wish to help out. |
Distro-wide guidelines
Build-time dependency on python3-devel
Every package that uses Python (at run-time and/or build-time)
and/or installs Python modules
MUST have a build-time dependency on python3-devel,
even if Python is not actually invoked during build-time.
Such a package MUST use one of the following in its .spec file:
-
%pyproject_buildrequiresin the%generate_buildrequiressection -
BuildRequires: python3-devel
Only having a transitive build-time dependency on python3-devel is not sufficient.
If the package uses an alternate Python interpreter instead of python3
(e.g. pypy, jython, python2.7),
it MAY instead require the corresponding *-devel package.
The *-devel package brings in relevant RPM macros.
It may also enable automated or manual checks: for example,
Python maintainers use this requirement to list packages
that use Python in some way
and might be affected by planned changes.
Mandatory macros
The following macros MUST be used where applicable.
The expansions in parentheses are provided only as reference/examples.
The macros are defined for you in all supported Fedora and EPEL versions.
-
%{python3}(/usr/bin/python3): The Python interpreter. For example, this macro should be used for invoking Python from aspecfile script, passed toconfigurescripts to select a Python executable, or used as%{python3} -m pipto run a Python-based tool.If the packaged software invokes Python at run time (as opposed to running Python to build/test it), it might be necessary to pass flags to
%{python3}to isolate it from user-installed packages. See Shebangs for details. -
%{python3_version}(e.g.3.9,3.10): Version of the Python interpreter. -
%{python3_version_nodots}(e.g.39,310): Version of the Python interpreter without the dot. -
%{python3_sitelib}(e.g./usr/lib/python3.9/site-packages): Where pure-Python modules are installed. -
%{python3_sitearch}(e.g./usr/lib64/python3.9/site-packages): Where Python extension modules (native code, e.g. compiled from C) are installed.
The rest of this document uses these macros,
along with %{_bindir} (/usr/bin/),
instead of the raw path names.
Python implementation support
Fedora primarily targets CPython, the reference implementation of the Python language. We generally use “Python” to mean CPython.
Alternate implementations like pypy are available,
but currently lack comprehensive tooling and guidelines for packaging.
When targetting these, there are no hard rules
(except the general Fedora packaging guidelines).
But please try to abide by the spirit of these guidelines.
When in doubt, consider consulting the Python SIG.
Python version support
Fedora packages MUST NOT depend on other versions
of the CPython interpreter
than the current python3.
In Fedora, Python libraries are packaged for a single version of Python,
called python3.
For example, in Fedora 32, python3 is Python 3.8.
In the past, there were multiple Python stacks,
e.g. python3.7 and python2.7,
installable together on the same machine.
That is also the case in some projects that build on top of Fedora,
like RHEL, EPEL and CentOS.
Fedora might re-introduce parallell-installable stacks in the future
(for example if a switch to a new Python version needs a transition period,
or if enough interested maintainers somehow appear).
Fedora does include alternate interpreter versions,
e.g. python2.7 or python3.5,
but these are meant only for developers that need to test upstream code.
Bug and security fixes for these interpreters only cover this use case.
Packages such as pip or tox,
which enable setting up isolated environments
and installing third-party packages into them,
MAY, as an exception to the rule above, use these interpreters
as long as this is coordinated with the maintainers
of the relevant Python interpreter.
Naming
Python packages have several different names, which should be kept in sync but will sometimes differ for historical or practical reasons. They are:
Some examples (both good and worse):
| Fedora component | Built RPM | Project name | Importable module |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Elsewhere in this text,
the metavariables SRPMNAME, RPMNAME, PROJECTNAME, MODNAME
refer to these names, respectively.
Canonical project name
Most of these names are case-sensitive machine-friendly identifiers,
but the project name has human-friendly semantics:
it is case-insensitive
and treats some sets of characters (like ._-) specially.
For automated use,
it needs to be normalized to a canonical format
used by Python tools and services such as setuptools, pip and PyPI.
For example, the canonical name of the Django project
is django (in lowercase).
This normalization is defined in
PEP 503,
and the %{py_dist_name} macro implements it
for Fedora packaging.
The canonical name is obtained by switching the project name to lower case
and converting all runs of non-alphanumeric characters to single “-” characters.
Example: “The $$$ Tree” becomes “the-tree”.
Elsewhere in this text,
the metavariable DISTNAME refers to the canonical form of the project name.
Note that in some places, the original,
non-normalized project name must be used.
For example,
the %pypi_source macro and the %autosetup macro
need Django, not django.
Name limitations
The character + in names of built (i.e. non-SRPM) packages
that include .dist-info or .egg-info directories
is reserved for Extras and MUST NOT be used for any other purpose.
As an exception, + characters MAY appear at the end of such names.
The + character triggers
the automatic dependency generator for extras.
Replace any + signs in the upstream name with -.
Omit + signs on the beginning of the name.
Consider adding Provides for the original name with + characters
to make the package easier to find for users.
Library naming
A built (i.e. non-SRPM) package for a Python library
MUST be named with the prefix python3-.
A source package containing primarily a Python library
MUST be named with the prefix python-.
The Fedora package’s name SHOULD contain
the Canonical project name.
If possible, the project name SHOULD be the same
as the name of the main importable module,
in lowercase,
with underscores (_) replaced by dashes (-).
If the importable module name and the project name do not match, users frequently end up confused. In this case, packagers SHOULD ensure that upstream is aware of the problem and (especially for new packages where renaming is feasible) strive to get the package renamed. The Python SIG is available for assistance.
A Python library is a package meant to be imported in Python,
such as with import requests.
Tools like Ansible or IDLE, whose code is importable
but not primarily meant to be imported from other software,
are not considered libraries in this sense.
So, this section does not apply for them.
(See the
general Libraries and Applications guidelines
for general guidance.)
The Fedora component (source package) name for a library
should be formed by taking the canonical project name
and prepending python- if it does not already start with python-.
This may leads to conflicts
(e.g. between bugzilla
and python-bugzilla).
In that case, ensure upstream is aware of the potentially confusing naming
and apply best judgment.
Application naming
Packages that primarily provide applications, services
or any kind of executables SHOULD be named
according to the general Fedora naming guidelines
(e.g. ansible).
Consider adding a virtual provide according to Library naming above
(e.g. python3-PROJECTNAME),
if it would help users find the package.
Files to include
Source files and bytecode cache
Packages MUST include the source file (*.py)
AND the bytecode cache (*.pyc) for each pure-Python importable module.
The source files MUST be included in the same package as the bytecode cache.
Scripts that are not importable
(typically ones in %{_bindir} or %{_libexecdir})
SHOULD NOT be byte-compiled.
The cache files are found in a __pycache__ directory
and have an interpreter-dependent suffix like .cpython-39.pyc.
The cache is not necessary to run the software, but if it is not found, Python will try to create it when a module is imported. If this succeeds, the file is not tracked by RPM and it will linger on the system after uninstallation. If it does not succeed, users can get spurious SELinux AVC denials in the logs.
Normally, byte compilation (generating the cache files)
is done for you by the brp-python-bytecompile
BRP script,
which runs automatically
after the %install section of the spec file has been processed.
It byte-compiles any .py files that it finds
in %{python3_sitelib} or %{python3_sitearch}.
You must include these files of your package
(i.e. in the %files section).
If the code is in a subdirectory (importable package), include the entire directory:
%files
%{python3_sitelib}/foo/
Adding the trailing slash is best practice for directories.
However, this cannot be used for top-level modules (those directly in
e.g. %{python3_sitelib}), because both %{python3_sitelib} and
%{python3_sitelib}/__pycache__/ are owned by Python itself. Here, the
%pycached macro can help. It expands to the given *.py source file
and its corresponding cache file(s). For example:
%files
%pycached %{python3_sitelib}/foo.py
expands roughly to:
%files
%{python3_sitelib}/foo.py
%{python3_sitelib}/__pycache__/foo.cpython-3X{,.opt-?}.pyc
Manual byte compilation
If you need to bytecompile stuff
outside of %{python3_sitelib}/%{python3_sitearch},
use the %py_byte_compile macro.
For example,
if your software adds %{_datadir}/mypackage to Python’s import path
and imports package foo from there, you will need to compile foo with:
%py_byte_compile %{python3} %{buildroot}%{_datadir}/mypackage/foo/
Dist-info metadata
Each Python package MUST include Package Distribution Metadata conforming to PyPA specifications (specifically, Recording installed projects).
The metadata SHOULD be included in the same subpackage as the main importable module, if there is one.
This applies to libraries (e.g. python-requests)
as well as tools (e.g. ansible).
When software is split into several subpackages, it is OK to only ship metadata in one built RPM. In this case, consider working with upstream to also split the upstream project.
The metadata takes the form of a .dist-info directory
installed in %{python3_sitelib} or %{python3_sitearch},
and contains information that tools like
importlib.metadata
use to introspect installed libraries.
For example, a project named MyLib with importable package mylib
could be packaged with:
%files -p python3-mylib
%{python3_sitelib}/mylib/
%{python3_sitelib}/MyLib-%{version}.dist-info/
%doc README.md
%license LICENSE.txt
Note that some older tools instead put metadata in an .egg-info directory,
or even a single file.
This won’t happen if you use the %pyproject_wheel macro.
If your package uses a build system
that generates an .egg-info directory or file,
please contact Python SIG.
As an exception, the Python standard library MAY ship without this metadata.
Explicit lists
Packages MUST NOT own shared directories owned by Python itself,
such as the top-level __pycache__ directories
(%{python3_sitelib}/__pycache__, %{python3_sitearch}/__pycache__).
Similarly to the general rule, packagers SHOULD NOT simply glob everything under a shared directory.
In addition to the general list,
the following SHOULD NOT be used in %files:
-
%{python3_sitelib}/* -
%{python3_sitearch}/* -
%{python_sitelib}/* -
%{python_sitearch}/* -
%pyproject_save_files '*' -
%pyproject_save_files +auto
This rule serves as a check against common mistakes which are otherwise hard to detect. It does limit some possibilities for automation.
The most common mistakes this rule prevents are:
-
installing a test suite system-wide as an importable module named
test, which would then conflict with other such packages, and -
upstream adding new unexpected importable modules – you should always check such changes for conflicts, and keep the list of such files explicit and auditable.
PyPI parity
Every Python package in Fedora SHOULD also be available on the Python Package Index (PyPI).
The command pip install PROJECTNAME MUST
install the same package (possibly in a different version),
install nothing,
or fail with a reasonable error message.
If this is not the case, the packager SHOULD contact upstream about this. The goal is to get the project name registered or blocked on PyPI, or to otherwise ensure the rule is followed.
If your package is not or cannot be published on PyPI, you can:
-
Ask upstream to publish it
-
If you wish: publish it to PyPI yourself and maintain it
-
Ask Python SIG to block the name on PyPI for you
-
Email PyPI admins to block the name for you, giving the project name and explaining the situation (for example: the package cannot currently be installed via
pip). You can ask questions and discuss the process at the Python Discourse.
Project names that were in Fedora but not on PyPI
when these guidelines were proposed are blocked from being uploaded to PyPI.
This prevents potential trolls from taking them,
but it also blocks legitimate owners.
If your package is affected, contact the Python SIG or
file a PyPA issue
and mention @encukou.
|
If your package’s project name conflicts with a different package on PyPI, change the project name. As painful as it is, we need to use a single global namespace across the Python ecosystem. Software that is not written specifically for Fedora already expects that project names use the PyPI namespace: for example, if a third-party library identifies a dependency by name, we don’t want that dependency satisfied by an unrelated Fedora package.
As always, specific exceptions can be granted by the Packaging Committee.
Provides and requirements
Provides for importable modules
For any module intended to be used in Python 3 with import MODNAME,
the package that includes it SHOULD provide python3-MODNAME,
with underscores (_) replaced by dashes (-).
This is of course always the case if the package is named python3-MODNAME.
If the subpackage has some other name,
then add %py_provides python3-MODNAME explicitly.
See the following section to learn about %py_provides.
Automatic python- and python3.X- provides
For any FOO,
a package that provides python3-FOO SHOULD use %py_provides
or an automatic generator
to also provide python-FOO
and python3.X-FOO, where X is the minor version of the interpreter.
The provide SHOULD NOT be added manually:
if a generator or macro is not used,
do not add the python-FOO / python3.X-FOO provides at all.
This is done automatically for package names by a generator.
If absolutely necessary, the generator can be disabled
by undefining the %__pythonname_provides macro.
For provides that aren’t package names,
or (for technical reasons) for packages without files,
the generator will not work.
For these cases, the following invocation will provide python3-FOO,
python-FOO and python3.X-FOO:
%py_provides python3-FOO
Using the generator or macro is important, because the specific form of the provide may change in the future.
Machine-readable provides
Every Python package MUST provide python3dist(DISTNAME)
and python3.Xdist(DISTNAME),
where X is the minor version of the interpreter
and DISTNAME is the Canonical project name
corresponding to the Dist-info metadata.
For example, python3-django would provide
python3dist(django) and python3.9dist(django).
This is generated automatically from the dist-info metadata. The provide SHOULD NOT be added manually: if the generator fails to add it, the metadata MUST be fixed.
These Provides are used for automatically generated Requires.
If absolutely necessary,
the automatic generator can be disabled by undefining the
%{?__pythondist_provides} macro.
Consider discussing your use case with the Python SIG if you need to do this.
Dependencies
As mentioned above,
each Python package MUST explicitly BuildRequire python3-devel.
Packages MUST NOT have dependencies (either build-time or runtime)
with the unversioned prefix python-
if the corresponding python3- dependency can be used instead.
Packages SHOULD NOT have explicit dependencies
(either build-time or runtime)
with a minor-version prefix such as python3.8- or python3.8dist(.
Such dependencies SHOULD instead be automatically generated
or a macro should be used to get the version.
Packages SHOULD NOT have an explicit runtime dependency on python3.
Instead of depending on python3,
packages have an automatic dependency on python(abi) = 3.X
when they install files to %{python3_sitelib} or %{python3_sitearch},
or they have an automatic dependency on /usr/bin/python3
if they have executable Python scripts,
or they have an automatic dependency on libpython3.X.so.1.0()
if they embed Python.
These rules help ensure a smooth upgrade path
when python3 is updated in new versions of Fedora.
Automatically generated dependencies
Packages MUST use the automatic Python run-time dependency generator.
Packages SHOULD use the opt-in build-dependency generator if possible.
The packager MUST inspect the generated requires for correctness. All dependencies MUST be resolvable within the targeted Fedora version.
Any necessary changes MUST be done by patches
or modifying the source (e.g. with sed),
rather than disabling the generator.
The resulting change SHOULD be offered to upstream.
As an exception, filtering
MAY be used for temporary workarounds
and bootstrapping.
Dependencies covered by the generators SHOULD NOT
be repeated in the .spec file.
(For example, if the generator finds a requests dependency,
then Requires: python3-requests is redundant.)
The automatically generated requirements
are in the form python3.Xdist(DISTNAME),
potentially augmented with version requirements or combined together
with rich dependencies.
Any .0 suffixes are removed from version numbers
to match the behavior of Python tools.
(PEP 440 specifies
that X.Y and X.Y