Zusätzliche Richtlinien fürPython

Nachfolgend finden Sie einige zusätzliche Python-bezogene Richtlinien, die hierher verschoben wurden, um die Hauptseite übersichtlich zu halten.

Manuelle Byte-Kompilierung

Dieser Abschnitt gilt nur für die Richtlinien aus den 201x-er Jahren. In den neuen Richtlinien finden Sie Informationen zur manuellen Byte-Kompilierung hier.

Beim Bytecode-Kompilieren einer .py-Datei bettet Python eine magische Nummer in die kompilierten Dateien ein, die der Laufzeitumgebung entspricht. Dateien in %{python?_sitelib} und %{python?_sitearch} MÜSSEN der Laufzeitumgebung entsprechen, für die sie erstellt wurden. Beispielsweise MUSS ein reines Python-Modul, das für die Laufzeitumgebung 3.4 kompiliert wurde, unterhalb von %{_usr}/lib/python3.4/site-packages liegen.

Das Skript brp-python-bytecompile versucht, dies für Sie zu ermitteln. Es bestimmt den zu verwendenden Interpreter für die Byte-Kompilierung des Moduls, indem es prüft, in welchem Verzeichnis die Datei installiert ist. Befindet sie sich beispielsweise unter /usr/lib{,64}/pythonX.Y, wird pythonX.Y für die Byte-Kompilierung des Moduls verwendet. Ist pythonX.Y nicht installiert, wird ein Fehler zurückgegeben und der RPM-Bauprozess wird abgebrochen. Denken Sie daher daran, das korrekte Python-Paket mit BuildRequire einzubinden.

Wenn Sie *.py-Dateien außerhalb der Verzeichnisse /usr/lib(64)?/pythonX.Y/ haben und diese Dateien byte-kompiliert werden müssen (z. B. weil es sich um ein importierbares Python-Modul handelt), MÜSSEN Sie sie explizit mit dem Makro %py_byte_compile kompilieren. Beachten Sie, dass nicht alle Python-Dateien importierbare Python-Module sind; suchen Sie im Zweifelsfall im Quellcode nach der entsprechenden Importanweisung.

Ein Beispiel für ein Paket, das beide Python-Versionen hat:

# Buildrequire both python2 and python3
BuildRequires: python2-devel python3-devel

%install
# Installs a python2 private module into %{buildroot}%{_datadir}/mypackage/foo
# and installs a python3 private module into %{buildroot}%{_datadir}/mypackage/bar
make install DESTDIR=%{buildroot}

# Manually invoke the python byte compile macro for each path that needs byte
# compilation.
%py_byte_compile %{python2} %{buildroot}%{_datadir}/mypackage/foo
%py_byte_compile %{python3} %{buildroot}%{_datadir}/mypackage/bar

Das Makro %py_byte_compile benötigt zwei Argumente. Das erste ist der Python-Interpreter, der für die Bytecode-Kompilierung verwendet werden soll. Das zweite ist eine Datei oder ein Verzeichnis, das bytecodekompiliert werden soll. Wenn das zweite Argument ein Verzeichnis ist, kompiliert das Makro rekursiv alle *.py-Dateien in diesem Verzeichnis.

Manuelle Byte-Kompilierung für EPEL 6 und 7

Der in %{__python} definierte Skriptinterpreter wird verwendet, um die Module außerhalb der Verzeichnisse /usr/lib(64)?/pythonX.Y/ zu kompilieren. Standardmäßig wird /usr/bin/python verwendet (Python 2.6 bzw. 2.7 in EPEL 7). Falls Sie die Module für Python 3 kompilieren müssen, verwenden Sie stattdessen /usr/bin/python3:

%global __python %{python3}

Dies ist hilfreich, wenn eine Python-3-Anwendung ein privates Modul in einem eigenen Verzeichnis installiert. Nehmen wir an, die Anwendung „foobar“ installiert ein Modul, das nur von der Befehlszeilenanwendung verwendet wird, in %{_datadir}/foobar. Da sich diese Dateien nicht in einem der Python-3-Bibliothekspfade (zum Beispiel /usr/lib/python3.6) befinden, muss %{__python} außer Kraft gesetzt werden, um brp-python-bytecompile anzuweisen, den Python-3-Interpreter für die Byte-Kompilierung zu verwenden.

Diese Einstellungen reichen aus, um jedes Paket, das Python-Module in %{python?_sitelib} oder %{python?_sitearch} erstellt oder nur für einen einzigen Python-Interpreter kompiliert, korrekt byte-kompilieren zu lassen. Wenn die Anwendung, die Sie paketieren, jedoch sowohl mit Python 2 als auch mit Python 3 kompiliert und in ein privates Modulverzeichnis installiert werden muss (beispielsweise weil sie ein in Python 2 und ein zweites in Python 3 geschriebenes Hilfsprogramm bereitstellt), müssen Sie dies manuell durchführen. Hier ist ein Beispielausschnitt aus einer Spec-Datei, der zeigt, wie das geht:

# Turn off the brp-python-bytecompile script
%global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')
# Buildrequire both python2 and python3
BuildRequires: python2-devel python3-devel
[...]

%install
# Installs a python2 private module into %{buildroot}%{_datadir}/mypackage/foo
# and installs a python3 private module into %{buildroot}%{_datadir}/mypackage/bar
make install DESTDIR=%{buildroot}

# Manually invoke the python byte compile macro for each path that needs byte
# compilation.
%py_byte_compile %{python2} %{buildroot}%{_datadir}/mypackage/foo
%py_byte_compile %{python3} %{buildroot}%{_datadir}/mypackage/bar

Beachten Sie, dass dies die Kompilierung von Dateien in /usr/lib(64)?/pythonX.Y/ deaktiviert.

Reproduzierbarkeit der Byte-Kompilierung

Dieser Unterabschnitt gilt nur für Fedora ⇐ 40, ELN und EPEL. In späteren Fedora-Versionen wird dies automatisch implementiert.

Bei zwei Python-Dateien mit exakt gleichem Inhalt und Metadaten kann die Byte-Kompilierung unterschiedliche Ergebnisse liefern. Die resultierenden .pyc-Dateien sind zwar funktional identisch, aber nicht bitgenau. In den meisten Fällen ist der interne Referenzzähler von Python die Ursache, da er bei jeder Byte-Kompilierung einen anderen internen Zustand aufweisen kann. Eine detailliertere Erklärung finden Sie in https://bugzilla.redhat.com/show_bug.cgi?id=1686078#c2 [diesem Bugzilla-Kommentar].

Diese Unannehmlichkeit könnte in Koji zu einem Problem führen, da noarch-Pakete, die im Rahmen eines architekturspezifischen Baus erstellt wurden, möglicherweise abgelehnt werden, weil sie unterschiedlichen Inhalt haben.

Um dieses Problem zu umgehen, fügen Sie Marshalparser mittels BuildRequires: /usr/bin/marshalparser hinzu (ein Werkzeug, das die Reproduzierbarkeit von .pyc-Dateien verbessert) hinzu und weisen Sie es an, die .pyc-Dateien in bestimmten Pfaden zu verarbeiten, indem Sie das Makro %py_reproducible_pyc_path setzen:

%global py_reproducible_pyc_path %{buildroot}%{_datadir}/llamafarm/plugins

Mit dieser Einstellung sucht marshalparser rekursiv nach allen bytekompilierten Python-Dateien in %{buildroot}%{_datadir}/llamafarm/plugins und versucht, diese zu korrigieren. Dies geschieht ganz am Ende des Bauprozesses, nachdem alle vorherigen Bytekompilierungsschritte abgeschlossen sind. Kann marshalparser einige der Cache-Dateien nicht auswerten, schlägt der Bau fehl.