So binden Sie zusätzliche Dateien in ein Python-Paket ein

PythonPythonBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

Python-Pakete sind eine leistungsstarke Möglichkeit, Code zu organisieren und zu verteilen. Während Python-Skripte (.py-Dateien) den Kern eines Pakets bilden, müssen Sie oft zusätzliche Dateien wie Konfigurationsdateien, Datendateien, Vorlagen oder Dokumentationen einbeziehen. Dieses Tutorial führt Sie durch den Prozess der Erstellung eines Python-Pakets, das diese zusätzlichen Ressourcen enthält, wodurch Ihr Paket vielseitiger und nützlicher wird.

Am Ende dieses Labors haben Sie ein vollständiges Python-Paket mit zusätzlichen Dateien erstellt und gelernt, wie Sie von Ihrem Code aus auf diese Dateien zugreifen können.

Erstellen einer grundlegenden Python-Paketstruktur

Beginnen wir mit der Erstellung einer grundlegenden Python-Paketstruktur. Ein Paket ist im Wesentlichen ein Verzeichnis, das Python-Module und eine spezielle __init__.py-Datei enthält, die Python mitteilt, dass dieses Verzeichnis als Paket behandelt werden soll.

Erstellen der Paketverzeichnisstruktur

Zuerst erstellen wir die notwendigen Verzeichnisse für unser Paket:

mkdir -p ~/project/mypackage/data

Dieser Befehl erstellt ein Verzeichnis namens mypackage mit einem Unterverzeichnis data, um unsere zusätzlichen Dateien zu speichern.

Navigieren wir nun zu unserem Projektverzeichnis:

cd ~/project

Erstellen der grundlegenden Paketdateien

Jedes Python-Paket benötigt eine __init__.py-Datei in seinem Stammverzeichnis. Erstellen wir diese Datei:

touch mypackage/__init__.py

Diese leere Datei teilt Python mit, dass das Verzeichnis mypackage ein Paket ist.

Als Nächstes erstellen wir ein einfaches Python-Modul innerhalb unseres Pakets:

echo 'def greet():
    print("Hello from mypackage!")' > mypackage/greeting.py

Hinzufügen einer Datendatei zum Paket

Fügen wir nun eine Datendatei zu unserem Paket hinzu. Dies kann eine Konfigurationsdatei, eine CSV-Datei oder jede andere Art von Datei sein, die Ihr Paket benötigt:

echo 'This is sample data for our package.' > mypackage/data/sample.txt

Erstellen wir auch eine Konfigurationsdatei:

echo '[config]
debug = true
log_level = INFO' > mypackage/config.ini

Überprüfen Ihrer Paketstruktur

Sie können die Struktur Ihres Pakets mit dem folgenden Befehl überprüfen:

find mypackage -type f | sort

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

mypackage/__init__.py
mypackage/config.ini
mypackage/data/sample.txt
mypackage/greeting.py

Dies ist eine grundlegende Python-Paketstruktur mit einigen zusätzlichen Nicht-Python-Dateien. In den nächsten Schritten erfahren wir, wie man diese Dateien beim Verteilen des Pakets einbezieht und wie man von Ihrem Code aus auf sie zugreift.

Erstellen eines Setup-Skripts für Ihr Paket

Um zusätzliche Dateien ordnungsgemäß in Ihr Python-Paket aufzunehmen, müssen Sie eine setup.py-Datei erstellen. Diese Datei wird von den Python-Paketierungswerkzeugen verwendet, um Ihr Paket zu erstellen und zu installieren.

Verstehen von setup.py

Die Datei setup.py enthält Metadaten über Ihr Paket, wie z. B. seinen Namen, seine Version, den Autor und die Abhängigkeiten. Sie gibt auch an, welche Dateien beim Verteilen des Pakets enthalten sein sollen.

Erstellen wir eine grundlegende setup.py-Datei im Stammverzeichnis Ihres Projekts:

cd ~/project

Erstellen Sie nun die Datei setup.py mit dem folgenden Inhalt:

cat > setup.py << 'EOF'
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="0.1",
    packages=find_packages(),
    
    ## Include data files
    package_data={
        "mypackage": ["config.ini", "data/*.txt"],
    },
    
    ## Metadata
    author="Your Name",
    author_email="[email protected]",
    description="A simple Python package with additional files",
)
EOF

Verstehen der Package-Data-Konfiguration

Der Parameter package_data ist der Schlüssel zum Einbeziehen zusätzlicher Dateien in Ihr Paket. Er nimmt ein Dictionary entgegen, wobei:

  • Schlüssel Paketnamen sind (oder "" für alle Pakete)
  • Werte Listen von Dateimustern relativ zum Paketverzeichnis sind

In unserem Beispiel fügen wir Folgendes ein:

  • Die Datei config.ini im Stammverzeichnis unseres Pakets
  • Alle .txt-Dateien im Verzeichnis data

Die Dateimuster unterstützen Wildcards wie *, um mehrere Dateien mit ähnlichen Namen oder Erweiterungen abzugleichen.

Testen Ihrer Setup-Konfiguration

Erstellen wir eine virtuelle Umgebung, um unser Paket zu testen:

python3 -m venv ~/project/venv
source ~/project/venv/bin/activate

Installieren wir nun unser Paket im Entwicklungsmodus:

cd ~/project
pip install -e .

Das Flag -e steht für "editable"-Modus, was bedeutet, dass Sie Ihren Paketcode bearbeiten können, ohne ihn jedes Mal neu installieren zu müssen.

Sie sollten eine Ausgabe sehen, die anzeigt, dass Ihr Paket erfolgreich installiert wurde:

Successfully installed mypackage-0.1

Überprüfen wir die Installation unseres Pakets:

python -c "import mypackage.greeting; mypackage.greeting.greet()"

Dies sollte Folgendes ausgeben:

Hello from mypackage!

Sie haben jetzt erfolgreich ein Python-Paket mit einem Setup-Skript erstellt, das zusätzliche Dateien enthält. Im nächsten Schritt erfahren wir, wie Sie von Ihrem Python-Code aus auf diese Dateien zugreifen können.

Zugriff auf zusätzliche Dateien in Ihrem Paket

Nachdem wir zusätzliche Dateien in unser Paket aufgenommen haben, müssen wir lernen, wie wir von unserem Python-Code aus auf sie zugreifen können. Es gibt verschiedene Möglichkeiten, dies zu tun, aber die zuverlässigste Methode ist die Verwendung des Moduls pkg_resources aus dem Paket setuptools.

Erstellen eines Moduls für den Zugriff auf zusätzliche Dateien

Erstellen wir ein neues Modul in unserem Paket, das zeigt, wie man auf die zusätzlichen Dateien zugreift:

cd ~/project

Erstellen Sie eine neue Datei namens fileaccess.py im Verzeichnis mypackage:

cat > mypackage/fileaccess.py << 'EOF'
import os
import pkg_resources

def get_config_path():
    """Return the path to the config.ini file."""
    return pkg_resources.resource_filename('mypackage', 'config.ini')

def read_config():
    """Read and return the content of the config.ini file."""
    config_path = get_config_path()
    with open(config_path, 'r') as f:
        return f.read()

def get_sample_data_path():
    """Return the path to the sample.txt file."""
    return pkg_resources.resource_filename('mypackage', 'data/sample.txt')

def read_sample_data():
    """Read and return the content of the sample.txt file."""
    data_path = get_sample_data_path()
    with open(data_path, 'r') as f:
        return f.read()

def list_package_data():
    """List all files included in the package data."""
    ## Get the package directory
    package_dir = os.path.dirname(pkg_resources.resource_filename('mypackage', '__init__.py'))
    
    ## List files in the main package directory
    main_files = [f for f in os.listdir(package_dir) 
                  if os.path.isfile(os.path.join(package_dir, f))]
    
    ## List files in the data directory
    data_dir = os.path.join(package_dir, 'data')
    data_files = [f'data/{f}' for f in os.listdir(data_dir) 
                 if os.path.isfile(os.path.join(data_dir, f))]
    
    return main_files + data_files
EOF

Aktualisieren der __init__.py-Datei

Aktualisieren wir die Datei __init__.py, um unsere neuen Funktionen verfügbar zu machen:

cat > mypackage/__init__.py << 'EOF'
from mypackage.greeting import greet
from mypackage.fileaccess import (
    get_config_path,
    read_config,
    get_sample_data_path,
    read_sample_data,
    list_package_data
)

__all__ = [
    'greet',
    'get_config_path',
    'read_config',
    'get_sample_data_path',
    'read_sample_data',
    'list_package_data'
]
EOF

Testen der Datei-Zugriffsfunktionen

Erstellen wir ein Skript, um unsere Datei-Zugriffsfunktionen zu testen:

cat > ~/project/test_package.py << 'EOF'
import mypackage

## Test greeting function
print("Testing greeting function:")
mypackage.greet()
print()

## Test config file access
print("Config file path:")
print(mypackage.get_config_path())
print("\nConfig file content:")
print(mypackage.read_config())
print()

## Test data file access
print("Sample data file path:")
print(mypackage.get_sample_data_path())
print("\nSample data file content:")
print(mypackage.read_sample_data())
print()

## List all package data
print("All package data files:")
for file in mypackage.list_package_data():
    print(f"- {file}")
EOF

Führen Sie nun das Testskript aus:

cd ~/project
python test_package.py

Sie sollten eine Ausgabe ähnlich der folgenden sehen:

Testing greeting function:
Hello from mypackage!

Config file path:
/home/labex/project/mypackage/config.ini

Config file content:
[config]
debug = true
log_level = INFO

Sample data file path:
/home/labex/project/mypackage/data/sample.txt

Sample data file content:
This is sample data for our package.

All package data files:
- __init__.py
- config.ini
- fileaccess.py
- greeting.py
- data/sample.txt

Verstehen von pkg_resources

Das Modul pkg_resources bietet eine Möglichkeit, auf Ressourcen innerhalb installierter Pakete zuzugreifen. Die Funktion resource_filename gibt den Pfad zu einer Datei innerhalb eines Pakets zurück, unabhängig davon, wo das Paket installiert ist.

Dieser Ansatz stellt sicher, dass Ihr Code auf zusätzliche Dateien zugreifen kann, egal ob:

  • Aus dem Quellverzeichnis während der Entwicklung ausgeführt
  • In einer virtuellen Umgebung installiert
  • Systemweit installiert
  • Verteilt und auf einem anderen Rechner installiert

Dies macht Ihr Paket portabler und zuverlässiger, da es sich nicht auf fest codierte Pfade oder relative Pfade verlässt, die sich je nach Verwendung des Pakets ändern könnten.

Erstellen und Verteilen Ihres Pakets

Nachdem wir ein Python-Paket mit zusätzlichen Dateien erstellt und bestätigt haben, dass wir auf diese zugreifen können, wollen wir lernen, wie man dieses Paket erstellt und verteilt.

Aktualisieren des Setup-Skripts

Bevor wir das Paket erstellen, aktualisieren wir unsere setup.py-Datei, um weitere Metadaten und Anforderungen aufzunehmen:

cd ~/project
cat > setup.py << 'EOF'
from setuptools import setup, find_packages

setup(
    name="mypackage",
    version="0.1.0",
    packages=find_packages(),
    
    ## Include data files
    package_data={
        "mypackage": ["config.ini", "data/*.txt"],
    },
    
    ## Dependencies
    install_requires=[
        "setuptools",
    ],
    
    ## Metadata
    author="Your Name",
    author_email="[email protected]",
    description="A simple Python package with additional files",
    keywords="sample, package, data",
    url="https://example.com/mypackage",
    classifiers=[
        "Development Status :: 3 - Alpha",
        "Intended Audience :: Developers",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
    ],
    python_requires=">=3.6",
)
EOF

Erstellen von Source- und Wheel-Distributionen

Python-Pakete können in verschiedenen Formaten verteilt werden, aber die gebräuchlichsten sind:

  1. Source Distribution (sdist): Ein Tarball, der den Quellcode und zusätzliche Dateien enthält
  2. Wheel Distribution (bdist_wheel): Ein vorgefertigtes Paket, das ohne Erstellung installiert werden kann

Erstellen wir beide Arten von Distributionen:

## Make sure we have the latest build tools
pip install --upgrade setuptools wheel

## Build the distributions
python setup.py sdist bdist_wheel

Sie sollten eine Ausgabe sehen, die anzeigt, dass die Distributionen erstellt wurden, und neue Dateien sollten im Verzeichnis dist erscheinen.

Überprüfen wir den Inhalt des Verzeichnisses dist:

ls -l dist

Sie sollten mindestens zwei Dateien sehen:

  • Eine .tar.gz-Datei (die Source Distribution)
  • Eine .whl-Datei (die Wheel Distribution)

Installieren des Pakets aus den Distributionsdateien

Testen wir nun die Installation des Pakets aus einer der Distributionsdateien. Zuerst deinstallieren wir unsere Entwicklungsversion:

pip uninstall -y mypackage

Installieren wir nun die Wheel Distribution:

pip install dist/mypackage-0.1.0-py3-none-any.whl

Sie sollten eine Ausgabe sehen, die anzeigt, dass das Paket erfolgreich installiert wurde.

Überprüfen wir, ob das Paket installiert ist und ob wir weiterhin auf die zusätzlichen Dateien zugreifen können:

python -c "import mypackage; print(mypackage.read_config())"

Dies sollte den Inhalt der Datei config.ini ausgeben:

[config]
debug = true
log_level = INFO

Veröffentlichen Ihres Pakets

In einem realen Szenario würden Sie Ihr Paket typischerweise im Python Package Index (PyPI) veröffentlichen, damit andere es mit pip install mypackage installieren können. Dies würde Folgendes beinhalten:

  1. Erstellen eines Kontos auf PyPI (https://pypi.org/)
  2. Verwenden von Tools wie twine, um Ihre Distributionen hochzuladen:
    pip install twine
    twine upload dist/*

Für dieses Lab werden wir jedoch bei der lokalen Erstellung der Distributionen anhalten. Sie haben jetzt ein vollständiges Python-Paket mit zusätzlichen Dateien, das von anderen verteilt und installiert werden kann.

Zusammenfassung dessen, was Sie erstellt haben

  • Ein Python-Paket mit Modulen und zusätzlichen Dateien
  • Ein Setup-Skript, das diese Dateien in die Distribution aufnimmt
  • Funktionen für den Zugriff auf diese Dateien von Ihrem Code aus
  • Source- und Wheel-Distributionsdateien, die für die Verteilung bereit sind

Diese Struktur bietet eine solide Grundlage für jedes Python-Paket, das Sie in Zukunft erstellen möchten.

Zusammenfassung

In diesem Lab haben Sie gelernt, wie man:

  1. Eine grundlegende Python-Paketstruktur mit zusätzlichen Nicht-Python-Dateien erstellt
  2. Ihre setup.py so konfiguriert, dass diese Dateien in der Paketdistribution enthalten sind
  3. Mit dem Modul pkg_resources auf zusätzliche Dateien von Ihrem Python-Code aus zugreift
  4. Source- und Wheel-Distributionen Ihres Pakets zur Verteilung erstellt

Sie verfügen nun über das Wissen, um umfassendere Python-Pakete zu erstellen, die nicht nur Python-Code, sondern auch Konfigurationsdateien, Datendateien, Vorlagen und andere Ressourcen enthalten. Diese Fähigkeit ist für die Entwicklung von realen Anwendungen unerlässlich, bei denen Python-Code oft mit externen Dateien arbeiten muss.

Einige wichtige Erkenntnisse aus diesem Lab:

  • Verwenden Sie den Parameter package_data in setup(), um zusätzliche Dateien einzubeziehen
  • Verwenden Sie pkg_resources.resource_filename(), um zuverlässig auf diese Dateien von Ihrem Code aus zuzugreifen
  • Erstellen Sie sowohl Source- als auch Wheel-Distributionen für maximale Kompatibilität
  • Halten Sie Ihre Paketstruktur organisiert, um die Wartung zu erleichtern

Dieses Wissen wird wertvoll sein, wenn Sie weiterhin komplexere Python-Anwendungen und -Pakete entwickeln.