Python Projektmanager UV

uv ist ein Projektmanagement Tool, dass einzelne Kommandos wie virtualenv und pip in einem gemeinsamen Interface vereint. Laut der eigenen Website ist uv schneller als die anderen Tools.

uv - Symbolbild
raspithek.de - Olli Graf
uv-logoCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
uv – Symbolbild

Installation

Da uv leider (noch) nicht im Repository von Raspberry Pi OS verfügbar ist, laden wir uns das Installationsskript vom Server herunter und führen es aus.

curl -LsSf https://astral.sh/uv/install.sh | sh

Projekt initialisieren

Um ein Projektverzeichnis zu initialisieren reicht

uv init rest_chat_server

Das Verzeichnis wird dabei automatisch erzeugt.

cd rest_chat_server

Standarddateien

Beim init legt uv mehrere Dateien an.

  • hello.py – ein Testprogramm zum schnellen Start.
  • pyproject.toml – hier steht die Projektkonfiguration
  • README.md – eine textuelle Beschreibung des Projekts.
Standarddateien, die durch uv angelegt wurden.
raspithek.de - Olli Graf
filesCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Standarddateien, die durch uv angelegt wurden.

Wir können hello.py einfach mal mit

uv run hello.py

starten.

Die Ausgabe von hello.py
raspithek.de - Olli Graf
uv-run-helloCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Die Ausgabe von hello.py

Du bemerkst sicher, dass uv automatisch eine virtuelle Umgebung für das Projekt unter .venv angelegt hat. Die Datei hello.py kannst du später auch getrost wieder löschen.

In der pyproject.toml steht folgendes drin.

[project]
name = "rest-chat-server"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.9"
dependencies = []

Hier finden sich die benötigte Python Version, sowie Name und Version des Projekts mit einer Kurzbeschreibung. Die letzten Werte kannst du beliebig anpassen. Ich ändere sie wie folgt:

[project]
name = "rest-chat-server"
version = "0.0.1"
description = "Chat Server mit REST"
readme = "README.md"
requires-python = ">=3.9"
dependencies = []

Modul installieren

Wir wollen in diesem Post einen Chat Server bauen, der über REST arbeitet. Dazu benutzen wir das falcon API. Dies können wir ganz einfach in unserer virtuellen Umgebung installieren.

uv add falcon

Die benötigten Module werden dann direkt in unserer Umgebung installiert. Wenn du jetzt noch mal in die pyproject.toml hinein schaust, wirst du feststellen, dass falcon jetzt unter dependencies aufgelistet wird.

Installation von falcon
raspithek.de - Olli Graf
uv-add-falconCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Installation von falcon

Der Chat Server

Unser Chat Server kommuniziert über die REST Schnittstelle und soll über POST neue Nachrichten entgegennehmen, die der Client über GET abrufen kann.

Dazu implementieren wir in einer Klasse ChatServer die Methoden on_get() und on_post(). Diese werden uns vom falcon API vorgegeben und später angesprungen.

import falcon, json
import logging
from logging import config
from datetime import datetime


class Message:

    def __init__(self,user, text):

        self.user = user
        self.text = text
        self.created = datetime.now()


    def __str__(self):
      return self.text

class ChatServer(object):

    def __init__(self):
        self.msglist = {}

        initmsg = Message('system','Chat Server bereit')
        
        self.addMsg(initmsg)

    def addMsg(self,msg):
      created = datetime.now()
      self.msglist[created.strftime('%d.%m.%y %H:%M.%f')] = msg

    def on_get(self,req,resp):
        logging.debug('on_get()')

        logging.debug(f'msglist= {self.msglist}')
        json_msgs = {}

        for key in self.msglist:
            text = self.msglist[key].text
            json_msgs[key] = {
                    'key': key,
                    'user': self.msglist[key].user,
                    'text': text
            }

        resp.status = falcon.HTTP_OK
        resp.media = json_msgs

    def on_post(self,req,resp):
        logging.debug('on_post()')
        
        json_string = req.media
        
        logging.debug(f'json_string={json_string}')

        msg = Message(json_string['user'],json_string['text'])
        self.addMsg(msg)


        resp.status = falcon.HTTP_OK

    def on_delete(self,req,resp):
        logging.debug('on_delete()')


def create_chat_resource():
  chat_endpoint = ChatServer()

  logging.debug(f'endpoint={chat_endpoint}')

  return chat_endpoint


application = falcon.App()

with open('log_config.json') as file_config:
  config.dictConfig(json.load(file_config))

resource = create_chat_resource()
application.add_route('/msg', resource)
logging.debug('Chat REST Service bereit')

Die Klasse verwaltet ein Dictionary mit den gesendeten Nachrichten. Der Zeitstempel dient dabei als Key.

Wir müssen mit falcon.App() die Applikation von falcon initialisieren und dieser durch application.add_route('/msg', resource) den Endpoint zuweisen, unter der die Anwendung angesprochen wird. Die resource ist dabei unsere ChatServer Klasse.

Chat Server starten

uv kann auch deine Anwendung innerhalb der virtuellen Umgebung starten. Versuch es mal mit uv run chat_server

Mit uv run chat_server läuft unser Programm einfach nur bis zum Ende durch.
raspithek.de - Olli Graf
uv-run-chat-serverCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Mit uv run chat_server läuft unser Programm einfach nur bis zum Ende durch.

Aber was ist jetzt passiert? Unser Programm läuft einfach durch und beendet sich einfach wieder. Ein Server muss dauerhaft laufen, um Requests entgegenzunehmen und zu verarbeiten. Wir haben hier nur das Grundgerüst gebaut, kein Servermodul.

gunicorn

Dazu gibt es eine relativ einfache Lösung. gunicorn ist ein WSGI kompatibler Webserver, denn du mit uv add gunicorn zum Projekt dazu fügen kannst.

gunicorn zur virtuellen Umgebung dazu fügen.
raspithek.de - Olli Graf
uv-add-gunicornCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
gunicorn zur virtuellen Umgebung dazu fügen.

Jetzt starten wir unseren chat_server innerhalb von gunicorn. uv run gunicorn chat_server

Innerhalb von gunicorn wartet unser chat_server auf Anfragen.
raspithek.de - Olli Graf
gunicorn-run-chat-serverCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Innerhalb von gunicorn wartet unser chat_server auf Anfragen.

Vielleicht fällt dir spätestens jetzt auf, dass im Projektverzeichnis eine Datei uv.lock angelegt wurde.

Diese Datei ist vor allem in Projektteams wichtig, da sie das konkrete Projekt-Setup beschreibt, mit dem dieses Projekt gebaut werden kann.

Schauen wir mal kurz in uv.lock hinein.

version = 1
requires-python = ">=3.9"

[[package]]
name = "falcon"
version = "4.0.2"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/37/4f/d317952294dee1982cd930c8ee2b8b7fbf04140473882801061b3346c713/falcon-4.0.2.tar.gz", hash = "sha256:58f4b9c9da4c9b1e2c9f396ad7ef897701b3c7c7c87227f0bd1aee40c7fbc525", size = 630121 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/b0/75/e33013aedec976d13f2104ab2e054b5e3863b518c9b28239d2837b521d7f/falcon-4.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8eab0212e77017385d48be2dfe9f5b32305fc9e4066cd298e4bb39e666e114c8", size = 2315204 },
    { url = "https://files.pythonhosted.org/packages/90/5f/4a3ccb6d8bdb4cfcc38aea9cd5e5c49aea400305f581c839be206c3a93e2/falcon-4.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:942129dd3bfb56342ac368f05ff4f9be53e98883b4227089fce2fd616ebc6ef3", size = 2194755 },
    { url = "https://files.pythonhosted.org/packages/28/99/447d6f8618b3f8b882c7e74eafabb59f6e9112acbc3255dddd353fc75505/falcon-4.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60e7b6e5ee44bb2411a7f47bb64e0b225f11cca6ddf91e5130d456242095f0d7", size = 10390701 },
    { url = "https://files.pythonhosted.org/packages/cb/27/a93dc68be1e70809cfa6d227424790ff502cc1f4272200bb91ebe92fafb1/falcon-4.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:330f1623e579575a9e3d90c2a15aebe100b2afa1e18a4bee2ddaa9a570e97902", size = 10986193 },
    { url = "https://files.pythonhosted.org/packages/cb/22/aae29170b0947a5170844bf74b671b5e0e6dc218e2cc6262d2378ec44d15/falcon-4.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d7cfac5cfca69373d1f65211d75767ed4f2d53b46554307427ec00a6f7f87c1", size = 10511133 },
    { url = "https://files.pythonhosted.org/packages/2f/73/0862e66b5b9c5295f065ee7c83571fd106dd84d63cf0479038986ddf2881/falcon-4.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:da3d942dd34f7a5213987bd053c3b52b6eb75fcfd342dc4fea9241f79a6529b3", size = 10201951 },
    { url = "https://files.pythonhosted.org/packages/78/4f/044454ad96a542f2c446a07b6ebc8da0bef8e7e689e32aeb2bf40594a712/falcon-4.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5169e064bbe5dece52e088e3e8b17cae429f1e04c7aef8c31ae350303b19c620", size = 10633849 },
    { url = "https://files.pythonhosted.org/packages/2f/73/bd689c2790c42b6287df1a43928ae3af6cd2541ac1d64d6fa2fc960dad5b/falcon-4.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:0d62e565b9e71b52b59e03130b2b71345a6873f5299aad6a141caf4a58661b41", size = 2115914 },
    { url = "https://files.pythonhosted.org/packages/01/e3/dfeff966d60f2308f765736044e0a62f046d2420baf50fa4872b06338fd5/falcon-4.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cb6ee1aee9ff6a656762cf5fcd2e6c5dced410ca990016be2bc193e6b74ae9da", size = 2321291 },
    { url = "https://files.pythonhosted.org/packages/73/02/8a1a68ddf9b6f9d4a7d0d63f0a485109318f08c0181a3d9f4b05dceab355/falcon-4.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f1a16d8bdc8ef9cf2832a6ca6d43b156b613fb1587cd08cc928c7b8a118ea0a", size = 2196225 },
    { url = "https://files.pythonhosted.org/packages/9f/64/6fa45987bd0fc78d991be5ea0e30f0812eb26713c2e99ce07e35c959346b/falcon-4.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aee81fc4702eef5bccb640b93187fdf36ca2606fca511982069dbc60be2d1c93", size = 11603829 },
    { url = "https://files.pythonhosted.org/packages/84/ef/bc1d47ee32e2a211cffca346bd935009d2b37189c2119df95c31a9af6231/falcon-4.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c1dbcec63d9118c3dfac1f810305128c4fffe26f4f99a7b4e379dec95fc3bfc", size = 12146705 },
    { url = "https://files.pythonhosted.org/packages/e9/cd/ef07fd256c2a29d3c3f1cc22e0ce59724450eb13ef5ca553e63b6abd19f7/falcon-4.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2892ab1232d3a7cc9890b1b539c471fe04c54f826704f9d05efe5632f18efa1", size = 11693278 },
    { url = "https://files.pythonhosted.org/packages/7e/2b/e03066e7be01f1b09c87ecd9c48e14a0ddafd9fc8fddd05db27b5ad4e3d9/falcon-4.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:af68482b408bde53a77b36e45317767dfc5b6fce1525f5b25d65f57f35d33fca", size = 11379786 },
    { url = "https://files.pythonhosted.org/packages/2d/15/f218b581df1447f743b16812c84ab8f6f7d51fb3c1950129744f6fd653bc/falcon-4.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:53d84de83abe1a2094b319a4f018ab6c5773d9c2c841b528662aa151ab9df35c", size = 11770361 },
    { url = "https://files.pythonhosted.org/packages/11/3e/855c3051cb8aad61a921959e5e62416d759761241c1da8394103c3d1d6af/falcon-4.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:1d06bbbccdb58522b2a6bb2e79074844b0db0da1fff407725858a02515e15bbd", size = 2124712 },
    { url = "https://files.pythonhosted.org/packages/67/db/0b78b7ee3fe7e370ed430b7deabfa524b57a5b9eb32622ce1f1bb7aacf0d/falcon-4.0.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:23b0419a9a025745734022aaa2e65447595e539ba27352b3f59d86b288f614db", size = 2294078 },
    { url = "https://files.pythonhosted.org/packages/63/01/77b5b0214bc4ca717b6c6cbe8c3adaba653a7312c9c51a9b390f66efbce0/falcon-4.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:524d7b75f7368fe82e94ed16370db5a27bb4b2d066470cba53f02304264447e8", size = 2186007 },
    { url = "https://files.pythonhosted.org/packages/1d/0c/44abd34e38b88f15c5a7030f48ec079669218af3162de2bd1925e13a46a5/falcon-4.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c6b1d7451d5dee4be9b67a75e2a4a0b024dccffedd4e7c7a09513733b5a11db", size = 11644341 },
    { url = "https://files.pythonhosted.org/packages/5e/f3/0260f70dd080d23372e2ff0e330ca37897ab5e1b4890df281558bda8e34a/falcon-4.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:59bb4a29626c5e610c62620a1395755e8c7b5509385b80d3637fbc8a604d29a3", size = 12218712 },
    { url = "https://files.pythonhosted.org/packages/8d/f8/704b73fc76cf283504aaacc2f466a08fd5d440cddd8d50b6d5c288f0293b/falcon-4.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26c9ed2912ee48e2e1e7eca3e7e85ab664ff07bd321097a26e4ad6168059424", size = 11842131 },
    { url = "https://files.pythonhosted.org/packages/f2/9a/53f9ee7ee8758972d92bb3dfb2225a9c382fbd12f684616cab9126420602/falcon-4.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0a12bbf3482b7ef1db0c6727c2ad8be5c3ac777d892e56a170e0b4b93651c915", size = 11346087 },
    { url = "https://files.pythonhosted.org/packages/af/ac/8098957dd5b97ed16788104b7acb33c64689f7ab04e0c6b07d6561182950/falcon-4.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a601de7816138f17bf168262e0bceb128fdd1ea2f29ddae035585b5da9223a21", size = 11992383 },
    { url = "https://files.pythonhosted.org/packages/7a/23/f8a74294b5b0cb5b9e3eb44ccea310a5d480ef95e938704827db0dd97f99/falcon-4.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:eec3feda4a9cd773203401e3cf425728a13bf5055b22243b1452e9ad963634f5", size = 2077409 },
    { url = "https://files.pythonhosted.org/packages/1f/34/71ef64406ac7f83c5726a37c9fcae0578bc9d650de09c32148aa6c58502f/falcon-4.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:110b172afe337fbae802f1402c89a5dfe6392f3b8ce4f2ecdfd5cee48f68b805", size = 2257265 },
    { url = "https://files.pythonhosted.org/packages/b7/13/528d074e8a75a9236c9f060685e4cb813fbca774269afc89d31e821d8560/falcon-4.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b3a5db14cf2ef05f8f9630468c03939b86dc16115a5250a1870dac3dca1e04ba", size = 2151133 },
    { url = "https://files.pythonhosted.org/packages/2f/70/8c7bf8bf941238a87debce72fcdc7b2301d6599271a392c8216ea2f5d91e/falcon-4.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e0b4d41ce29c2b5c5b18021320e9e0977ba47ade46b67face52ee1325e2ea4", size = 11438997 },
    { url = "https://files.pythonhosted.org/packages/fa/43/71e358d36ec4559737d63312d746fb5f8b0e64f1fe273cd6991e567a9225/falcon-4.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:56af3b8838da2e19ae56b4e1bac168669ba257d6941f94933dc4f814fe721c08", size = 12015197 },
    { url = "https://files.pythonhosted.org/packages/7a/70/c10acaa3486748f77d9b0e79aaa19d3023b760bb9b93389ac1883a52e366/falcon-4.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec939d26dd77f57f08f3e13fb14b4e609c0baf073dc3f0c368f0e4cc10439528", size = 11653687 },
    { url = "https://files.pythonhosted.org/packages/b7/3b/dfdd9bd9f6114a49a55298b12048f1b65d0813b82c28676b956c4444f707/falcon-4.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9bfd751dd898505e17152d7ecfcdc457c9d85bceed7e651a9915183bd4afc86b", size = 11165291 },
    { url = "https://files.pythonhosted.org/packages/01/61/eb3d1d2076df85d5a7c2cd823ba5dbe0a928053a3102effb9006b2851377/falcon-4.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b85f9c6f50a7465303290cb305404ea5c1ddeff6702179c1a8879c4693b0e5e", size = 11831049 },
    { url = "https://files.pythonhosted.org/packages/bf/c7/268cddb1f84ebe5b402acdf116083658f3fb0dd38a75571e0ee703cef212/falcon-4.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:a410e4023999a74ccf615fafa646b112044b987ef5901c8e5c5b79b163f2b3ba", size = 2052994 },
    { url = "https://files.pythonhosted.org/packages/d0/00/7be6347247812e6553be50d83b0951e569d597b9c3a71e4c0de5b00789b7/falcon-4.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f9709fd9181f58d492463b951cc42fb33b230e8f261128bc8252a37a4553f318", size = 2323679 },
    { url = "https://files.pythonhosted.org/packages/c4/71/65266fc8433e396f42a2b045e7b7069390c4314e8b66e66c4e092166226f/falcon-4.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:427c20ceb367039b856506d7baeef17c7f0c40b8fcbf1147c0e76f33a574a7cf", size = 2203699 },
    { url = "https://files.pythonhosted.org/packages/80/30/82ff9d61d6baa5f908ccbbb775585cd1ac24dd47fcc2d2e6c5b9b0f44ce4/falcon-4.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fb50cebc3cae6720ccf4a05fccb233ea6a88e803828a07c063d6dce10a74e0e", size = 10418688 },
    { url = "https://files.pythonhosted.org/packages/bf/e5/660262ee87a90aab812d2d10ab42e6e0bffe853890b2e14268863c4dd659/falcon-4.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:628c450e14af811f13db6334265d7ff8a7b8a25ece1bde35d09a367a72046533", size = 11033845 },
    { url = "https://files.pythonhosted.org/packages/8f/b2/cf4c9567ad571e3304743e6f65c42576929cc16d494cb234f972fa70a150/falcon-4.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e04b30a7f89e5413e00c5cd1ea62bf7948323eb0220f8a5bbf705abae266a384", size = 10547880 },
    { url = "https://files.pythonhosted.org/packages/e2/b8/503d3574be76a09b64dd48214e012fd1b911a158400bc04b1ee0d4caec0f/falcon-4.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:9095a36b8eeb80207322393b3bc88edaacd0426c2907e8427617618421bde9cc", size = 10218888 },
    { url = "https://files.pythonhosted.org/packages/2c/88/d96a3e9d93aee74280a82be844c2eaa603283c5548b3293165deb2d55b4e/falcon-4.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0adc6c2887f9d7ed55fe38edef055cc85c26762e392d80dca8765184c180b921", size = 10663138 },
    { url = "https://files.pythonhosted.org/packages/38/97/4021fce87e3feb67839405ca8d2560d989da141692214c6f1b297af23443/falcon-4.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:7bffb4cadcbf7c5994695d421ef5305ad8315cfbefe971713046967614f0ffa4", size = 2121203 },
    { url = "https://files.pythonhosted.org/packages/20/e2/ef821224a9ca9d4bb81d6e7ba60c6fbf3eae2e0dc10d806e6ff21b6dfdc5/falcon-4.0.2-py3-none-any.whl", hash = "sha256:077b2abf001940c6128c9b5872ae8147fe13f6ca333f928d8045d7601a5e847e", size = 318356 },
]

[[package]]
name = "gunicorn"
version = "23.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
    { name = "packaging" },
]
sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 },
]

[[package]]
name = "packaging"
version = "25.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 }
wheels = [
    { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 },
]

[[package]]
name = "rest-chat-server"
version = "0.0.1"
source = { virtual = "." }
dependencies = [
    { name = "falcon" },
    { name = "gunicorn" },
]

[package.metadata]
requires-dist = [
    { name = "falcon", specifier = ">=4.0.2" },
    { name = "gunicorn", specifier = ">=23.0.0" },
]

Hier sind nicht nur die Versionen der benötigten Module eingetragen sondern auch die URLs, von denen diese bezogen werden können.

chat_server testen

Mit dem obigen Kommando lauscht gunicorn nur auf dem lokalen Raspi, zum Test beende ich ihn mit CTRL-C und starte ihn neu mit

uv run gunicorn --bind 0.0.0.0:8000 chat_server

Der –bind Parameter teilt gunicorn mit, im gesamten LAN auf eingehenden Verbindungen zu warten.

Ich logge mich zum Test nacheinander auf verschiedenen meiner Raspberry Pis ein und sende über curl eine Nachricht an den Chat-Server

curl -X POST http://quimby:8000/msg -H "Content-Type: application/json" -d '{"user": "database", "text": "Hallo von database"}'

Dabei passe ich den Usernamen an den jeweiligen Hostnamen an.

Wenn ich die Nachrichtenliste dann abrufe, sehe ich dieses:

Alle Nachrichten der verschiedenen Raspis sind in der Nachrichtenliste abrufbar.
raspithek.de - Olli Graf
multiple-testCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Alle Nachrichten der verschiedenen Raspis sind in der Nachrichtenliste abrufbar.

Projekt übertragen

Um zu zeigen, wie einfach das Projekt für andere jetzt einzurichten ist, clone ich mit git das Repository unter einem Zweitaccount und installiere auch für diesen User uv, wie oben angegeben. Dann richte ich mir mit diesen Kommandos die Arbeitsumgebung ein und starte den Chat-Server.

uv venv .venv
source .venv/bin/activate
uv pip install -e .
uv run gunicorn chat_server
Einrichtung und Start des Projekts für einen anderen User.
raspithek.de - Olli Graf
uv-transferCreative Commons Attribution-NonCommercial-ShareAlike 4.0 International License . loading=
Einrichtung und Start des Projekts für einen anderen User.

Das ganze dauert keine drei Minuten.

Fazit

uv vereinfacht die Projektverwaltung enorm. Das Kommando hat alles unter der Haube, für das wir sonst mehrere Programme benötigt haben. Er ist tatsächlich sehr viel schneller und komfortabler bei der Modulinstallation und mir macht es Spaß damit zu arbeiten. Wünschenswert wäre, dass uv in das Debian Repository aufgenommen wird statt es für jeden User einzeln installieren zu müssen.

Schreibe einen Kommentar

Insert math as
Block
Inline
Additional settings
Formula color
Text color
#333333
Type math using LaTeX
Preview
\({}\)
Nothing to preview
Insert
Creative Commons License
Except where otherwise noted, the content on this site is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Olli Graf - raspithek.de
WordPress Cookie Hinweis von Real Cookie Banner