Öffentliche Cython-APIs#
Ab April 2020 stellen die folgenden Module in SciPy Funktionalität über öffentliche cdef Cython API-Deklarationen bereit
scipy.linalg.cython_blasscipy.linalg.cython_lapackscipy.optimize.cython_optimizescipy.special.cython_special
Dies nutzt die Funktionen zur gemeinsamen Nutzung von Deklarationen in Cython, bei denen gemeinsam genutzte cdef Elemente in *.pxd-Dateien deklariert werden, die zusammen mit den entsprechenden DLL/SO-Dateien in binären SciPy-Installationen verteilt werden.
Anwendungs-Binärschnittstelle#
Die Nutzung dieser Funktionen in SciPy erfordert jedoch von SciPy-Mitwirkenden zusätzliche Sorgfalt hinsichtlich der Aufrechterhaltung der Stabilität der Anwendungs-Binärschnittstelle (ABI). Dies ähnelt der Entwicklung von Bibliotheken in C und unterscheidet sich von der Rückwärtskompatibilität in reinem Python.
Der Hauptunterschied zu Python ergibt sich aus der Tatsache, dass die Deklarationen in den .pxd-Header-Dateien verwendet werden, wenn von Benutzern geschriebener Code *kompiliert* wird, aber sie müssen auch mit dem übereinstimmen, was in SciPy verfügbar ist, wenn der Benutzer-Code *importiert* wird.
Benutzer-Code kann mit einer SciPy-Version kompiliert werden, und die kompilierte Binärdatei (die die in den .pxd-Dateien deklarierte Binärschnittstelle verwendet) kann mit einer anderen, auf dem System installierten SciPy-Version verwendet werden. Wenn die Schnittstellen nicht kompatibel sind, wird entweder eine Ausnahme ausgelöst oder es kommt zu Laufzeit-Speicherkorruption und Abstürzen.
Beim Import prüft Cython, ob die Signaturen von Funktionen in der installierten SciPy SO/DLL-Datei mit denen in der .pxd-Datei übereinstimmen, die der Benutzer während der Kompilierung verwendet hat, und löst eine Python-Ausnahme aus, wenn eine Diskrepanz besteht. Wenn der SciPy-Code korrekt strukturiert ist (siehe unten), wird diese Prüfung nur für Funktionen durchgeführt, die tatsächlich im Benutzer-Code importiert werden.
Wir verlassen uns auf diese Funktion, um eine Laufzeit-Sicherheitsprüfung bereitzustellen, die es den Benutzern erleichtert, inkompatible SciPy-Versionen über Python-Ausnahmen zu erkennen, anstatt schwer nachvollziehbare Laufzeitabstürze.
Ziel der ABI-Stabilität#
SciPy strebt die Aufrechterhaltung der ABI-Stabilität in Cython-Code an, und zwar in folgendem Sinne:
Binärdateien, die durch Kompilierung von Benutzercode mit einer SciPy-Version erzeugt werden, sind mit jeder anderen SciPy-Version kompatibel, mit der der Quellcode kompiliert werden kann.
Der Versuch, zur Laufzeit eine inkompatible SciPy-Version zu verwenden, führt zur Laufzeit beim Import des Benutzermoduls zu einer Python-Ausnahme.
Der Versuch, zur Kompilierzeit eine inkompatible SciPy-Version zu verwenden, führt zu einem Cython-Fehler.
Das bedeutet, dass Benutzer jede kompatible SciPy-Version verwenden können, um Binärdateien zu kompilieren, ohne auf die ABI achten zu müssen, d.h.:
ABI-Kompatibilität = API-Kompatibilität
Die Rückwärts-/Vorwärtskompatibilität der Cython-API wird mit einer ähnlichen Richtlinie für veraltete Funktionen/Entfernungen wie für die Python-API behandelt, siehe Veralterungen.
Implementierung der ABI-Stabilität in SciPy#
Die folgenden Regeln bei der Entwicklung von Cython-APIs in SciPy sind notwendig, um das oben genannte Ziel der ABI-Stabilität zu erreichen:
Das Hinzufügen neuer
cdef-Deklarationen (Funktionen, Strukturen, Typen usw.) **ist erlaubt**.Das Entfernen von
cdef-Deklarationen **ist erlaubt**, sollte aber der allgemeinen Richtlinie für veraltete Funktionen/Entfernungen folgen.cdef-Deklarationen von Funktionen **können geändert werden**.Änderungen führen jedoch zu einer rückwärts inkompatiblen API-Änderung, die jeglichen Code bricht, der die geänderte Signatur verwendet, und **sollte** der allgemeinen Richtlinie für veraltete Funktionen/Entfernungen folgen.
cdef-Deklarationen von allem anderen (z. B.struct,enumund Typen) sind **endgültig**. Sobald eine Deklaration in der öffentlichen Cython-API einer veröffentlichten SciPy-Version exponiert ist, **darf sie nicht mehr geändert werden**.Wenn Änderungen erforderlich sind, müssen diese durch Hinzufügen neuer Deklarationen mit anderen Namen und Entfernen der alten durchgeführt werden.
cdef-Klassen sind in den öffentlichen APIs **nicht erlaubt** (TBD: Die Rückwärtskompatibilität von cdef-Klassen erfordert weitere Forschung, sollte aber nicht erlaubt sein, wenn wir uns nicht sicher sind).Verwenden Sie für jedes öffentliche API-Modul (wie in
scipy.linalg.cython_blas) eine einzige Schnittstellen-Deklarationsdatei.pxd.Die öffentliche Schnittstellendeklarationsdatei **sollte keine**
cimport-Anweisungen enthalten. Wenn doch, prüft Cythons Signaturprüfung alle cimportierten Funktionen, nicht nur die, die vom Benutzercode verwendet werden, sodass eine Änderung einer davon die gesamte API bricht.Wenn Datenstrukturen erforderlich sind, **bevorzugen Sie undurchsichtige Strukturen** in der öffentlichen API. Die Schnittstellendeklarationen sollten keine Deklarationen von Strukturmitgliedern enthalten. Die Zuweisung, Freigabe und der Attributzugriff auf Datenstrukturen sollten über Funktionen erfolgen.
Veralten von öffentlichen Cython-APIs#
Um eine öffentliche Cython-API-Funktion zu veralten, z. B.
# scipy/something/foo.pxd
cdef public int somefunc()
# scipy/something/foo.pyx
cdef public int somefunc():
return 42
können Sie die Funktion scipy._lib.deprecation.deprecate_cython_api verwenden, um die Veraltung am Ende der entsprechenden .pyx-Datei vorzunehmen.
# scipy/something/foo.pyx
cdef public int somefunc():
return 42
from scipy._lib.deprecation import deprecate_cython_api
import scipy.something.foo as mod
deprecate_cython_api(mod, "somefunc", new_name="scipy.something.newfunc",
message="Deprecated in Scipy 1.5.0")
del deprecate_cython_api, mod
Danach geben Cython-Module, die cimport somefunc, zur Importzeit eine DeprecationWarning aus.
Es gibt keine Möglichkeit, Cython-Datenstrukturen und -Typen zu veralten. Diese können jedoch entfernt werden, nachdem alle Funktionen, die sie in der API verwenden, entfernt wurden und den Verfallszyklus durchlaufen haben.
Ganze Cython-Module können ähnlich wie Python-Module veraltet werden, indem auf der obersten Ebene eine DeprecationWarning ausgegeben wird.