So schreiben, verpacken und verteilen Sie eine Bibliothek in Python

Python ist eine großartige Programmiersprache, aber das Verpacken ist einer der schwächsten Punkte. Es ist eine bekannte Tatsache in der Gemeinschaft. Das Installieren, Importieren, Verwenden und Erstellen von Paketen hat sich im Laufe der Jahre erheblich verbessert, ist aber immer noch nicht mit den neueren Sprachen wie Go und Rust vergleichbar, die aus den Kämpfen von Python und anderen ausgereiften Sprachen viel gelernt haben. 

In diesem Lernprogramm erfahren Sie alles Wissenswerte zum Schreiben, Verpacken und Verteilen Ihrer eigenen Pakete. 

So schreiben Sie eine Python-Bibliothek

Eine Python-Bibliothek ist eine zusammenhängende Sammlung von Python-Modulen, die als Python-Paket organisiert ist. Im Allgemeinen bedeutet dies, dass sich alle Module im selben Verzeichnis befinden und dieses Verzeichnis sich im Python-Suchpfad befindet. 

Lassen Sie uns schnell ein kleines Python 3-Paket schreiben und all diese Konzepte veranschaulichen.

Das Pathologie-Paket

Python 3 verfügt über ein ausgezeichnetes Path-Objekt, das eine enorme Verbesserung gegenüber dem ungünstigen os.path-Modul von Python 2 darstellt. Es fehlt jedoch eine wichtige Fähigkeit, den Pfad des aktuellen Skripts zu finden. Dies ist sehr wichtig, wenn Sie Zugriffsdateien relativ zum aktuellen Skript suchen möchten. 

In vielen Fällen kann das Skript an einem beliebigen Ort installiert werden, sodass Sie keine absoluten Pfade verwenden können. Das Arbeitsverzeichnis kann auf einen beliebigen Wert festgelegt werden, sodass Sie keinen relativen Pfad verwenden können. Wenn Sie auf eine Datei in einem Unterverzeichnis oder einem übergeordneten Verzeichnis zugreifen möchten, müssen Sie das aktuelle Skriptverzeichnis ermitteln können. 

So machen Sie es in Python:

import pathlib script_dir = pathlib.Path (__ file __). parent.resolve ()

Um auf eine Datei namens "file.txt" in einem "data" -Unterverzeichnis des aktuellen Skriptverzeichnisses zuzugreifen, können Sie folgenden Code verwenden: print (open (str (script_dir / 'data / file.txt'). read ())

Mit dem Pathologie-Paket haben Sie ein integriertes System script_dir Methode, und Sie verwenden es so:

from pathology.Path import script_dir print (open (str (script_dir () / 'data / file.txt'). read ()) 

Ja, es ist ein Bissen. Das Pathologiepaket ist sehr einfach. Sie leitet ihre eigene Path-Klasse von Pathlibs Path ab und fügt eine statische hinzu script_dir () das gibt immer den Pfad des aufrufenden Skripts zurück. 

Hier ist die Implementierung:

import pathlib import inspect class Pfad (Typ (pathlib.Path ())): @staticmethod def script_dir (): print (inspect.stack () [1] .filename) p = pathlib.Path (inspect.stack () [1 ] .filename) return p.parent.resolve () 

Aufgrund der plattformübergreifenden Implementierung von pathlib.Path, Sie können direkt von ihr abgeleitet werden und müssen von einer bestimmten Unterklasse stammen (PosixPath oder WindowsPath). Die Auflösung des Skripts verwendet das Inspect-Modul, um den Aufrufer und dann dessen Dateinamenattribut zu finden.

Testen des Pathologiepakets

Wenn Sie etwas schreiben, das mehr als ein Wegwerf-Skript ist, sollten Sie es testen. Das Pathologiemodul ist keine Ausnahme. Hier sind die Tests unter Verwendung des Standardeinheitentest-Frameworks: 

import os import shutil from unittest import TestCase aus pathology.path import Path-Klasse PathTest (TestCase): def test_script_dir (self): erwartet = os.path.abspath (os.path.dirname (__ file__)) actual = str (Path.script_dir) ()) self.assertEqual (erwartet, aktuell) def test_file_access (self): script_dir = os.path.abspath (os.path.dirname (__ file__)) Unterverzeichnis = os.path.join (script_dir, 'test_data') if Path (Unterverzeichnis) .is_dir (): shutil.rmtree (Unterverzeichnis) os.makedirs (Unterverzeichnis) Dateipfad = str (Pfad (Unterverzeichnis) / 'file.txt') content = '123' open (Dateipfad 'w'). write (content) test_path = Path.script_dir () / Unterverzeichnis / 'file.txt' actual = open (str (test_path)). read () self.assertEqual (content, actual) 

Der Python-Pfad

Python-Pakete müssen irgendwo im Python-Suchpfad installiert sein, damit sie von Python-Modulen importiert werden können. Der Python-Suchpfad ist eine Liste von Verzeichnissen und ist immer in verfügbar sys.path. Hier ist mein aktueller sys.path:

>>> print ('\ n'.join (sys.path)) /Users/gigi.sayfan/miniconda3/envs/py3/lib/python36.zip /Users/gigi.sayfan/miniconda3/envs/py3/lib/ python3.6 /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/lib-dynload /Users/gigi.sayfan/miniconda3/envs/py3/lib/python3.6/site-packages / Users / gigi.sayfan / miniconda3 / envs / py3 / lib / python3.6 / site-packages / setuptools-27.2.0-py3.6.egg 

Beachten Sie, dass die erste leere Zeile der Ausgabe das aktuelle Verzeichnis darstellt. Sie können also Module aus dem aktuellen Arbeitsverzeichnis importieren. Sie können Verzeichnisse direkt in / aus sys.path hinzufügen oder daraus entfernen. 

Sie können auch eine definieren PYTHONPATH Umgebungsvariable, und es gibt ein paar andere Möglichkeiten, um es zu steuern. Der Standard Site-Pakete ist standardmäßig enthalten, und hier werden Pakete installiert, die Sie mit via pip go installieren. 

So verpacken Sie eine Python-Bibliothek

Jetzt, da wir unseren Code und unsere Tests haben, packen wir alles in eine richtige Bibliothek. Python bietet einen einfachen Weg über das Setup-Modul. Sie erstellen eine Datei mit dem Namen setup.py im Stammverzeichnis des Pakets. Um eine Quelldistribution zu erstellen, führen Sie Folgendes aus: python setup.py sdist

Um eine binäre Distribution namens Rad zu erstellen, führen Sie Folgendes aus: python setup.py bdist_wheel

Hier ist die setup.py-Datei des Pathologiepakets:

von setuptools import setup, find_packages setup (name = 'pathology', version = "0.1"), url = "https://github.com/the-gigi/pathology", license = "MIT", author = "Gigi Sayfan" , author_email = "[email protected]", description = "Statische script_dir () - Methode zum Pfad hinzufügen", packages = find_packages (exclude = ['tests']), long_description = open ('README.md'). read (), zip_safe = False)

Es enthält viele Metadaten zusätzlich zu dem 'packages' - Element, das die find_packages () Funktion importiert aus Setuptools Unterpakete finden.

Erstellen wir eine Quelldistribution:

$ python setup.py sdist ausgeführt sdist ausgeführt egg_info erstellt pathology.egg-info schreiben pathology.egg-info / PKG-INFO schreibt abhängige_links zu pathology.egg-info / dependency_links.txt schreibt Top-Level-Namen zu pathology.egg-info / top_level.txt Schreibmanifestdatei "pathology.egg-info / SOURCES.txt" Lesemanifestdatei "pathology.egg-info / SOURCES.txt" Schreibmanifestdatei "pathology.egg-info / SOURCES.txt" Warnung: sdist: standard Datei nicht gefunden: sollte eine der folgenden Funktionen haben: README, README.rst, README.txt. Überprüfung der Erstellung von Pathologie-0.1. Erstellen von Pathologie-0.1 / Pathologie. Erstellen von Pathologie-0.1 / Pathology.egg-Info. Kopieren von Dateien in Pathologie-0.1 -> pathologie-0.1 kopieren pathologie / __ init__.py -> pathologie-0.1 / pathologie kopieren pathologie / path.py -> pathologie-0.1 / pathologie kopieren pathologie.egg-info / PKG-INFO -> pathologie-0.1 / pathology.egg -info kopiert pathology.egg-info / SOURCES.txt -> pathology-0.1 / pathologie.egg-info kopiert pathology.egg-info / dependency_links.txt -> pathologie -0.1 / pathology.egg-info Kopieren pathology.egg-info / not-zip-safe -> pathology-0.1 / pathology.egg-info Kopieren pathology.egg-info / top_level.txt -> pathology-0.1 / pathology.egg -info pathology-0.1 / setup.cfg erstellen dist erstellen tar-Archiv erstellen 'pathology-0.1' (und alles darunter) entfernen

Die Warnung ist, weil ich eine nicht standardmäßige README.md-Datei verwendet habe. Es ist sicher zu ignorieren. Das Ergebnis ist eine tar-gzipped-Datei unter dem Verzeichnis dist:

$ ls -la dist gesamt 8 drwxr-xr-x 3 gigi.sayfan gigi.sayfan 102 Apr 18 21:20. drwxr-xr-x 12 gigi.sayfan gigi.sayfan 408 18. April 21: 20… -rw-r - r-- 1 gigi.sayfan gigi.sayfan 1223 18. April 21:20 pathology-0.1.tar.gz

Und hier ist eine binäre Distribution:

$ python setup.py bdist_wheel Läuft bdist_wheel Läuft Build Build_py Erstellen von Build / Lib Erstellen von Build / Lib / Pathologie Kopieren der Pathologie / __ Init__.py -> Build / Lib / Pathologie Kopieren der Pathologie / Pfad.py -> Build / Lib / Pathologie Installation nach Build / bdist.macosx-10.7-x86_64 / laufendem Lauf install install_lib Erstellen von build / bdist.macosx-10.7-x86_64 Erstellen von build / bdist.macosx-10.7-x86_64 / wheel Erstellen von Build / bdist.macosx-10.7-x86_64 / rad / pathologie kopieren build / lib / pathologie / __ init__.py -> build / bdist.macosx-10.7-x86_64 / wheel / pathologie kopieren build / lib / pathologie / pfad.py -> build / bdist.macosx-10.7-x86_64 / Laufende Rad- / Pathologie install_egg_info läuft egg_info schreibt pathology.egg-info / PKG-INFO schreibt Abhängigkeitslinks zu pathology.egg-info / dependency_links.txt und schreibt Pathologie.egg-info / top_level.txt-Pathologie mit Top-Level-Namen. egg-info / SOURCES.txt 'Manifestdatei schreiben' pathology.egg-info / SOURCES.txt 'Pathologie.egg-info nach bui kopieren ld / bdist.macosx-10.7-x86_64 / wheel / pathology-0.1-py3.6.egg-info ausgeführt werden install_scripts zum Erstellen von build / bdist.macosx-10.7-x86_64 / wheel / pathology-0.1.dist-info / WHEEL

Das Pathologiepaket enthält nur reine Python-Module, sodass ein universelles Paket erstellt werden kann. Wenn Ihr Paket C-Erweiterungen enthält, müssen Sie für jede Plattform ein eigenes Rad erstellen:

$ ls -la dist insgesamt 16 drwxr-xr-x 4 gigi.sayfan gigi.sayfan 136 Apr 18 21:24. drwxr-xr-x 13 gigi.sayfan gigi.sayfan 442 18. April 21: 24… -rw-r - r-- 1 gigi.sayfan gigi.sayfan 2695 18. April 21:24 pathology-0.1-py3-none-any .whl -rw-r - r-- 1 gigi.sayfan gigi.sayfan 1223 18. April 21:20 pathology-0.1.tar.gz 

Weitere Informationen zum Packen von Python-Bibliotheken finden Sie unter So schreiben Sie Ihre eigenen Python-Pakete.

So verteilen Sie ein Python-Paket

Python verfügt über ein zentrales Paket-Repository namens PyPI (Python Packages Index). Wenn Sie ein Python-Paket mit pip installieren, wird das Paket von PyPI heruntergeladen (sofern Sie kein anderes Repository angeben). Um unser Pathologie-Paket zu verteilen, müssen wir es in PyPI hochladen und zusätzliche Metadaten bereitstellen, die für PyPI erforderlich sind. Die Schritte sind:

  • Erstellen Sie ein Konto auf PyPI (nur einmal).
  • Registrieren Sie Ihr Paket.
  • Laden Sie Ihr Paket hoch.

Ein Konto erstellen

Sie können auf der PyPI-Website ein Konto erstellen. Dann erstellen Sie eine .Pypirc Datei in Ihrem Heimatverzeichnis:

[distutils] index-servers = pypi [pypi] -Repository = https://pypi.python.org/pypi username = the_gigi 

Zu Testzwecken können Sie Ihrem Index einen "pypitest" -Indexserver hinzufügen .Pypirc Datei:

[distutils] index-servers = pypi pypitest [pypitest] repository = https://testpypi.python.org/pypi username = the_gigi [pypi] repository = https://pypi.python.org/pypi username = the_gigi

Registrieren Sie Ihr Paket

Wenn dies die erste Version Ihres Pakets ist, müssen Sie es bei PyPI registrieren. Verwenden Sie den Registerbefehl von setup.py. Sie werden nach Ihrem Passwort gefragt. Beachten Sie, dass ich es hier auf das Test-Repository verweise:

$ python setup.py register -r pypitest running register running egg_info schreibt pathology.egg-info / PKG-INFO schreibt Abhängigkeitslinks zu pathology.egg-info / dependency_links.txt und schreibt Top-Level-Namen in pathology.egg-info / top_level.txt Lesen der Manifestdatei 'pathology.egg-info / SOURCES.txt' Schreiben der Manifestdatei 'pathology.egg-info / SOURCES.txt' beim Ausführen des Kennworts Kennwort: Registrierung der Pathologie unter https://testpypi.python.org/pypi Server Response (200 ): OK

Laden Sie Ihr Paket hoch

Jetzt, da das Paket registriert ist, können wir es hochladen. Ich empfehle die Verwendung von Bindfäden, was sicherer ist. Installieren Sie es wie gewohnt mit pip einbauen. Laden Sie dann Ihr Paket mit twine hoch und geben Sie Ihr Passwort ein (unten geändert):

$ twine upload -r pypitest -p  dist / * Hochladen von Distributionen auf https://testpypi.python.org/pypi Hochladen der Pathologie-0.1-py3-none-any.whl [======================= ============] 5679/5679 - 00:00:02 Pathology-0.1.tar.gz hochladen [======================================= =============] 4185/4185 - 00:00:01 

Weitere Informationen zum Verteilen von Paketen finden Sie unter So geben Sie Ihre Python-Pakete frei.

Fazit

In diesem Lernprogramm haben wir den vollständigen Prozess des Schreibens einer Python-Bibliothek durchlaufen, verpacken und über PyPI verteilen. An diesem Punkt sollten Sie über alle Tools verfügen, um Ihre Bibliotheken mit der ganzen Welt zu schreiben und zu teilen.

Zögern Sie nicht, zu sehen, was wir für den Verkauf und das Lernen auf dem Markt zur Verfügung haben, und stellen Sie Ihre Fragen und stellen Sie Ihr wertvolles Feedback mithilfe des untenstehenden Feeds.