Package Management und Versionskontrolle mit github

Inhalt

Im neunten Kapitel behandeln wir Package Management, sowie Versionverwaltung und decken die folgenden Konzepte ab:

  • Der Python Package Index PyPI

  • Package Management mit pip

  • Definition von Packages

  • Versionskontrolle mit git

Package Management

In Kapitel 8 haben wir mit numpy, pandas, matplotlib und networkx bereits vier Packages kennen gelernt, die nicht zum Kern von Python gehören. In Kapitel 5 haben wir gelernt, das nach Modulen und Packages im Python Modulpfad gesucht wird. Um diese Packages benutzen können, muss man also dafür sorgen, dass diese im Python Modulpfad verfügbar sind. Hierzu könnte man die Dateien der Packages zum Beispiel als Archiv runterladen und händisch in einen der Ordner des Modulpfads entpacken. Das ist jedoch kompliziert und fehleranfällig, insbesondere wenn man die Version eines Packages ändern möchte, also ein Ugrade auf eine neuere, oder Downgrade auf eine ältere Version, durchführen will. Daher macht man dies in der Regel nicht selbst, sondern benutzt ein Werkzeug für das Package Management. In der Python Welt gibt es hierfür pip. Mit conda gibt es noch eine Alternative zu pip, die wir hier aber nicht näher betrachten.

1. Der Python Package Index

Die Grundlage für das Package Management ist ein Index, auf dem Packages publiziert werden. Der größte und wichtigste Index für Python ist PyPI. Hier findet man nahezu alles, was in Python an Packages öffentlich verfügbar ist. Die Packages liegen hier nicht nur in der neuesten Version vor, sondern auch in allen vorher publizierten Versionen. Daher kann man hier auch einfach alte Versionen beziehen, wenn man diese zum Beispiel aus Kompatibilitätsgründen benötigt.

2. Installieren von Packages mit pip

pip ist ein Python Package welches man einfach als Kommandozeilenwerkzeug betrachten kann. Das Installieren von Packages mit pip ist sehr einfach und ähnlich zum Arbeiten mit apt unter Ubuntu Linux. Die neuste Version installiert man einfach mit pip install:

Kommandozeile mit pip
# Um die neuste Version zu installieren
deameni@ndole-dell:~$ pip install

# Beispiel von numpy
deameni@ndole-dell:~$ pip install numpy

# Will man eine bestimmte Version, kann man diese angeben:
deameni@ndole-dell:~$ pip install numpy==15.04

# Man kann auch eine mindest Version fordern:
deameni@ndole-dell:~$ pip install numpy>=16.00

# Um ein bereits installiertes Package auf eine neuere Version zu upgraden:
deameni@ndole-dell:~$ pip install --upgrade numpy

# Um mehrere Packages auf einmal zu installieren
deameni@ndole-dell:~$ pip install numpy pandas matplotlib networkx


Hat man keine Administrationsrechte, kann man häufig Packages nicht global für alle Nutzer eines Betriebssystems installieren. Daher bietet pip mit dem --user Parameter auch die Möglichkeit, Packages nur für einen aktuellen Benutzer zu installieren: pip install –user numpy

3. Datei requirements.txt

Will man für ein Projekt angeben, welche Packages benötigt werden, kann man diese in einer Textdatei mit dem Namen requirements.txt definieren.

requirements.txt
================
numpy>=16.00
pandas
matplotlib
networkx


Man kann alle Packages dann mit einem Befehl installieren:

Ausführung vom Programm
deameni@ndole-dell:~$ pip install -r requirements.txt

4. Installieren von anderen Quellen

Ist ein Package nicht in PyPI verfügbar, aber zum Beispiel in einem lokalen Ordner oder auf GitHub, kann man dies auch mit pip installieren:

Ausführung vom Programm
deameni@ndole-dell:~$ pip install /path/to/local/folder
deameni@ndole-dell:~$ pip install ./downloads/archive-1.0.0.tar.gz

5. Eigene Packages mit pip kompatibel machen

Um ein Package mit pip installierbar zu machen, bzw. auf PyPI zu veröffentlichen, benötigt man noch einige zusätzliche Dateien.

  • Eine setup.py die das Package erstellt. Außerdem kann man hier Abhängigkeiten eines Packages verwalten, also Packages die für die Benutzung benötigt werden.

  • Eine LICENSE Datei in der die Lizenz, unter der der Quelltext geteilt wird, mitgeteilt wird (z.B. MIT, BSD, Apache, GPL).

  • Eine (optionale) Datei mit einer Beschreibung des Packages (z.B. README.md).

Die wichtigste dieser Dateien ist die setup.py. Unten ist ein Beispiel von diesem Datei.

setup.py
========
import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="course-sample-package",
    version="0.0.1",
    author="Loich Kamdoum D.",
    author_email="lkd18@tu-clausthal.de",
    description="A small example package for a programming course",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/kamdoumloich/dataSciencePractice",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: Apache Software License",
        "Operating System :: OS Independent",
    ],
)


Wie man sieht, benutzt die setup.py das Package setuptools. Diese Package stellt die Funktionalität zur Packageerstellung zur Verfügung. Neben dem einfachen Setup aus unserem Beispiel, kann man über die setup.py auch Abhängigkeiten verwalten. Neben den setuptools benötigt man auch noch das Package wheel um ein eigenes Package zu erstellen. Ein Wheel ist das Binärformat für Python Packages. Beides kann man einfach mit pip installieren.

Um das Archiv zu erstellen muss man die setup.py mit dem Interpreter ausführen:

deameni@ndole-dell:~$ python3 setup.py sdist bdist_wheel

Das Package wird dann im Unterordner dist erstellt. Durch den Parameter sdist wird ein .tar.gz Archiv mit den Dateien des Packages erstellt. Durch den Parameter bdist_wheel eine .whl mit dem gebauten +Wheel_ des Packages.

Die auf diese Art erstellten Packages kann man jetzt, wenn man entsprechende Accounts hat, auf PyPI, bzw. Test PyPI (Testversion von PyPI auf der man neue Packages testen sollte, bevor man sie bei PyPI hochlädt), hochladen und teilen.

Versionskontrolle mit Git

Werkzeuge zur Versionskontrolle von Dateien, insbesondere Quelltext, sind ein zentraler Bestandteil der Softwareenticklung. Mit solchen Werkzeugen lassen sich verschiedene Versionen von Dateien verwalten um ihre Änderungshistorie zu verfolgen. Außerdem ermöglichen Versionskontrollsysteme das verteilte Arbeiten an Quelltext an verschiedenen Arbeitsplätzen und insbesondere auch durch Teams. An dieser Stelle gibt es keine umfassende Einführung in Versionskontrolle. Stattdessen gibt es nur ein kurze Einführung in die wichtigsten Funktionen des derzeit verbreitetsten Werkzeugs: git.

1. Git Repositories

Die Grundlage von git sind die Repositories, vereinfacht gesagt Ordner, für die verschiedene Versionen verwaltet werden. Man kann aus einem normalen Ordner ein git Repository machen, in dem man git init ausführt. Hier sollte man jetzt keine Änderungen mehr durchführen. Stattdessen sollte man eine Arbeitskopie erstellen, in dem man den git clone pathto/repository Befehl benutzt.

Die Arbeitskopie ist eine Vollständige Kopie des Hauptrepositories und könnte diese theoretisch komplett ersetzen. In der Praxis legt man eher selten lokal ein git Hauptrepository an. Stattdessen werden diese auf einem Server verwaltet, zum Beispiel bei GitHub oder auch dem GitLab der GWDG. Von dort klont man dann die lokale Kopie.

2. Add, Commit, Push

Hat man eine Arbeitskopie eines Repositories, kann man in diesem Ordner ganz normal Arbeiten, wie in jedem anderen auch. Die Änderungen werden noch nicht von git mitverfolgt und versioniert. Ist man an einem Punkt, wo man eine neue Version von einer oder mehrerer Datei erstellen will, muss man dies git aktiv mitteilen. Hierzu muss man zuerst mit git add pathtodocument die geänderten Dateien zum Index hinzufügen. Der Index verwaltet Änderungen, die in der Arbeitskopie gemacht wurden. Will man die Änderungen zum Repository hinzufügen, also den aktuellen Index, muss man sie Commiten durch den git commit Befehl. Hierdurch wird eine neue Revision/ des Repositories erstellt, in der die Änderungen des Index beinhaltet sind. Ein Commit wird in der Regel mit einem Kommentar beschrieben, der die Änderungen zusammenfasst.

Die Änderungen sind jetzt aber immernoch nur lokal in der Arbeitskopie verfügbar. Will man die Änderungen von der lokalen Arbeitskopie ins Hauptrepository übertragen, muss man diese dort hinpushen. Mit dem Befehl git push wird im Normalfall der aktuelle Branch an origin geschickt. Mit origin wird der Ort bezeichnet, von dem man das mit Hilfe von git clone die Arbeitskopie erstellt hat. Arbeitet man auf dem Hauptentwicklungszweig, sind daher in der Regel folgenden beiden Befehle identisch und übertragen die Änderungen an das Hauptrepository:

add, commit and push from einem Datei
>>> git add sqrt.py
>>> git commit -m "added new function for calculating the square root"
>>> git push origin master # or git push

3. Pull

Zum verteilten Arbeiten gehört auch, dass man Änderungen lokal übernehmen kann, die an einer anderen Stelle gemacht wurden. Oder anders ausgedrückt: Wenn eine Änderung per push ins Hauptrepository übertragen wurde, möchten Sie andere eventuell auch lokal übernehmen, ohne das die eigenen Änderungen verloren gehen oder man das Repository neu klonen muss. Mit git pull kann man Änderungen aus dem Hauptrepository in die Arbeitskopie übernehmen. Gibt es bereits Änderungen in der lokalen Arbeitskopie, wird durch git pull ein sogenannter Merge Commit erstellt. Dieser Commit führt die lokalen Änderungen, mit denen aus dem Hauptrepository wieder zusammen.

Ein git pull funktioniert nur dann Reibungslos, wenn es keinen Konflikt zwischen der Arbeitskopie und dem Hauptrepository gibt. Ein Konflikt ensteht dann, wenn der gleiche Bereich in einer Datei geändert wurde, also überlappende Zeilen. Solange nur unterschiedliche Dateien oder zumindest nicht der gleiche Bereich in der selben Datei geändert wurde, gibt es keinen Konflikt. Im Falle eine Konfliktes, gibt es zwei Optionen: Man kann den Merge Commit rückgängig machen, dann hat man jedoch die Änderungen aus dem Hauptrepository nicht in der lokalen Arbeitskopie. Oder man kann den Konflikt lösen. Hierzu zeigt einem git alle Textstellen in Dateien, wo es Konflikte gibt an und man muss selbst entscheiden, welche Variante behalten wird. Details zur Konfliktlösung findet man in der git Dokumentation.

4. Änderungen rückgängig machen

Ein Vorteil von Versionkontrolle ist, dass man lokale Änderungen auch wieder rückgängig machen kann. Hierzu kann man den Befehl git checkout – benutzen. Mit git checkout kann man im Allgemeinen die Arbeitskopie auf einen bestimmten Commit setzen. Das rückgängig machen von Änderungen ist ein Spezialfall davon. Mit dem folgenden Befehl würde man zum Beispiel die Änderungen an den Dateien sqrt.py und __init__.py rückgängig machen.

revisions back
>>> git checkout -- sqrt.py __init__.py

5. Weitere Funktionen

Oben sind nur die wichtigsten Funktionen erklärt, die man kennen muss um mit git arbeiten zu können. Es gibt jedoch noch weitere wichtige Funktionen, die hier zwar nicht zwingend benötigt werden, aber für den Praxiseinsatz von git in größeren Projekten nicht wegzudenken sind:

  • Branches: Ein Branch ist ein isolierter Entwicklungsstrang im Repository. Der Hauptentwicklungszweig ist der master. Auf diesem wird gearbeitet, wenn kein anderer Branch angegeben wird. In den obigen Beispielen wird immer auf dem master Branch gearbeitet. Branches lassen sich durch Merge Commits zusammenführen.

  • Feature Branches: Die wichtigste Variante von Branches sind die Feature Branches. Hierbei wird ein Branch vom master erstellt um eine neue Funktionalität hinzuzufügen oder eine Fehler zu korrigieren. Die komplette Entwicklung wird dann auf diesem Branch durchgeführt, inklusive dem Test und dem Codereview. Erst wenn die Entwicklung abgeschlossen ist, wird der Feature Branch wieder mit dem master zusammengeführt. Dies passiert auf Platformen wie GitHub oder GitLab in der Regel durch Pull Requests.

  • Tags: Mit Hilfe von Tags kann man Revisionen eines Repositories einen Namen zuweisen. Die Hauptverwendung von Tags ist die Versionierung von Software, zum Beispiel um den Stand des Quelltextes, der Version 1.0.0 zugrunde liegt zu markieren.

  • Commit Amendments: Commits in git können nachträglich angepasst werden. Dies erlaubt das nachträgliche Ändern von Commits, zum Beispiel im Probleme, die mit Hilfe von Codereviews gefunden wurden, zu adressieren.