{ "cells": [ { "cell_type": "markdown", "id": "1fe95632", "metadata": {}, "source": [ "# Ein Python-Modul entwicklen und veröffentlichen\n", "\n", "<br/>\n", "<br/>\n", "\n", "Dieses Notebook finden Sie hier: https://scm.cms.hu-berlin.de/ibi/python/-/blob/master/programmierspass/Develop_and_publish_modul.ipynb\n", "\n", "<br/>\n", "\n", "\n", "\n", "Dieses Notebook ist als freies Werk unter der Lizenz [Creative Commons Attribution-NonCommercial 3.0 Unported](http://creativecommons.org/licenses/by-nc/3.0/) verfügbar. Sie dürfen die Inhalte kopieren, verteilen und verändern, solange Sie die Urheber nennen und sie nicht für kommerzielle Zwecke nutzen." ] }, { "cell_type": "markdown", "id": "c7dc7204", "metadata": {}, "source": [ "## Was ist ein Modul?\n", "\n", "- Ein Modul ist eine Datei, die Python-Definitionen und -Anweisungen beinhaltet. Oder anders gesagt: Jede Python-Datei ist ein Modul und der Name des Moduls ist der Dateiname ohne die Endung `.py`\n", "- Ein Package ist eine Sammlung von Modulen. Hierfür liegen mehrere Module in einem Ordner, welcher auch eine Datei `__init__.py` enthalten muss. Dies unterscheidet ein Package von einem Ordner, der zufällig mehrere Module enthält." ] }, { "cell_type": "markdown", "id": "21e7cd83", "metadata": {}, "source": [ "## Module verwenden\n", "\n", "- Python wird mit einer Bibliothek von Standardmodulen ausgeliefert. Ein solches Modul kann mit dem Befehl `import` importiert und anschließend verwendet weden." ] }, { "cell_type": "code", "execution_count": null, "id": "94cad5e7", "metadata": {}, "outputs": [], "source": [ "import json" ] }, { "cell_type": "markdown", "id": "1129c831", "metadata": {}, "source": [ "- Wenn wir nun versuchen ein Modul zu installieren, welches nicht in den Standardmodulen enthalten ist, dann kommt es zu einer Fehlermeldung." ] }, { "cell_type": "code", "execution_count": null, "id": "3aa3db5d", "metadata": {}, "outputs": [], "source": [ "import pandas" ] }, { "cell_type": "markdown", "id": "bdc84dcf", "metadata": {}, "source": [ "## Module installieren\n", "\n", "- Module, die nicht in der Bibliothek von Standardmodulen enthalten sind, müssen vor dem Import installiert werden. Hierfür wird ein Paketverwaltungsprogramm verwendet. Dies ist im Normfall `pip`. Mit dem Befehl `pip install` können Pakete installiert werden." ] }, { "cell_type": "code", "execution_count": null, "id": "2148e19b", "metadata": {}, "outputs": [], "source": [ "!pip install pandas" ] }, { "cell_type": "markdown", "id": "2dce18c9", "metadata": {}, "source": [ "## Doch was passiert hier eigentlich?" ] }, { "cell_type": "markdown", "id": "f07907eb", "metadata": {}, "source": [ "### Python Package Index (PyPI)\n", "\n", "- `pip`lädt Pakete aus dem Python Package Index (PyPI).\n", "- PyPI ist ein Sofware-Vezeichnis der Programmiersprache Python.\n", "- PyPI umfasst knapp 420.00 Projekte (Stand: Dezember 2022)\n", "- Jede:r kann sich auf PyPI (https://pypi.org) registrieren und ein Projekt erstellen.\n", "\n", "<div class=\"alert alert-info\">\n", "<b>Hinweis</b> Der Begriff \"Package\" kann etwas verwirrend sein. PyPI spricht auch von Packages. Ein PyPI-Package kann ein einzelnes Python-Modul sein oder aber auch mehrere Python-Packages umfassen. \n", "</div>" ] }, { "cell_type": "markdown", "id": "d45b9900", "metadata": {}, "source": [ "### PyPI Testumgebung\n", "\n", "- Für Testzwecke gibt es die PyPI Testumgebgung (https://test.pypi.org)\n", "- Diese funktioniert genau wie die reale Version und sollte verwendet werden um die eigene Konfiguration zu testen. " ] }, { "cell_type": "markdown", "id": "cbf98fba", "metadata": {}, "source": [ "## Mein erstes PyPI (Test)-Package" ] }, { "cell_type": "markdown", "id": "0cbf8602", "metadata": {}, "source": [ "### Beispiel für ein minimales Projekt\n", "\n", "```\n", "pypi-example/\n", "├── LICENSE\n", "├── pyproject.toml\n", "├── README.md\n", "└── pypiex/\n", " ├── __init__.py\n", " └── example.py\n", "```" ] }, { "cell_type": "markdown", "id": "8b3f6ddf", "metadata": {}, "source": [ "### pyproject.toml - Konfiguration von Metadaten\n", "\n", "```toml\n", "[build-system]\n", "requires = [\"setuptools>=61.0\"]\n", "build-backend = \"setuptools.build_meta\"\n", "\n", "[project]\n", "name = \"Pypiex\"\n", "version = \"0.0.1\"\n", "authors = [\n", " { name = \"Frederik Arnold\", email = \"frederik.arnold@hu-berlin.de\" }\n", "]\n", "description = \"Eine kurze Beschreibung für PyPiex\"\n", "readme = \"README.md\"\n", "requires-python = \">=3.7\"\n", "\n", "classifiers = [\n", " \"Programming Language :: Python :: 3\",\n", " \"License :: OSI Approved :: Apache Software License\",\n", " \"Operating System :: OS Independent\",\n", "]\n", "\n", "[project.urls]\n", "\"Homepage\" = \"https://...\"\n", "\"Bug Tracker\" = \"https://...\"\n", "```\n", "\n", "- Weitere Informationen zu den einzelnen Angaben: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/#declaring-project-metadata" ] }, { "cell_type": "markdown", "id": "927e9459", "metadata": {}, "source": [ "### README.md\n", "\n", "```\n", "# Mein Projekt\n", "\n", "Dies ist ein Beispielprojekt.\n", "```" ] }, { "cell_type": "markdown", "id": "4c8acd0d", "metadata": {}, "source": [ "### LICENSE\n", "\n", "```\n", "Apache License\n", " Version 2.0, January 2004\n", " http://www.apache.org/licenses/\n", "\n", " TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n", "\n", " 1. Definitions.\n", "\n", " \"License\" shall mean the terms and conditions for use, reproduction,\n", " and distribution as defined by Sections 1 through 9 of this document.\n", "\n", " \"Licensor\" shall mean the copyright owner or entity authorized by\n", " the copyright owner that is granting the License.\n", "\n", " \"Legal Entity\" shall mean the union of the acting entity and all\n", " other entities that control, are controlled by, or are under common\n", " control with that entity. For the purposes of this definition,\n", " \"control\" means (i) the power, direct or indirect, to cause the\n", " direction or management of such entity, whether by contract or\n", " otherwise, or (ii) ownership of fifty percent (50%) or more of the\n", " outstanding shares, or (iii) beneficial ownership of such entity.\n", " \n", " [...]\n", "\n", "```" ] }, { "cell_type": "markdown", "id": "d4b197a7", "metadata": {}, "source": [ "### Package für den Upload erzeugen\n", "\n", "- Für die Erzeugung der zum Upload benötigten Dateien, muss zuerst in den Projektordner navigiert werden, und dort die folgende Befehle ausgeführt werden." ] }, { "cell_type": "markdown", "id": "68e05d16", "metadata": {}, "source": [ "- Zuerst müssen für den Build benötigten Pakete installiert werden.\n", "\n", "```\n", "pip install --upgrade build\n", "```" ] }, { "cell_type": "markdown", "id": "3cf7b4cd", "metadata": {}, "source": [ "- Dann kann anhand der `pyproject.toml` das Package erstellt werden. Dieses wird in den Ordner `dist` im Projektordner gespeichert.\n", "\n", "```\n", "python -m build\n", "```" ] }, { "cell_type": "markdown", "id": "afd1c91e", "metadata": {}, "source": [ "- Wenn die Befehle korrekt ausgeführt werden konnten, dann sollte die letzte Zeile so lauten:\n", "\n", "```\n", "Successfully built xyz-version.tar.gz and xyz-version-py3-none-any.whl\n", "```\n", "\n", "- Außerdem sollten zwei Dateien im Ordner `dist` erzeugt worden sein. Es gibt verschiedene Arten von Packages.\n", "- Die Datei mit der Endung `.tar.gz` ist eine Source Distribution.\n", "- Die Datei mit der Endung `.whl` (Wheel-Datei) ist eine Built Distribution. Dieses Format ist neuer und hat verschiedene Vorteile. Die Details sind an dieser Stelle nicht relevant. " ] }, { "cell_type": "markdown", "id": "a87cd03e", "metadata": {}, "source": [ "### Package auf den Testserver hochladen\n", "\n", "- Um Pakete hochladen zu können muss zuerst ein Account erstellt werden. \n", "\n", "<div class=\"alert alert-info\">\n", "<b>Hinweis</b> Der PyPI Testserver ist unabhängig von der Produktionsumgebung und es werden jeweils eigene Accounts benötigt.\n", "</div> " ] }, { "cell_type": "markdown", "id": "1444d33a", "metadata": {}, "source": [ "- Jetzt muss ein `API token` generiert werden. Dies geschieht in den Kontoeinstellungen im Bereich `API-Token`. Folgender Link führt automatisch dort hin: https://test.pypi.org/manage/account/#api-tokens. Auf `API-Token hinzufügen` klicken. Dort einen sinnvollen Namen vergeben und den Geltungsbereich auf `Gesamtes Konto` stellen.\n", "\n", "<div class=\"alert alert-info\">\n", "<b>Hinweis</b> Ein erstelltes Token muss direkt gesichert werden, da es danach nicht mehr einsehbar ist.\n", "</div>" ] }, { "cell_type": "markdown", "id": "abf06326", "metadata": {}, "source": [ "- Jetzt die für den Upload benötigten Packages laden und installieren:\n", "\n", "```\n", "pip install --upgrade twine\n", "```" ] }, { "cell_type": "markdown", "id": "325e2694", "metadata": {}, "source": [ "- Und dann den Upload ausführen. Hierbei wird nach dem Username und Passwort gefragt. Für den Username muss `__token__` verwendet werden und für Passwort das gerade erstelle Token inklusive des `pypi` Prefix.\n", "\n", "\n", "```\n", "python -m twine upload --repository testpypi dist/*\n", "```\n", "\n", "<div class=\"alert alert-info\">\n", "<b>Hinweis</b> Soll eine neue Version für ein Paket hochgeladen werden, dann muss vor der Erzeugung des Pakets immer zuerst die Versionsnummer in der `pyproject.toml` angepasst werden. Eine Version kann immer nur ein Mal hochgeladen werden. \n", "</div>" ] }, { "cell_type": "markdown", "id": "a55a2eb7", "metadata": {}, "source": [ "## Package installieren und verwenden\n", "\n", "- Das Paket kann jetzt mit `pip` installiert werden. Hierzu muss der Testserver angegeben werden." ] }, { "cell_type": "code", "execution_count": null, "id": "eab699f8", "metadata": {}, "outputs": [], "source": [ "!pip install --index-url https://test.pypi.org/simple/ --no-deps Pypiex" ] }, { "cell_type": "code", "execution_count": null, "id": "2f369bf9", "metadata": {}, "outputs": [], "source": [ "from pypiex import example\n", "example.say_hello(\"Frederik\")" ] }, { "cell_type": "markdown", "id": "2a17f85c", "metadata": {}, "source": [ "## Literatur\n", "\n", "- https://packaging.python.org/en/latest/tutorials/packaging-projects/\n", "- https://setuptools.pypa.io/en/latest/userguide/index.html" ] }, { "cell_type": "code", "execution_count": null, "id": "ee4663eb", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 5 }