»The process of preparing programs for a digital computer is especially attractive, not only because it can be economically and scientifically rewarding, but also because it can be an aesthetic experience much like composing poetry or music.” – Donald E. Knuth
22 Distribution von Python-Projekten
Es ist anzunehmen, dass Sie im Laufe dieses Buches bereits das eine oder andere eigenständige Python-Programm geschrieben haben. Vielleicht haben Sie sogar schon ein Programm oder Modul in Python geschrieben, das auch für andere Leute von Nutzen sein könnte. In diesem Moment stellt sich zwangsläufig die Frage, wie ein Python-Programm oder -Modul adäquat veröffentlicht werden kann. Idealerweise sollte es so geschehen, dass der Benutzer kein Experte sein muss, um es zu installieren.
Dazu ist in Pythons Standardbibliothek vor allem das Modul distutils enthalten, mit dem sich fertige Distributionen Ihres Programms oder Moduls erstellen lassen. Danach werden wir uns mit dem Drittanbietermodul py2exe beschäftigen, das Ihr Python-Programm zusammen mit dem gesamten Python-Interpreter zu einer einzigen ausführbaren Datei zusammenschweißt.
Zum Schluss gehen wir noch auf das Drittanbietermodul epydoc ein, mit dem sich sehr bequem eine Dokumentation zu Ihrem Programm oder Modul generieren lässt.
22.1 Erstellen von Distributionen – distutils 

Das Paket distutils zielt auf die Distribution von Python-Modulen ab. Selbstverständlich könnte man einfach den Quellcode des Moduls ins Internet stellen und dazu eine Installationsanweisung liefern. Das scheint zwar aus Sicht des Entwicklers erst einmal sehr bequem zu sein, ist aber aus Sicht des Benutzers nicht gerade komfortabel. Der Benutzer muss dann, um das Programm zu installieren, von Hand allerlei Dateien kopieren und sich dabei immer strikt an gewisse Regeln halten. Das kann man von einem Benutzer nicht verlangen. Der Installationsprozess soll durch das Paket distutils automatisiert werden, indem sogenannte Distributionen erstellt werden.
Bei einer Distribution unterscheidet man grundsätzlich zwei Typen:
- Eine sogenannte Quellcodedistribution (engl. source distribution) ist ein Archiv, das den Quellcode Ihres Moduls enthält. Zusätzlich zu dem Quellcode existiert ein Installationsscript namens setup.py, das die Installation des Moduls durchführt. Der Benutzer braucht diese Art einer Distribution also nur herunterzuladen, zu entpacken und das Installationsscript zu starten. Der Vorteil einer Quellcodedistribution ist ihre Plattformunabhängigkeit. Es muss also nur eine Distribution erstellt werden, die für jedes unterstützte Betriebssystem verwendet werden kann.
- Eine sogenannte Binärdistribution (engl. binary distribution) ist eine ausführbare Datei, die die Installation Ihres Moduls automatisch durchführt. Der Benutzer braucht diese Art einer Distribution also nur herunterzuladen und auszuführen. Eine Binärdistribution ist für den Benutzer besonders komfortabel, da er nur zwei Arbeitsschritte auszuführen hat. Allerdings bedeutet eine Binärdistribution mehr Aufwand für den Entwickler, denn das Installationsprogramm muss für verschiedene Plattformen erstellt werden.
Zum Erstellen einer Distribution sind mit dem distutils-Paket im Allgemeinen folgende Arbeitsschritte nötig:
- Schreiben Ihres Moduls oder Pakets [Eigentlich handelt es sich dabei nicht um einen Arbeitsschritt zum Erstellen einer Distribution. Dennoch ist es einleuchtenderweise eine unverzichtbare Voraussetzung. Beachten Sie, dass Sie auch mehrere Module und/oder Pakete in eine gemeinsame Distribution verpacken können. Näheres dazu erfahren Sie im Laufe des Kapitels. ]
- Schreiben des Installationsscripts setup.py
- Erstellen einer Quellcodedistribution bzw. einer Binärdistribution
Diese Arbeitsschritte sollen in den folgenden Abschnitten detailliert besprochen werden.
| Hinweis |
| Grundsätzlich lassen sich mit distutils nicht nur Distributionen von Modulen oder Paketen erstellen, sondern auch von Extensions (dt. Erweiterungen). Solche Extensions können später wie ein Modul oder Paket eingebunden werden, sind aber im Gegensatz zu normalen Modulen oder Paketen in einer anderen Programmiersprache, üblicherweise C oder C++, geschrieben. Wir werden in Abschnitt 26.2.3, »Erzeugen der Extension«, auch auf die Verwendung von distutils im Zusammenhang mit Extensions eingehen. |
22.1.1 Schreiben des Moduls 

Dieser Punkt sollte so weit klar sein. Rufen Sie sich aber noch mal ins Gedächtnis, dass es einen Unterschied zwischen einem Modul und einem Paket gibt. Während ein Modul aus nur einer Programmdatei besteht, ist ein Paket ein Ordner, der mehrere Untermodule oder -Pakete enthalten kann. Ein Paket erkennt man an der Programmdatei __init__.py im Paketverzeichnis. Die Unterscheidung der Begriffe Modul und Paket wird beim Erstellen des Installationsscripts noch eine Rolle spielen.
An dieser Stelle soll das Beispielmodul entwickelt werden, auf das wir uns im gesamten Kapitel beziehen werden. Dabei handelt es sich um ein sehr einfaches Modul, um die grundlegende Funktionalität von distutils zu demonstrieren. Bemerkungen zu komplexeren Distributionen, die beispielsweise Pakete oder Ähnliches enthalten, finden Sie an der jeweiligen Stelle im Text.
Sinn und Zweck des Beispielmoduls ist es, einen beliebigen Text so zu verändern, dass er sich ähnlich wie dieser liest:
Nach eienr Stidue der Cmabridge Uinverstiaet, ist es eagl in wlehcer Reiehnfogle die Bchustebaen in Woeretrn vokrmomen.
Es ist nur withcig, dsas der ertse und lettze Bchusatbe an der ricthgien Stlele snid. Der Rset knan total falcsh sein und man knan es onhe Porbelme leesn.
Das ist so, wiel das mneschilcge Geihrn nihct jeedn Bchustbaen liset sodnern das Wrot als gaznes.
Das Modul stellt dabei eine Funktion verwirble_text bereit, die einen String übergeben bekommt und diesen dann so »verwirbelt« zurückgibt, dass nur der erste und letzte Buchstabe sicher auf ihrem Platz bleiben.
import random
def verwirble_text(text): liste = [] for wort in text.split(): w = list(wort[1:-1]) random.shuffle(w) liste.append("".join([wort[0], "".join(w), wort[-1]])) return " ".join(liste)
Die Funktion iteriert in einer Schleife über alle im übergebenen String enthaltenen Wörter. Bei jedem Schleifendurchlauf wird der Teilstring aus dem jeweiligen Wort extrahiert, der verwirbelt werden soll. Dabei wird sichergestellt, dass der erste und der letzte Buchstabe nicht in diesen Teilstring mit aufgenommen werden. Zum Verwirbeln der Buchstaben wird die Funktion shuffle des Moduls random verwendet. Schlussendlich werden der verwirbelte String, der Anfangsbuchstabe und der Endbuchstabe zusammengefügt und an den resultierenden Text angehängt.
Beachten Sie, dass die Funktion der Einfachheit halber von einem absolut gutartigen String ausgeht. Das bedeutet insbesondere, dass der String keine Satzzeichen enthalten sollte.
Im Folgenden soll nun eine Distribution dieses Moduls verwirbeln erstellt werden, damit auch andere Python-Programmierer möglichst komfortabel in den Genuss dieses überaus mächtigen Werkzeugs gelangen können.
22.1.2 Das Installationsscript 

Der erste Schritt zur Distribution des eigenen Moduls ist das Erstellen eines Installationsscripts. Dies ist eine Python-Programmdatei namens setup.py, über die später das Erstellen der Distribution abläuft. Auch die Installation einer Quellcodedistribution aufseiten des Benutzers geschieht durch Aufruf dieser Programmdatei.
In unserem Beispiel muss im Installationsscript nur die Funktion setup des Moduls distutils.core aufgerufen werden.
from distutils.core import setup
setup( name = "verwirbeln", version = "1.0", author = "Micky Maus", author_email = "micky@maus.de", py_modules = ["verwirbeln"] )
Diese Funktion bekommt verschiedene keyword arguments übergeben, die Informationen über das Modul enthalten. Zusätzlich bekommt die Funktion über den Parameter py_modules alle Programmdateien übergeben, die der Distribution angehören sollen. Auf diese Weise ist es auch möglich, mehrere selbst geschriebene Module in einer Distribution anzubieten.
Das ist tatsächlich schon alles. Diese Programmdatei kann jetzt dazu verwendet werden, das Modul auf einem beliebigen Rechner mit Python-Installation zu installieren oder eine Distribution des Moduls zu erstellen. Wie das im Einzelnen funktioniert, klären wir später, zunächst betrachten wir einmal die Funktion setup.
distutils.core.setup(arguments)
Die Funktion setup des Moduls distutils.core muss in der Programmdatei setup.py aufgerufen werden und stößt den jeweils gewünschten Installationsprozess an. Dazu müssen der Funktion verschiedene keyword arguments übergeben werden, die Informationen über das Modul bzw. Paket bereitstellen. Die folgende Tabelle listet die wichtigsten möglichen Argumente auf und klärt kurz ihre Bedeutung.
Wenn nichts anderes angegeben ist, handelt es sich bei den jeweiligen Parametern um Strings.
| Parametername | Beschreibung |
|
name
|
Der Name der Distribution |
|
version
|
Die Versionsnummer der Distribution |
|
description
|
Eine kurze Beschreibung der Distribution |
|
long_description
|
Eine ausführliche Beschreibung der Distribution |
|
author
|
Der Name des Autors |
|
author_email
|
Die E-Mail-Adresse des Autors |
|
maintainer
|
Der Name des Paketverwalters (Maintainer), sofern dies nicht der Autor selbst ist |
|
maintainer_email
|
Die E-Mail-Adresse des Paketverwalters |
|
url
|
Die URL einer Homepage mit weiteren Informationen zur Distribution |
|
download_url
|
Die URL, unter der die Distribution direkt heruntergeladen werden kann |
|
packages
|
Eine Liste von Strings, die die Namen aller Pakete enthält, die in der Distribution enthalten sein sollen. |
|
package_dir
|
Ein Dictionary, über das Pakete in Unterverzeichnissen in die Distribution aufgenommen werden können. Näheres zur Verwendung von package_dir folgt weiter unten. |
|
package_data
|
Ein Dictionary, über das Dateien, die zu einem Paket gehören, mit in die Distribution aufgenommen werden können. Näheres zur Verwendung von package_data finden Sie weiter unten. |
|
py_modules
|
Eine Liste von Strings, die die Namen aller Python-Module enthält, die in der Distribution enthalten sein sollen |
|
scripts
|
Eine Liste von Strings, die die Namen aller Scriptdateien enthält, die in der Distribution enthalten sein sollen |
|
data_files
|
Eine Liste von Tupeln, über die zusätzliche Dateien in die Distribution mit aufgenommen werden können. Näheres zur Verwendung von data_files finden Sie weiter unten. |
|
ext_modules
|
Eine Liste von distutils.core.Extension-Instanzen, die die Namen aller Python-Erweiterungen enthält, die kompiliert werden und in der Distribution enthalten sein sollen. Näheres zu diesem Thema erfahren Sie in Abschnitt 26.2. |
|
script_name
|
Der Name des Installationsscripts, das in der Distribution verwendet werden soll. Dieser Parameter ist mit sys.argv[0], also dem Namen des Scripts vorbelegt, das gerade ausgeführt wird. |
|
license
|
Ein String, der die Lizenz angibt, unter der die Distribution veröffentlicht wird. |
|
console
|
Der Pfad zu einer Programmdatei, die mithilfe von py2exe zu einer ausführbaren Windows-Konsolenanwendung gemacht werden soll2 |
|
window
|
Der Pfad zu einer Programmdatei, die mithilfe von py2exe zu einer ausführbaren Windows-EXE gemacht werden soll. Dieser Parameter eignet sich für Programme mit grafischer Benutzeroberfläche, da kein Konsolenfenster angezeigt wird. |
Distribution von Paketen
Wenn Ihr Projekt statt aus einzelnen Modulen aus einem oder mehreren Paketen besteht, müssen Sie die Namen aller Pakete, die in die Distribution aufgenommen werden sollen, über den Schlüsselwortparameter packages angeben: [Näheres zu py2exe erfahren Sie in Abschnitt 22.2. ]
from distutils.core import setup
setup( [.] packages = ["paket1", "paket2", "paket1.unterpaket1"] )
In diesem Fall werden die Pakete paket1 und paket2, die sich im Hauptverzeichnis befinden müssen, in die Distribution aufgenommen. Zusätzlich wird noch das Paket unterpaket1 aufgenommen, das sich innerhalb des Pakets paket1 befindet. Beachten Sie, dass Sie durchaus sowohl Pakete über packages, als auch einzelne Module über py_modules in die Distribution aufnehmen können.
Natürlich möchte Sie niemand dazu zwingen, das Installationsscript im Hauptordner abzulegen, in dem möglicherweise bereits relativ viele Programmdateien liegen. Oftmals existiert neben dem Installationsscript ein Ordner src oder source, in dem sich dann die Module oder Pakete der Distribution befinden. Um solch einen Unterordner im Installationsscript bekannt zu machen, wird der Schlüsselwortparameter package_dir beim Aufruf von setup übergeben:
from distutils.core import setup
setup( [.] package_dir = {"" : "src"}, packages = ["paket1", "paket2", "paket1.unterpaket1"] )
Distribution zusätzlicher Dateien
Neben Modulen und Paketen können noch weitere Dateien zu Ihrem Projekt gehören und sollten damit auch Platz in der Distribution finden. Dazu zählen zunächst einfache Scriptdateien. Diese implementieren beispielsweise ein Tool, das im Zusammenhang mit Ihrem Paket steht. Der Unterschied zwischen einem Modul und einer Scriptdatei ist der, dass das Modul selbst keinen Python-Code ausführt, sondern nur Funktionen oder Klassen bereitstellt, während eine Scriptdatei ein lauffähiges Programm enthält. Solche Scriptdateien können beim Aufruf von setup durch den Schlüsselwortparameter scripts übergeben werden. Dabei muss für scripts, wie für andere Parameter auch, eine Liste von Strings übergeben werden, die jeweils einen Dateinamen enthalten.
Ein kleiner Service, den das Paket distutils in Bezug auf Scriptdateien durchführt, ist das automatische Anpassen der Shebang-Zeile an das Betriebssystem, auf dem die Distribution installiert wird.
Die nächste Kategorie zusätzlicher Dateien sind Ressourcen, die von bestimmten Paketen benötigt werden und in diesen enthalten sind. Beispielsweise könnte das Paket paket1 die beiden Dateien hallo.txt und welt.txt erfordern. In einem solchen Fall können diese Dateien über den Schlüsselwortparameter package_data in Form eines Dictionarys übergeben werden:
setup(
[.]
packages = ["paket1", "paket2", "paket1.unterpaket1"],
package_data = {"paket1" : ["hallo.txt", "welt.txt"]}
)Anstatt jede Datei einzeln anzugeben, können auch Wildcards verwendet werden. So würde der Wert ["*.txt"] alle Textdateien einbinden, die sich im Verzeichnis des Paketes paket1 befinden.
Zu guter Letzt ist es möglich, sonstige Dateien mit in die Distribution aufzunehmen. Dazu zählen alle Dateien, die in keine der vorherigen Kategorien passen, beispielsweise Konfigurationsdateien, Hilfeseiten oder Ähnliches. Diese Dateien können über den Schlüsselwortparameter data_files beim Funktionsaufruf von setup als Liste von Tupeln übergeben werden:
setup(
[.]
data_files = [("grafiken", ["test1.bmp", "test2.bmp"])
("config", ["programm.cfg"])]
)In diesem Fall werden die Dateien test1.bmp und test2.bmp aus dem Verzeichnis grafiken sowie die Datei programm.cfg aus dem Verzeichnis config in die Distribution übernommen. Die Verzeichnisse verstehen sich relativ zum Pfad des Installationsscripts. Beachten Sie, dass hier durchaus auch absolute Pfade, beispielsweise für eine systemweite Konfigurationsdatei, angegeben werden können.
| Hinweis |
| Beachten Sie allgemein, dass Sie Ordner innerhalb eines Pfades immer durch einen einfachen Slash (/) voneinander trennen sollten. Das Paket distutils kümmert sich dann um die korrekte »Übersetzung« des Pfades in das Format des jeweiligen Betriebssystems. |
22.1.3 Erstellen einer Quellcodedistribution 

Nachdem das Installationsscript geschrieben wurde, kann mit dessen Hilfe eine Quellcodedistribution Ihres Pakets oder Moduls erstellt werden. Dazu wechseln Sie in das Verzeichnis, in dem das Installationsscript liegt, und führen es mit dem Argument sdist aus:
setup.py sdist
Dieser Befehl erzeugt die Quellcodedistribution im Unterordner dist nach dem Namensschema Projektname-Version.Format. Dabei kann das Format des Archivs über die Option --formats angegeben werden. Es ist zudem möglich, eine Distribution in mehreren Archivformaten zu erstellen:
setup.py sdist --formats=zip,gztar
Mögliche Werte sind dabei zip für ein zip-Archiv (*.zip), gztar für ein gz-komprimiertes tar-Archiv (*.tar.gz), bztar für ein bz2-komprimiertes tar-Archiv (*.tar.bz2), ztar für ein Z-komprimiertes tar-Archiv (*.tar.Z) sowie tar für ein unkomprimiertes tar-Archiv. Wenn die Option --formats nicht angegeben wurde, wird unter Windows ein zip-Archiv und unter Unix-Systemen ein gz-komprimiertes tar-Archiv erstellt.
In das Archiv werden alle Dateien aufgenommen, die im Installationsscript eingetragen wurden. Zusätzlich wird eine Datei namens README oder README.txt automatisch in das Archiv mit aufgenommen, sofern eine solche im selben Ordner wie das Installationsscript existiert.
Das resultierende Archiv, die Quellcodedistribution, kann jetzt veröffentlicht und verbreitet werden. Der Benutzer, der diese Distribution herunterlädt, kann Ihr Modul bzw. Ihr Paket so installieren, wie in Abschnitt 22.1.5 beschrieben wird.
| Hinweis |
| Beim Erstellen einer Distribution wird eine Datei namens MANIFEST erzeugt. Diese Textdatei enthält die Pfade zu allen Dateien, die in die Distribution mit aufgenommen werden. Beim erneuten Erstellen der Distribution werden diese Pfade aus der MANIFEST-Datei wieder ausgelesen, sofern die Datei existiert. |
| Wenn das Installationsscript aktueller ist als die MANIFEST-Datei, wird die MANIFEST-Datei beim nächsten Erstellvorgang aktualisiert. Trotzdem ist es gelegentlich notwendig, dieses Aktualisieren explizit zu erzwingen: |
|
setup.py sdist --force-manifest
setup.py sdist --manifest-only
|
| Mit diesen Aufrufen von setup.py wird das Aktualisieren der MANIFEST-Datei vor dem Erstellen der Distribution erzwungen bzw. ausschließlich die MANIFEST-Datei aktualisiert. |
22.1.4 Erstellen einer Binärdistribution 

Neben einer Quellcodedistribution ist das Erstellen einer Binärdistribution von besonderem Interesse, da diese den wenigsten Installationsaufwand hat. Umgekehrt bedeutet es allerdings mehr Arbeit für Sie, da für verschiedene Betriebssysteme ganz unterschiedliche Formate für Binärdistributionen erstellt werden müssen. Das prominenteste dieser Formate ist ein Windows Installer, aber auch RPM-Pakete für RPM-basierende Linux-Distributionen können erstellt werden.
Beachten Sie, dass Sie neben einer Binärdistribution stets auch eine Quellcodedistribution Ihres Projekts veröffentlichen sollten, da es Betriebssysteme gibt, die weder mit einem RPM-Paket noch mit einem Windows Installer etwas anfangen können.
Zum Erzeugen einer Binärdistribution wird das Installationsscript mit den folgenden Argumenten aufgerufen werden:
| Argument | Bedeutung |
|
bdist_rpm |
Erzeugt ein RPM-Paket für RPM-basierende Linux-Distributionen wie beispielsweise Fedora Core oder SuSE. |
|
bdist_wininst |
Erzeugt einen Windows Installer, der dazu da ist, ein Modul bzw. Paket auf einem Windows-System zu installieren. Es wird die ausführbare Datei Projektname-Version-win32.exe im Unterordner dist erzeugt. |
Da alle Informationen, die zum Erstellen der Binärdistribution benötigt werden, bereits im Installationsscript angegeben wurden, ist das Erzeugen einer Binärdistribution tatsächlich mit den folgenden Aufrufen von setup.py erledigt:
setup.py bdist_wininst setup.py bdist_rpm
Beachten Sie allgemein, dass eine Binärdistribution unabhängig von einer Quellcodedistribution erzeugt werden kann. Es ist aber sinnvoll, ein Projekt sowohl in Form einer Binärdistribution für Windows als auch in Form einer Quellcodedistribution für andere Betriebssysteme anzubieten.
| Hinweis |
| Solange Ihr Projekt aus reinen Python-Modulen besteht, also weder Pakte noch Extensions beinhaltet, kann die Installationsdatei für Windows auch unter anderen Betriebssystemen, beispielsweise unter Linux, erzeugt werden. Sobald aber Pakete oder Erweiterungen enthalten sind, muss dafür ein Windows-System verwendet werden. |
22.1.5 Beispiel für die Verwendung einer Distribution 

Nachdem Sie jetzt das grundlegende Handwerkszeug zum Erstellen einer Binär- und Quellcodedistribution erlernt haben, sollen hier noch ein paar Worte zur Verwendung der Distributionen selbst folgen.
Zu einer Binärdistribution brauchen wir dabei nicht besonders viel zu sagen, denn die Installationsprozedur entspricht dem auf dem jeweiligen Betriebssystem üblichen Vorgehen.
Wie eine Quellcodedistribution installiert wird, ist hingegen nicht ganz intuitiv und sollte bei Ihren eigenen Distributionen unbedingt in einer Readme-Datei erklärt werden. Die Installation einer Quellcodedistribution verläuft nach dem folgenden Schema:
- Herunterladen der Distribution
- Entpacken des Archivs
- Ausführen der Programmdatei setup.py mit dem Argument install
Sie sehen, dass auch für die Installation einer Distribution die Programmdatei setup.py verantwortlich ist:
setup.py install
Wenn die Programmdatei setup.py mit dem Argument install ausgeführt wird, installiert sie die Distribution in die Python-Umgebung, die auf dem System installiert ist. Beachten Sie, dass dafür, je nach System, Administrator- oder Root-Rechte erforderlich sind.




bestellen





