Documentation for a newer release is available. View Latest

Python

Setuptools 59

Fedora Linux 36 proporciona python-setuptools 59. Esto incluye la retirada de la instrucción de configuración use_2to3. Para más detalles, consulte la bitácora de cambios última.

Esquema de instalación nuevo de paquetes de Python

En Fedora Linux 36, Python cambia la forma en que se gestionan las rutas de instalación de los paquetes de Python. Estos cambios afectan a la versión principal de Python en Fedora 36, Python 3.10, así como a cualquier versión posterior incluida. La mayoría de los usuarios de Fedora Linux no deberían verse afectados por el cambio, pero en algunos casos podrían existir pequeñas diferencias.

Al instalar paquetes de Python con sudo pip, sudo python setup.py install o métodos similares, se instalan en /usr/local/lib(64)/python3.10/site-packages/. Esto ya se ha implementado desde Fedora Linux 27 . Sin embargo, la forma de hacerlo se ha reimplementado significativamente en Fedora Linux 36, lo que ha generado varias pequeñas diferencias.

El módulo sysconfig de Python de la biblioteca estándar define varios esquemas de instalación. Por defecto, el esquema de instalación usado en Fedora 36 al instalar paquetes de Python con privilegios de root (por ejemplo, mediante sudo) es {prefix}/lib(64)/python3.10/site-packages/, donde {prefix} se define como /usr/local por defecto. Al compilar paquetes RPM, {prefix} se define como /usr por defecto. Cuando Python se ejecuta desde un entorno virtual de Python, {prefix} se define como la ruta del entorno virtual.

Anteriormente, la parte /local/ solo se añadía artificialmente al instalar paquetes mediante distutils; ahora también se define en sysconfig. Esto se modificó para ser más consistente con lo que hacen otros distribuidores de Python, de modo que el esquema tenga más probabilidades de ser aceptado en Python original y funcione correctamente con herramientas originales como setuptools o pip, que no podemos modificar cuando se instalan o actualizan con pip directamente desde Índice de paquetes de Python.

Aquí están las diferencias que estarían observadas con la propuesta nueva:

sysconfig.get_path(key) devuelve rutas con /local/

Previously, on Fedora Linux 35 outside of a virtual environment:

>>> import sysconfig
>>> for key in sysconfig.get_path_names():
...     print(f'{key} = {sysconfig.get_path(key)}')
...
stdlib = /usr/lib64/python3.10
platstdlib = /usr/lib64/python3.10
purelib = /usr/lib/python3.10/site-packages
platlib = /usr/lib64/python3.10/site-packages
include = /usr/include/python3.10
scripts = /usr/bin
data = /usr

Now, on Fedora Linux 36 (except during RPM build):

>>> import sysconfig
>>> for key in sysconfig.get_path_names():
...     print(f'{key} = {sysconfig.get_path(key)}')
...
stdlib = /usr/lib64/python3.10
platstdlib = /usr/lib64/python3.10
purelib = /usr/local/lib/python3.10/site-packages
platlib = /usr/local/lib64/python3.10/site-packages
include = /usr/include/python3.10
scripts = /usr/local/bin
data = /usr/local

The values now reflect the reality of where packages are actually going to be installed with pip, setuptools, distutils, etc. However, if your Python code uses the values to determine where to load Python packages from, it won’t see dnf-installed packages, which are installed in /usr/lib(64)/python3.10/site-packages/. Generally, sysconfig.get_path(key) gives results that determine where the Python packages should be installed to. To fix affected code, avoid assumptions that "where to install packages to" is the same as "where to load Python modules from".

Example fixes from affected open source projects:

If you need to restore the previous behavior of sysconfig.get_path(key), you may explicitly set the {base} and {platbase} variables to /usr:

>>> for key in sysconfig.get_path_names():
...     print(f'{key} = {sysconfig.get_path(key, vars={"base": "/usr", "platbase": "/usr"})}')
...
stdlib = /usr/lib64/python3.10
platstdlib = /usr/lib64/python3.10
purelib = /usr/lib/python3.10/site-packages
platlib = /usr/lib64/python3.10/site-packages
include = /usr/include/python3.10
scripts = /usr/bin
data = /usr

RPM build–related caveats

When Python runs during RPM build, it sets the defaults for {base} and {platbase} variables to /usr. This behavior is triggered when the $RPM_BUILD_ROOT environment variable is set. That has several caveats:

Executing Python in Python’s subprocess

If the Python code that runs in RPM build (for example in %check) executes another Python instance via a subprocess, it is relatively easy to inadvertently unset all environment variables. When this happens, the inner Python will not know it runs within RPM build and will return paths with the /usr/local/ prefix.

In the most trivial example, the surrounding environment variables are implicitly passed to subprocess and everything works as expected:

>>> import os, subprocess, sys
>>> 'RPM_BUILD_ROOT' in os.environ
True
>>> command = [sys.executable, '-c', 'import sysconfig; print(sysconfig.get_path("purelib"))']
>>> subprocess.check_output(command)
b'/usr/lib/python3.10/site-packages\n'

But when a custom environment is passed, it breaks the detection, because $RPM_BUILD_ROOT is no longer set:

>>> subprocess.check_output(command, env={'FOO': 'bar'})
b'/usr/local/lib/python3.10/site-packages\n'

A solution is to always make a copy of the surrounding environment, then editing it and passing it to the subprocess. That is a generally valid Python advice.

>>> env = os.environ | {'FOO': 'bar'}
>>> subprocess.check_output(command, env=env)
b'/usr/lib/python3.10/site-packages\n'

Example fixes from affected open source projects:

%(…​) RPM macros

When RPM macros in the form of %(command …​) are expanded, $RPM_BUILD_ROOT is not yet set. Hence, Python does not know it is invoked from RPM build and the paths returned by sysconfig.get_path(…​) contain /local/. To fix this, set $RPM_BUILD_ROOT in the macro definition (to any value, even empty). For example a macro defined like this:

%global python3_scripts_dir %(python3 "import sysconfig; print(sysconfig.get_path('scripts'))")

Needs to be changed to this:

%global python3_scripts_dir %(RPM_BUILD_ROOT= python3 "import sysconfig; print(sysconfig.get_path('scripts'))")

The affected RPM macros supplied by Fedora’s python-rpm-macros packages have all been changed accordingly.

Paths for bootstrapping Python virtual environments

If your Python code uses installation schemes to determine paths to be used in created virtual environments, and the Python interpreter executing that code does not run from a Python virtual environment itself, the paths will not match.

To bootstrap Python virtual environments, the code should use the venv installation scheme (but only if it exists).

>>> scheme = 'venv' if 'venv' in sysconfig.get_scheme_names() else None
>>> sysconfig.get_path('purelib', scheme=scheme, vars={'base': '<venv>'})
'<venv>/lib/python3.10/site-packages'
>>> sysconfig.get_path('scripts', scheme=scheme, vars={'base': '<venv>'})
'<venv>/bin'

The venv scheme is currently Fedora specific, but other Python distributors (such as Ubuntu Deadsnakes) may define it as well. The venv scheme is generally available starting with Python 3.11. Due to checking if the venv install scheme exists the code is functional on other operating systems as well, as it falls back to a backwards compatible behavior.

Example fixes from affected open source projects:

Django 4.0

Fedora Linux 36 provides the latest version of Django 4.0. Few highlights of this version are:

  • The new RedisCache backend provides built-in support for caching with Redis.

  • To ease customization of Forms, Formsets, and ErrorList they are now rendered using the template engine.

  • The Python standard library’s zoneinfo is now the default timezone implementation in Django.

For more details, see the upstream release notes.