Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 405 – Python Virtuelle Umgebungen

Autor:
Carl Meyer <carl at oddbird.net>
BDFL-Delegate:
Alyssa Coghlan
Status:
Final
Typ:
Standards Track
Thema:
Packaging
Erstellt:
13. Juni 2011
Python-Version:
3.3
Post-History:
24. Okt. 2011, 28. Okt. 2011, 06. Mrz. 2012, 24. Mai 2012
Resolution:
Python-Dev Nachricht

Inhaltsverzeichnis

Zusammenfassung

Diese PEP schlägt vor, Python einen Mechanismus für leichtgewichtige „virtuelle Umgebungen“ mit eigenen Site-Verzeichnissen hinzuzufügen, die optional von systemweiten Site-Verzeichnissen isoliert sind. Jede virtuelle Umgebung hat ihre eigene Python-Binärdatei (was die Erstellung von Umgebungen mit verschiedenen Python-Versionen ermöglicht) und kann ihre eigene, unabhängige Sammlung von installierten Python-Paketen in ihren Site-Verzeichnissen haben, teilt sich aber die Standardbibliothek mit der Basis-Python-Installation.

Motivation

Der Nutzen von Python-virtuellen Umgebungen wurde bereits durch die Popularität bestehender Drittanbieter-Tools für virtuelle Umgebungen, vor allem Ian Bickings virtualenv, gut etabliert. Virtuelle Umgebungen werden bereits häufig für die Verwaltung und Isolierung von Abhängigkeiten, die einfache Installation und Nutzung von Python-Paketen ohne Systemadministratorzugriff und das automatisierte Testen von Python-Software über mehrere Python-Versionen hinweg, unter anderem, verwendet.

Bestehende Tools für virtuelle Umgebungen leiden unter mangelnder Unterstützung durch das Verhalten von Python selbst. Tools wie rvirtualenv, die die Python-Binärdatei nicht in die virtuelle Umgebung kopieren, können keine zuverlässige Isolation von systemweiten Site-Verzeichnissen gewährleisten. Virtualenv, das die Python-Binärdatei kopiert, muss viel vom Python-eigenen site-Modul duplizieren und manuell eine sich ständig ändernde Sammlung von Standardbibliotheksmodulen in die virtuelle Umgebung symlinken/kopieren, um bei jedem Start einen heiklen Bootstrapping-Tanz aufzuführen. (Virtualenv muss die Binärdatei kopieren, um die Isolation zu gewährleisten, da Python eine symbolische Verknüpfung zu einer ausführbaren Datei auflöst, bevor es nach sys.prefix sucht.)

Die Umgebungsvariable PYTHONHOME, Pythons einzige bestehende integrierte Lösung für virtuelle Umgebungen, erfordert das Kopieren/Symlinken der gesamten Standardbibliothek in jede Umgebung. Das Kopieren der gesamten Standardbibliothek ist keine leichte Lösung, und die plattformübergreifende Unterstützung für Symlinks bleibt inkonsistent (selbst auf Windows-Plattformen, die sie unterstützen, erfordert deren Erstellung oft Administratorrechte).

Ein in Python integrierter Mechanismus für virtuelle Umgebungen, der auf jahrelanger Erfahrung mit bestehenden Drittanbieter-Tools aufbaut, kann den Wartungsaufwand senken, die Zuverlässigkeit erhöhen und für alle Python-Benutzer leichter zugänglich sein.

Spezifikation

Wenn die Python-Binärdatei ausgeführt wird, versucht sie, ihr Präfix zu ermitteln (das sie in sys.prefix speichert), welches dann verwendet wird, um die Standardbibliothek und andere wichtige Dateien zu finden, und vom site-Modul, um den Speicherort der Site-Package-Verzeichnisse zu bestimmen. Derzeit wird das Präfix (unter der Annahme, dass PYTHONHOME nicht gesetzt ist) gefunden, indem zunächst der Dateisystembaum nach oben durchlaufen wird, um nach einer Markerdatei (os.py) zu suchen, die die Anwesenheit der Standardbibliothek signalisiert. Wenn keine gefunden wird, wird auf das im Binärdatei hartkodierte Präfix zur Build-Zeit zurückgegriffen.

Diese PEP schlägt einen neuen ersten Schritt zu dieser Suche vor. Wenn eine Datei pyvenv.cfg entweder neben der Python-Ausführungsdatei oder ein Verzeichnis darüber gefunden wird (wenn die Ausführungsdatei ein Symlink ist, wird sie nicht aufgelöst), wird diese Datei nach Zeilen der Form key = value durchsucht. Wenn ein home-Schlüssel gefunden wird, bedeutet dies, dass die Python-Binärdatei zu einer virtuellen Umgebung gehört, und der Wert des home-Schlüssels ist das Verzeichnis, das die Python-Binärdatei enthält, die zum Erstellen dieser virtuellen Umgebung verwendet wurde.

In diesem Fall wird die Präfix-Suche normal fortgesetzt, wobei der Wert des home-Schlüssels als effektiver Standort der Python-Binärdatei verwendet wird, was das Präfix der Basisinstallation findet. sys.base_prefix wird auf diesen Wert gesetzt, während sys.prefix auf das Verzeichnis gesetzt wird, das pyvenv.cfg enthält.

(Wenn pyvenv.cfg nicht gefunden wird oder den home-Schlüssel nicht enthält, wird die Präfix-Suche normal fortgesetzt, und sys.prefix ist gleich sys.base_prefix.)

Außerdem wird sys.base_exec_prefix hinzugefügt und ähnlich in Bezug auf sys.exec_prefix behandelt. (sys.exec_prefix ist das Äquivalent von sys.prefix, aber für plattformspezifische Dateien; standardmäßig hat es denselben Wert wie sys.prefix.)

Die Standardbibliotheksmodule site und sysconfig werden so modifiziert, dass die Standardbibliothek und die Header-Dateien relativ zu sys.base_prefix / sys.base_exec_prefix gefunden werden, während Site-Package-Verzeichnisse („purelib“ und „platlib“, im Sinne von sysconfig) weiterhin relativ zu sys.prefix / sys.exec_prefix gefunden werden.

Somit würde eine Python-virtuelle Umgebung in ihrer einfachsten Form nur aus einer Kopie oder einem Symlink der Python-Binärdatei bestehen, begleitet von einer pyvenv.cfg-Datei und einem Site-Packages-Verzeichnis.

Isolation von systemweiten site-packages

Standardmäßig ist eine virtuelle Umgebung vollständig von den systemweiten Site-Packages-Verzeichnissen isoliert.

Wenn die Datei pyvenv.cfg außerdem einen Schlüssel include-system-site-packages mit dem Wert true (nicht case-sensitiv) enthält, fügt das site-Modul auch die systemweiten Site-Verzeichnisse zu sys.path hinzu, nach den Site-Verzeichnissen der virtuellen Umgebung. Somit sind systemweit installierte Pakete weiterhin importierbar, aber ein Paket mit demselben Namen, das in der virtuellen Umgebung installiert ist, hat Vorrang.

PEP 370-Site-Packages auf Benutzerebene werden für venv-Zwecke als Teil der systemweiten Site-Packages betrachtet: Sie sind aus einer isolierten venv nicht verfügbar, aber aus einer include-system-site-packages = true venv verfügbar.

Erstellung von virtuellen Umgebungen

Diese PEP schlägt auch ein neues Modul venv zur Standardbibliothek vor, das die Erstellung virtueller Umgebungen implementiert. Dieses Modul kann mit dem Flag -m ausgeführt werden.

python3 -m venv /path/to/new/virtual/environment

Ein pyvenv-installiertes Skript wird ebenfalls bereitgestellt, um dies bequemer zu machen.

pyvenv /path/to/new/virtual/environment

Das Ausführen dieses Befehls erstellt das Zielverzeichnis (und erstellt alle übergeordneten Verzeichnisse, die noch nicht existieren) und platziert darin eine Datei pyvenv.cfg mit einem home-Schlüssel, der auf die Python-Installation zeigt, von der der Befehl ausgeführt wurde. Es erstellt auch ein Unterverzeichnis bin/ (oder Scripts unter Windows), das eine Kopie (oder einen Symlink) der python3-Ausführungsdatei und das pysetup3-Skript aus dem packaging-Standardbibliotheksmodul (um die einfache Installation von Paketen von PyPI in die neue venv zu erleichtern) enthält. Und es erstellt ein (anfangs leeres) Unterverzeichnis lib/pythonX.Y/site-packages (oder Lib\site-packages unter Windows).

Wenn das Zielverzeichnis bereits existiert, wird ein Fehler ausgelöst, es sei denn, die Option --clear wurde bereitgestellt. In diesem Fall wird das Zielverzeichnis gelöscht und die Erstellung der virtuellen Umgebung wird wie üblich fortgesetzt.

Die erstellte Datei pyvenv.cfg enthält auch den Schlüssel include-system-site-packages, der auf true gesetzt wird, wenn pyvenv mit der Option --system-site-packages ausgeführt wird, standardmäßig auf false.

Mehrere Pfade können an pyvenv übergeben werden. In diesem Fall wird eine identische venv gemäß den angegebenen Optionen an jedem bereitgestellten Pfad erstellt.

Das Modul venv platziert auch „Shell-Aktivierungsskripte“ für POSIX- und Windows-Systeme im Verzeichnis bin oder Scripts der venv. Diese Skripte fügen einfach das bin- (oder Scripts-)Verzeichnis der virtuellen Umgebung am Anfang des PATH der Benutzer-Shell ein. Dies ist für die Nutzung einer virtuellen Umgebung nicht unbedingt erforderlich (da ein expliziter Pfad zur Python-Binärdatei oder zu den Skripten der venv genauso gut verwendet werden kann), aber es ist praktisch.

Um pysetup und anderen Python-Paketmanagern zu ermöglichen, Pakete in die virtuelle Umgebung so zu installieren, wie sie es in einer normalen Python-Installation tun würden, und eine spezielle Behandlung von virtuellen Umgebungen in sysconfig zu vermeiden, abgesehen von der Verwendung von sys.base_prefix anstelle von sys.prefix, wo angebracht, ahmt das interne Layout der virtuellen Umgebung das Layout der Python-Installation selbst auf jeder Plattform nach. Eine typische virtuelle Umgebungsstruktur auf einem POSIX-System wäre also

pyvenv.cfg
bin/python3
bin/python
bin/pysetup3
include/
lib/python3.3/site-packages/

Während auf einem Windows-System

pyvenv.cfg
Scripts/python.exe
Scripts/python3.dll
Scripts/pysetup3.exe
Scripts/pysetup3-script.py
        ... other DLLs and pyds...
Include/
Lib/site-packages/

Von Drittanbietern installierte Pakete in der virtuellen Umgebung werden ihre Python-Module im Verzeichnis site-packages und ihre ausführbaren Dateien in bin/ oder Scripts haben.

Hinweis

Bei einer normalen systemweiten Windows-Installation würde die Python-Binärdatei selbst nicht in das „Scripts/“-Unterverzeichnis gelangen, wie es im Standard-venv-Layout der Fall ist. Dies ist in einer virtuellen Umgebung nützlich, damit ein Benutzer nur ein einziges Verzeichnis zu seinem Shell-PATH hinzufügen muss, um die virtuelle Umgebung effektiv zu „aktivieren“.

Hinweis

Unter Windows ist es notwendig, auch DLLs und pyd-Dateien von kompilierten stdlib-Modulen in die venv zu kopieren oder zu symlinken, da unter Windows, wenn die venv aus einer nicht-systemweiten Python-Installation erstellt wird, die Kopien dieser Dateien aus der Python-Installation nicht gefunden werden können, wenn Python aus der venv ausgeführt wird.

Sysconfig-Installationsschemata und User-Site

Dieser Ansatz verzichtet ausdrücklich darauf, ein neues sysconfig-Installationsschema für venvs einzuführen. Vielmehr stellen wir durch die Modifizierung von sys.prefix sicher, dass bestehende Installationsschemata, die Standorte auf sys.prefix basieren, in einer venv einfach funktionieren. Installationen nach anderen Installationsschemata (z. B. die User-Site-Schemata), deren Pfade nicht relativ zu sys.prefix sind, werden von einer venv überhaupt nicht beeinflusst.

Es ist möglicherweise machbar, eine alternative Implementierung von Python-virtuellen Umgebungen auf Basis eines virtuellen sysconfig-Schemas zu erstellen, aber es wäre weniger robust, da mehr Code erforderlich wäre, um zu wissen, ob er innerhalb einer virtuellen Umgebung operiert oder nicht.

Include-Dateien

Das aktuelle virtualenv behandelt Include-Dateien auf diese Weise.

Auf POSIX-Systemen, wo die Include-Dateien der installierten Python-Version unter ${base_prefix}/include/pythonX.X gefunden werden, erstellt virtualenv ${venv}/include/ und symlinked ${base_prefix}/include/pythonX.X nach ${venv}/include/pythonX.X. Unter Windows, wo die Python-Include-Dateien unter {{ sys.prefix }}/Include gefunden werden und Symlinks nicht zuverlässig verfügbar sind, kopiert virtualenv {{ sys.prefix }}/Include nach ${venv}/Include. Dies stellt sicher, dass Erweiterungsmodule, die innerhalb der virtualenv kompiliert und installiert werden, immer die Python-Headerdateien finden, die sie am erwarteten Ort relativ zu sys.prefix benötigen.

Diese Lösung ist nicht ideal, wenn ein Erweiterungsmodul eigene Headerdateien installiert, da der Standardinstallationsort für diese Headerdateien ein Symlink zu einem Systemverzeichnis sein kann, das nicht beschreibbar ist. Ein Installer, pip, umgeht dies explizit, indem er Headerdateien an einem nicht standardmäßigen Ort ${venv}/include/site/pythonX.X/ installiert, da es in Python derzeit keine standardmäßige Abstraktion für ein sitespezifisches Include-Verzeichnis gibt.

Diese PEP schlägt einen leicht anderen Ansatz vor, der aber im Wesentlichen den gleichen Effekt und die gleichen Vor- und Nachteile hat. Anstatt Include-Dateien in die venv zu symlinken oder zu kopieren, modifizieren wir einfach die sysconfig-Schemata so, dass Headerdateien immer relativ zu base_prefix und nicht zu prefix gesucht werden. (Wir erstellen auch ein include/-Verzeichnis innerhalb der venv, damit Installer dort Include-Dateien speichern können, die innerhalb der venv installiert werden.)

Eine bessere Handhabung von Include-Dateien in distutils/packaging und damit auch in pyvenv ist ein Bereich, der möglicherweise eine eigene zukünftige PEP verdient. Vorerst schlagen wir vor, dass sich das bisherige Verhalten von virtualenv zumindest in der Praxis als „gut genug“ erwiesen hat.

API

Die oben beschriebene High-Level-Methode nutzt eine einfache API, die Mechanismen für Drittanbieter-Tools für virtuelle Umgebungen bietet, um die Umgebungsgestaltung nach ihren Bedürfnissen anzupassen.

Das Modul venv enthält eine Klasse EnvBuilder, die die folgenden Schlüsselwortargumente bei der Instanziierung akzeptiert.

  • system_site_packages – Ein boolescher Wert, der angibt, dass die systemweiten Python-Site-Packages für die Umgebung verfügbar sein sollen. Standardmäßig False.
  • clear – Ein boolescher Wert, der, wenn er wahr ist, ein bestehendes Zielverzeichnis löscht, anstatt eine Ausnahme auszulösen. Standardmäßig False.
  • symlinks – Ein boolescher Wert, der angibt, ob versucht werden soll, die Python-Binärdatei (und alle notwendigen DLLs oder andere Binärdateien, z. B. pythonw.exe) zu symlinken, anstatt sie zu kopieren. Standardmäßig False.

Der instanziierte env-builder verfügt über eine Methode create, die als erforderliches Argument den Pfad (absolut oder relativ zum aktuellen Verzeichnis) des Zielverzeichnisses annimmt, das die virtuelle Umgebung enthalten soll. Die Methode create erstellt die Umgebung entweder im angegebenen Verzeichnis oder löst eine entsprechende Ausnahme aus.

Das Modul venv bietet auch eine Modul-Level-Funktion create als Komfortfunktion.

def create(env_dir,
           system_site_packages=False, clear=False, use_symlinks=False):
    builder = EnvBuilder(
        system_site_packages=system_site_packages,
        clear=clear,
        use_symlinks=use_symlinks)
    builder.create(env_dir)

Ersteller von Drittanbieter-Tools für virtuelle Umgebungen können die bereitgestellte Klasse EnvBuilder als Basisklasse verwenden.

Die Methode create der Klasse EnvBuilder veranschaulicht die verfügbaren Hooks für die Anpassung.

def create(self, env_dir):
    """
    Create a virtualized Python environment in a directory.

    :param env_dir: The target directory to create an environment in.

    """
    env_dir = os.path.abspath(env_dir)
    context = self.create_directories(env_dir)
    self.create_configuration(context)
    self.setup_python(context)
    self.post_setup(context)

Jede der Methoden create_directories, create_configuration, setup_python und post_setup kann überschrieben werden. Die Funktionen dieser Methoden sind:

  • create_directories – Erstellt das Umgebungsverzeichnis und alle notwendigen Verzeichnisse und gibt ein Kontextobjekt zurück. Dies ist nur ein Behälter für Attribute (wie Pfade) zur Verwendung durch die anderen Methoden.
  • create_configuration – Erstellt die Konfigurationsdatei pyvenv.cfg in der Umgebung.
  • setup_python – Erstellt eine Kopie der Python-Ausführungsdatei (und unter Windows, DLLs) in der Umgebung.
  • post_setup – Eine Hook-Methode (standardmäßig keine Operation), die in Drittanbieter-Unterklassen überschrieben werden kann, um Pakete vorab zu installieren oder Skripte in der virtuellen Umgebung zu installieren.

Darüber hinaus bietet EnvBuilder eine Hilfsmethode, die von post_setup in Unterklassen aufgerufen werden kann, um bei der Installation benutzerdefinierter Skripte in die virtuelle Umgebung zu helfen. Die Methode install_scripts akzeptiert als Argumente das context-Objekt (siehe oben) und einen Pfad zu einem Verzeichnis. Das Verzeichnis sollte die Unterverzeichnisse „common“, „posix“, „nt“ enthalten, die jeweils Skripte für das Bin-Verzeichnis in der Umgebung enthalten. Der Inhalt von „common“ und des Verzeichnisses, das os.name entspricht, wird nach einer Textersetzung von Platzhaltern kopiert.

  • __VENV_DIR__ wird durch den absoluten Pfad des Umgebungsverzeichnisses ersetzt.
  • __VENV_NAME__ wird durch den Namen der Umgebung (letztes Pfadsegment des Umgebungsverzeichnisses) ersetzt.
  • __VENV_BIN_NAME__ wird durch den Namen des Bin-Verzeichnisses (entweder bin oder Scripts) ersetzt.
  • __VENV_PYTHON__ wird durch den absoluten Pfad der ausführbaren Datei der Umgebung ersetzt.

Die Unterklasse DistributeEnvBuilder in der Referenzimplementierung veranschaulicht, wie der Anpassungshaken in der Praxis genutzt werden kann, um Distribute vorab in die virtuelle Umgebung zu installieren. Es ist nicht vorgesehen, dass DistributeEnvBuilder tatsächlich in den Python-Kern aufgenommen wird, aber sie macht die Referenzimplementierung für Test- und Erkundungszwecke unmittelbar nützlicher.

Abwärtskompatibilität

Aufteilung der Bedeutungen von sys.prefix

Jedes Tool für virtuelle Umgebungen in dieser Richtung (das versucht, Site-Packages zu isolieren, während es sich weiterhin der Standardbibliothek der Basis-Python-Installation bedient, ohne dass diese in die virtuelle Umgebung symlinked werden muss) schlägt eine Aufteilung zwischen zwei verschiedenen Bedeutungen vor, die derzeit beide in sys.prefix zusammengefasst sind: die Antworten auf die Fragen „Wo ist die Standardbibliothek?“ und „Wo ist der Site-Packages-Speicherort, an dem Drittanbieter-Module installiert werden sollen?“

Diese Aufteilung könnte durch die Einführung eines neuen sys-Attributs für entweder das frühere Präfix oder das letztere Präfix gehandhabt werden. Jede Option birgt das Potenzial für eine gewisse Rückwärtsinkompatibilität mit Software, die geschrieben wurde, um die andere Bedeutung für sys.prefix anzunehmen. (Solche Software sollte vorzugsweise die APIs in den Modulen site und sysconfig verwenden, um diese Fragen zu beantworten, anstatt sys.prefix direkt zu verwenden, in welchem Fall kein Rückwärtskompatibilitätsproblem besteht, aber in der Praxis sys.prefix manchmal verwendet wird.)

Die Dokumentation für sys.prefix beschreibt es als „Ein String, der das sitespezifische Verzeichnispräfix angibt, unter dem die plattformunabhängigen Python-Dateien installiert sind“, und erwähnt ausdrücklich die Standardbibliothek und die Headerdateien, die unter sys.prefix gefunden werden. site-packages wird nicht erwähnt.

Die Beibehaltung dieser dokumentierten Definition würde bedeuten, dass sys.prefix weiterhin auf die systemweite Basisinstallation zeigt (wo die Standardbibliothek und Headerdateien gefunden werden), und ein neuer Wert in sys (etwas wie sys.site_prefix) eingeführt wird, um auf das Präfix für site-packages zu zeigen. Dies würde die dokumentierte Semantik von sys.prefix beibehalten, birgt aber das Risiko, die Isolation zu brechen, wenn Drittanbieter-Code sys.prefix anstelle von sys.site_prefix oder der entsprechenden site-API verwendet, um Site-Packages-Verzeichnisse zu finden.

Der bemerkenswerteste Fall sind wahrscheinlich setuptools und sein Fork distribute, die meist distutils und sysconfig APIs verwenden, aber sys.prefix direkt verwenden, um eine Liste von Site-Verzeichnissen für die Vorabprüfung zu erstellen, wo pth-Dateien nützlich platziert werden können.

Ansonsten findet eine Google Code Search eine scheinbar etwa gleiche Mischung aus Paketen, die sys.prefix verwenden, um einen Site-Packages-Pfad zu erstellen, und Paketen, die es verwenden, um z. B. die Standardbibliothek von der Code-Ausführungsverfolgung zu eliminieren.

Obwohl dies die Modifizierung der dokumentierten Definition von sys.prefix erfordert, bevorzugt diese PEP es, sys.prefix auf die virtuelle Umgebung (wo site-packages gefunden wird) zeigen zu lassen und sys.base_prefix einzuführen, um auf die Standardbibliothek und die Python-Headerdateien zu zeigen. Begründung für diese Wahl:

  • Es ist vorzuziehen, auf der Seite größerer Isolation der virtuellen Umgebung zu irren.
  • Virtualenv modifiziert bereits sys.prefix so, dass es auf die virtuelle Umgebung zeigt, und in der Praxis war dies kein Problem.
  • Keine Modifizierung von setuptools/distribute erforderlich.

Auswirkungen auf andere Python-Implementierungen

Die meisten Änderungen dieser PEP erfolgen in der Standardbibliothek, die von anderen Python-Implementierungen gemeinsam genutzt wird und keine Probleme verursachen sollte.

Andere Python-Implementierungen müssen das neue sys.prefix-Suchverhalten des Interpreter-Bootstraps nachbilden, einschließlich des Auffindens und Parsens der pyvenv.cfg-Datei, falls vorhanden.

Referenzimplementierung

Die Referenzimplementierung finden Sie in einem Klon des Mercurial-Repositorys von CPython. Um sie zu testen, erstellen Sie mit bin/pyvenv /pfad/zu/neuer/venv eine virtuelle Umgebung.


Quelle: https://github.com/python/peps/blob/main/peps/pep-0405.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT