paint-brush
So erstellen Sie ein Python-CLI-Programm für die Trello-Board-Verwaltung (Teil 1)von@elainechan01
2,360 Lesungen
2,360 Lesungen

So erstellen Sie ein Python-CLI-Programm für die Trello-Board-Verwaltung (Teil 1)

von Elaine Yun Ru Chan19m2023/08/15
Read on Terminal Reader
Read this story w/o Javascript

Zu lang; Lesen

Wie es auf Wikipedia heißt: „Eine Befehlszeilenschnittstelle (CLI) ist ein Mittel zur Interaktion mit einem Gerät oder Computerprogramm mit Befehlen von einem Benutzer oder Client und Antworten vom Gerät oder Programm in Form von Textzeilen.“ Mit anderen Worten ist ein CLI-Programm ein Programm, bei dem der Benutzer die Befehlszeile verwendet, um mit dem Programm zu interagieren, indem er Anweisungen zur Ausführung gibt. Viele alltägliche Software ist als CLI-Programm verpackt. Nehmen Sie zum Beispiel den vim-Texteditor – ein Tool, das mit jedem UNIX-System geliefert wird und einfach durch Ausführen von vim <FILE> im Terminal aktiviert werden kann. Lassen Sie uns in Bezug auf die Google Cloud CLI in die Anatomie eines CLI-Programms eintauchen.
featured image - So erstellen Sie ein Python-CLI-Programm für die Trello-Board-Verwaltung (Teil 1)
Elaine Yun Ru Chan HackerNoon profile picture
0-item

Haftungsausschluss: In diesem Tutorial wird davon ausgegangen, dass die Leser über grundlegende Kenntnisse in Python, APIs, Git und Unit Tests verfügen.

Ich bin auf verschiedene CLI-Software mit den coolsten Animationen gestoßen und habe mich gefragt: Könnte ich jemals mein „minimalistisches“ Stein-Schere-Papier-Schulprojekt aktualisieren?


Hallo, lass uns spielen! Wählen Sie Ihren Kämpfer (Stein, Papier, Schere): Stein

Was ist ein CLI-Programm?

Wie es auf Wikipedia heißt: „Eine Befehlszeilenschnittstelle (CLI) ist ein Mittel zur Interaktion mit einem Gerät oder Computerprogramm mit Befehlen von einem Benutzer oder Client und Antworten vom Gerät oder Programm in Form von Textzeilen.“


Mit anderen Worten ist ein CLI-Programm ein Programm, bei dem der Benutzer die Befehlszeile verwendet, um mit dem Programm zu interagieren, indem er Anweisungen zur Ausführung gibt.


Viele alltägliche Software ist als CLI-Programm verpackt. Nehmen Sie zum Beispiel den vim Texteditor – ein Tool, das mit jedem UNIX-System geliefert wird und einfach durch Ausführen vim <FILE> im Terminal aktiviert werden kann.


Lassen Sie uns in Bezug auf die Google Cloud CLI in die Anatomie eines CLI-Programms eintauchen.

Argumente

Argumente (Parameter) sind Informationselemente, die einem Programm bereitgestellt werden. Sie werden oft als Positionsargumente bezeichnet, weil sie durch ihre Position identifiziert werden.


Wenn wir beispielsweise die project im Kernabschnitt festlegen möchten, führen wir gcloud config set project <PROJECT_ID> aus


Insbesondere können wir dies in übersetzen

Streit

Inhalt

Argument 0

gcloud

Argument 1

config

Befehle

Befehle sind eine Reihe von Argumenten, die dem Computer Anweisungen geben.


Basierend auf dem vorherigen Beispiel legen wir die project im Kernabschnitt fest, indem wir gcloud config set project <PROJECT_ID> ausführen


Mit anderen Worten, set ist ein Befehl.

Optionale Befehle

Normalerweise sind Befehle erforderlich, wir können jedoch Ausnahmen machen. Basierend auf dem Anwendungsfall des Programms können wir optionale Befehle definieren.


Bezugnehmend auf den Befehl gcloud config , wie in der offiziellen Dokumentation angegeben, handelt es sich bei gcloud config um eine Befehlsgruppe, mit der Sie Eigenschaften ändern können. Die Verwendung ist als solche:

 gcloud config GROUP | COMMAND [GCLOUD_WIDE_FLAG … ]

wobei COMMAND entweder set , list usw. sein kann ... (Beachten Sie, dass GROUP config ist)

Optionen

Optionen sind dokumentierte Parametertypen, die das Verhalten eines Befehls ändern. Es handelt sich um Schlüssel-Wert-Paare, die mit „-“ oder „--“ gekennzeichnet sind.


Zurück zur Verwendung der gcloud config Befehlsgruppe: Die Option(en) sind in diesem Fall GCLOUD_WIDE_FLAG .


Angenommen, wir möchten die detaillierte Verwendung und Beschreibung des Befehls anzeigen, führen wir gcloud config set –help aus. Mit anderen Worten: --help ist die Option.


Ein weiteres Beispiel: Wenn wir die Zoneneigenschaft im Compute-Abschnitt eines bestimmten Projekts festlegen möchten, führen wir gcloud config set compute <ZONE_NAME> –project=<PROJECT_ID> aus. Mit anderen Worten: --project ist eine Option, die den Wert <PROJECT_ID> enthält.


Es ist auch wichtig zu beachten, dass ihre Positionen normalerweise keine Rolle spielen.

Obligatorische Optionen

Optionen wie der Name sind normalerweise optional, können aber auch so angepasst werden, dass sie obligatorisch sind.


Wenn wir beispielsweise einen Dataproc-Cluster erstellen möchten, führen wir gcloud dataproc clusters create <CLUSTER_NAME> –region=<REGION> aus. Und wie in ihrer Nutzungsdokumentation angegeben:

 gcloud dataproc clusters create (CLUSTER: –region=REGION)

Das Flag --region ist obligatorisch, wenn es nicht zuvor konfiguriert wurde.

Short-Optionen vs. Long-Optionen

Kurze Optionen beginnen mit - gefolgt von einem einzelnen alphanumerischen Zeichen, während lange Optionen mit -- gefolgt von mehreren Zeichen beginnen. Stellen Sie sich kurze Optionen als Abkürzungen vor, wenn der Benutzer sicher ist, was er möchte, während lange Optionen besser lesbar sind.


Du hast dich für Rock entschieden! Der Computer trifft nun seine Auswahl.

Was werden wir mit diesem Tutorial erreichen?

Also habe ich gelogen ... Wir werden nicht versuchen, das CLI-Programm „Stein-Papier-Schere“ zu aktualisieren.

Schauen wir uns stattdessen ein reales Szenario an:

Gliederung und Ziele

Ihr Team verwendet Trello, um die Probleme und den Fortschritt des Projekts zu verfolgen. Ihr Team sucht nach einer einfacheren Möglichkeit, mit dem Board zu interagieren – ähnlich wie beim Erstellen eines neuen GitHub-Repositorys über das Terminal. Das Team hat sich an Sie gewandt, um ein CLI-Programm mit der Grundvoraussetzung zu erstellen, dass Sie der Spalte „Zu erledigen“ des Boards eine neue Karte hinzufügen können.


Basierend auf der genannten Anforderung entwerfen wir unser CLI-Programm, indem wir seine Anforderungen definieren:


Funktionale Anforderungen

  • Der Benutzer kann einer Spalte auf der Tafel eine neue Karte hinzufügen
    • Erforderliche Eingaben: Spalte, Kartenname
    • Optionale Eingaben: Kartenbeschreibung, Kartenetiketten (aus vorhandenen auswählen)

Nicht-funktionale Anforderungen

  • Programm, das den Benutzer auffordert, Zugriff auf das Trello-Konto zu gewähren (Autorisierung)
  • Programm, das den Benutzer auffordert, festzulegen, auf welchem Trello-Board gearbeitet werden soll (Konfiguration)

Optionale Anforderungen

  • Der Benutzer kann dem Board eine neue Spalte hinzufügen
  • Der Benutzer kann dem Board ein neues Etikett hinzufügen
  • Der Benutzer kann eine vereinfachte/detaillierte Ansicht aller Spalten sehen


Basierend auf dem oben Gesagten können wir die Befehle und Optionen unseres CLI-Programms wie folgt formalisieren:

Detaillierte Tabellenansicht der CLI-Struktur basierend auf den Anforderungen


Ps. Machen Sie sich keine Sorgen wegen der letzten beiden Spalten, wir werden später mehr darüber erfahren …


Was unseren Tech-Stack betrifft, bleiben wir dabei:


Unit-Tests

  • pytest
  • pytest-mock
  • CLI-Test-Helfer

Trello

  • py-trello (Python-Wrapper für das Trello SDK)

CLI

  • Schreiber
  • reich
  • Simple-Term-Menü

Dienstprogramme (Verschiedenes)

  • python-dotenv

Zeitleiste

Wir werden dieses Projekt in Teilen angehen und hier ist ein Ausschnitt dessen, was Sie erwarten können:


Teil 1

  • Implementierung der py-trello Geschäftslogik

Teil 2

  • Implementierung der CLI-Geschäftslogik
  • Verteilen des CLI-Programms als Paket

Teil 3

  • Umsetzung optionaler funktionaler Anforderungen
  • Paketaktualisierung


Der Computer hat sich für die Schere entschieden! Mal sehen, wer diesen Kampf gewinnt ...

Lass uns anfangen

Ordnerstruktur

Ziel ist es, das CLI-Programm als Paket auf PyPI zu verteilen. Daher ist ein solches Setup erforderlich:

 trellocli/ __init__.py __main__.py models.py cli.py trelloservice.py tests/ test_cli.py test_trelloservice.py README.md pyproject.toml .env .gitignore


Hier ist ein tiefer Einblick in jede Datei und/oder jedes Verzeichnis:

  • trellocli : fungiert als Paketname, der von Benutzern verwendet werden soll, z. B. pip install trellocli
    • __init__.py : Stellt das Stammverzeichnis des Pakets dar und passt den Ordner als Python-Paket an
    • __main__.py : Definiert den Einstiegspunkt und ermöglicht Benutzern das Ausführen von Modulen ohne Angabe des Dateipfads durch Verwendung des Flags -m , z. B. python -m <module_name> , um python -m <parent_folder>/<module_name>.py zu ersetzen
    • models.py : speichert global verwendete Klassen, z. B. Modelle, denen API-Antworten entsprechen sollen
    • cli.py : speichert die Geschäftslogik für CLI-Befehle und -Optionen
    • trelloservice.py : speichert die Geschäftslogik für die Interaktion mit py-trello
  • tests : speichert Unit-Tests für das Programm
    • test_cli.py : speichert Unit-Tests für die CLI-Implementierung
    • test_trelloservice.py : speichert Unit-Tests für die Interaktion mit py-trello
  • README.md : speichert die Dokumentation für das Programm
  • pyproject.toml : speichert die Konfigurationen und Anforderungen des Pakets
  • .env : speichert Umgebungsvariablen
  • .gitignore : Gibt die Dateien an, die während der Versionskontrolle ignoriert (nicht verfolgt) werden sollen


Eine ausführlichere Erklärung zum Veröffentlichen von Python-Paketen finden Sie in diesem großartigen Artikel: „How to Publish an Open-Source Python Package to PyPI“ von Geir Arne Hjelle

Aufstellen

Bevor wir beginnen, gehen wir zunächst auf die Einrichtung des Pakets ein.


Beginnend mit der Datei __init__.py in unserem Paket, in der Paketkonstanten und -variablen wie App-Name und -Version gespeichert werden. In unserem Fall wollen wir Folgendes initialisieren:

  • App Name
  • Ausführung
  • SUCCESS- und ERROR-Konstanten
 # trellocli/__init__.py __app_name__ = "trellocli" __version__ = "0.1.0" ( SUCCESS, TRELLO_WRITE_ERROR, TRELLO_READ_ERROR ) = range(3) ERRORS = { TRELLO_WRITE_ERROR: "Error when writing to Trello", TRELLO_READ_ERROR: "Error when reading from Trello" }


Wenn wir zur Datei __main__.py übergehen, sollte hier der Hauptablauf Ihres Programms gespeichert sein. In unserem Fall speichern wir den Einstiegspunkt des CLI-Programms, vorausgesetzt, dass es in cli.py eine aufrufbare Funktion gibt.

 # trellocli/__main__.py from trellocli import cli def main(): # we'll modify this later - after the implementation of `cli.py` pass if __name__ == "__main__": main()


Nachdem das Paket nun eingerichtet wurde, werfen wir einen Blick auf die Aktualisierung unserer README.md Datei (Hauptdokumentation). Es gibt keine bestimmte Struktur, der wir folgen müssen, aber eine gute README-Datei würde aus Folgendem bestehen:

  • Überblick
  • Installation und Anforderungen
  • Erste Schritte und Verwendung

Ein weiterer toller Beitrag zum Nachlesen, wenn Sie tiefer eintauchen möchten: How to Write a Good README von merlos


So möchte ich die README-Datei für dieses Projekt strukturieren

 <!--- README.md --> # Overview # Getting Started # Usage # Architecture ## Data Flow ## Tech Stack # Running Tests # Next Steps # References


Lassen wir das Grundgerüst vorerst so, wie es ist – wir kommen später darauf zurück.


Lassen Sie uns nun die Metadaten unseres Pakets basierend auf der offiziellen Dokumentation konfigurieren

 # pyproject.toml [project] name = "trellocli_<YOUR_USERNAME>" version = "0.1.0" authors = [ { name = "<YOUR_NAME>", email = "<YOUR_EMAIL>" } ] description = "Program to modify your Trello boards from your computer's command line" readme = "README.md" requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ] dependencies = [] [project.urls] "Homepage" = ""


Beachten Sie, dass es Platzhalter gibt, die Sie ändern müssen, z. B. Ihren Benutzernamen, Ihren Namen usw.


Außerdem lassen wir die Homepage-URL vorerst leer. Wir werden Änderungen vornehmen, nachdem wir es auf GitHub veröffentlicht haben. Außerdem lassen wir den Abschnitt „Abhängigkeiten“ vorerst leer und fügen ihn nach und nach hinzu.


Als nächstes auf der Liste wäre unsere .env Datei, in der wir unsere Umgebungsvariablen wie API-Geheimnisse und Schlüssel speichern. Es ist wichtig zu beachten, dass diese Datei nicht von Git verfolgt werden sollte, da sie vertrauliche Informationen enthält.


In unserem Fall speichern wir hier unsere Trello-Zugangsdaten. Befolgen Sie diese Anleitung , um ein Power-Up in Trello zu erstellen. Genauer gesagt, basierend auf der Verwendung durch py-trello , da wir OAuth für unsere Anwendung verwenden möchten, benötigen wir Folgendes, um mit Trello zu interagieren:

  • API-Schlüssel (für unsere Anwendung)
  • API-Geheimnis (für unsere Anwendung)
  • Token (Token des Benutzers, um Zugriff auf seine Daten zu gewähren)


Sobald Sie Ihren API-Schlüssel und Ihr Geheimnis abgerufen haben, speichern Sie sie als solche in der .env Datei

 # .env TRELLO_API_KEY=<your_api_key> TRELLO_API_SECRET=<your_api_secret>


Zu guter Letzt verwenden wir die Vorlage Python .gitignore , die Sie hier finden. Beachten Sie, dass dies von entscheidender Bedeutung ist, um sicherzustellen, dass unsere .env Datei niemals verfolgt wird. Wenn unsere .env Datei irgendwann verfolgt wurde, ist der Schaden bereits angerichtet und böswillige Akteure können die vorherige Datei aufspüren, auch wenn wir sie in späteren Schritten entfernt haben Patches für vertrauliche Informationen.


Nachdem die Einrichtung nun abgeschlossen ist, übertragen wir unsere Änderungen auf GitHub. Denken Sie je nach den in pyproject.toml angegebenen Metadaten daran, Ihre LIZENZ und Homepage-URL entsprechend zu aktualisieren. Als Referenz zum Schreiben besserer Commits: Write Better Commits, Build Better Projects von Victoria Dye


Weitere bemerkenswerte Schritte:

Unit-Tests

Bevor wir mit dem Schreiben unserer Tests beginnen, ist es wichtig zu beachten, dass wir, da wir mit einer API arbeiten, Scheintests implementieren werden, um unser Programm ohne das Risiko von API-Ausfällen testen zu können. Hier ist ein weiterer großartiger Artikel über Mock-Tests von Real Python: Mocking External APIs in Python


Basierend auf den funktionalen Anforderungen besteht unser Hauptanliegen darin, Benutzern das Hinzufügen einer neuen Karte zu ermöglichen. Verweisen auf die Methode in py-trello : add_card . Dazu müssen wir die Methode add_card aus der Klasse List aufrufen, die über die Funktion get_list aus der Klasse „ Board abgerufen werden kann.


Sie verstehen das Wesentliche – wir werden viele Hilfsmethoden benötigen, um unser endgültiges Ziel zu erreichen. Sagen wir es in Worten:

  • Testen Sie, um das Token des Clients abzurufen
  • Testen Sie, um Boards abzurufen
  • Testen Sie, um ein Board abzurufen
  • Testen Sie, um Listen vom Board abzurufen
  • Testen Sie, um eine Liste abzurufen
  • Testen Sie, um Etiketten von der Tafel abzurufen
  • Testen Sie, um ein Etikett abzurufen
  • Testen Sie, um eine Karte hinzuzufügen
  • Testen Sie, um der Karte ein Etikett hinzuzufügen


Es ist auch wichtig zu beachten, dass wir beim Schreiben von Unit-Tests darauf achten, dass unsere Tests so umfangreich wie möglich sind. Werden Fehler gut verarbeitet? Deckt es jeden Aspekt unseres Programms ab?


Allerdings werden wir in diesem Tutorial die Dinge vereinfachen, indem wir nur nach Erfolgsfällen suchen.


Bevor wir in den Code eintauchen, ändern wir unsere Datei pyproject.toml so, dass sie die Abhängigkeiten enthält, die zum Schreiben/Ausführen von Komponententests erforderlich sind.

 # pyproject.toml [project] dependencies = [ "pytest==7.4.0", "pytest-mock==3.11.1" ]


Als nächstes aktivieren wir unsere virtuelle Umgebung und führen pip install . um die Abhängigkeiten zu installieren.


Sobald das erledigt ist, schreiben wir endlich einige Tests. Im Allgemeinen sollten unsere Tests eine zurückgegebene simulierte Antwort, einen Patch für die Funktion, die wir testen möchten, indem wir den Rückgabewert mit der simulierten Antwort korrigieren, und schließlich einen Aufruf der Funktion umfassen. Ein Beispieltest zum Abrufen der Zugriffstoken des Benutzers würde wie folgt aussehen:

 # tests/test_trelloservice.py # module imports from trellocli import SUCCESS from trellocli.trelloservice import TrelloService from trellocli.models import * # dependencies imports # misc imports def test_get_access_token(mocker): """Test to check success retrieval of user's access token""" mock_res = GetOAuthTokenResponse( token="test", token_secret="test", status_code=SUCCESS ) mocker.patch( "trellocli.trelloservice.TrelloService.get_user_oauth_token", return_value=mock_res ) trellojob = TrelloService() res = trellojob.get_user_oauth_token() assert res.status_code == SUCCESS


Beachten Sie in meinem Beispielcode, dass GetOAuthTokenResponse ein Modell ist, das noch in models.py festgelegt werden muss. Es bietet Struktur zum Schreiben sauberer Codes. Wir werden dies später in Aktion sehen.


Um unsere Tests auszuführen, führen Sie einfach python -m pytest aus. Beachten Sie, dass unsere Tests scheitern werden, aber das ist in Ordnung – am Ende wird es klappen.


Challenge Corner 💡 Können Sie versuchen, weitere Tests selbst zu schreiben? Sehen Sie sich gernediesen Patch an, um zu sehen, wie meine Tests aussehen


Lassen Sie uns zunächst unseren trelloservice aufbauen. Beginnen Sie mit dem Hinzufügen einer neuen Abhängigkeit, dem py-trello -Wrapper.

 # pyproject.toml dependencies = [ "pytest==7.4.0", "pytest-mock==3.11.1", "py-trello==0.19.0" ]


Führen Sie erneut pip install . um die Abhängigkeiten zu installieren.

Modelle

Beginnen wir nun mit dem Aufbau unserer Modelle – um die Antworten zu regulieren, die wir in trelloservice erwarten. Für diesen Teil lesen Sie am besten unsere Unit-Tests und den py-trello Quellcode, um zu verstehen, welche Art von Rückgabewert wir erwarten können.


Angenommen, wir möchten das Zugriffstoken des Benutzers abrufen und beziehen uns dabei auf die Funktion create_oauth_token von py-trello ( Quellcode ). Wir wissen, dass wir einen Rückgabewert wie diesen erwarten können

 # trellocli/models.py # module imports # dependencies imports # misc imports from typing import NamedTuple class GetOAuthTokenResponse(NamedTuple): token: str token_secret: str status_code: int


Beachten Sie andererseits widersprüchliche Namenskonventionen. Das py-trello Modul hat beispielsweise eine Klasse namens List . Eine Lösung hierfür wäre die Bereitstellung eines Alias beim Import.

 # trellocli/models.py # dependencies imports from trello import List as Trellolist


Nutzen Sie diese Gelegenheit gerne auch, um die Modelle an die Bedürfnisse Ihres Programms anzupassen. Angenommen, Sie benötigen nur ein Attribut aus dem Rückgabewert. Sie könnten Ihr Modell so umgestalten, dass es den besagten Wert aus dem Rückgabewert extrahiert, anstatt ihn als Ganzes zu speichern.

 # trellocli/models.py class GetBoardName(NamedTuple): """Model to store board id Attributes id (str): Extracted board id from Board value type """ id: str


Challenge Corner 💡 Kannst du versuchen, selbst mehr Modelle zu schreiben? Sehen Sie sich gernediesen Patch an, um zu sehen, wie meine Modelle aussehen

Geschäftslogik

Aufstellen

Modelle runter, lasst uns offiziell mit dem Codieren des trelloservice beginnen. Auch hier sollten wir uns auf die von uns erstellten Unit-Tests beziehen. Nehmen wir an, dass die aktuelle Testliste den Dienst nicht vollständig abdeckt. Kommen Sie immer zurück und fügen Sie bei Bedarf weitere Tests hinzu.


Fügen Sie wie üblich alle Importanweisungen oben ein. Erstellen Sie dann wie erwartet die TrelloService Klasse und die Platzhaltermethoden. Die Idee ist, dass wir eine gemeinsame Instanz des Dienstes in cli.py initialisieren und seine Methoden entsprechend aufrufen. Darüber hinaus streben wir nach Skalierbarkeit und damit nach einer umfassenden Abdeckung.

 # trellocli/trelloservice.py # module imports from trellocli import TRELLO_READ_ERROR, TRELLO_WRITE_ERROR, SUCCESS from trellocli.models import * # dependencies imports from trello import TrelloClient # misc imports class TrelloService: """Class to implement the business logic needed to interact with Trello""" def __init__(self) -> None: pass def get_user_oauth_token() -> GetOAuthTokenResponse: pass def get_all_boards() -> GetAllBoardsResponse: pass def get_board() -> GetBoardResponse: pass def get_all_lists() -> GetAllListsResponse: pass def get_list() -> GetListResponse: pass def get_all_labels() -> GetAllLabelsResponse: pass def get_label() -> GetLabelResponse: pass def add_card() -> AddCardResponse: pass


PS: Beachten Sie, dass unsere Tests dieses Mal bestanden werden, wenn wir unsere Tests durchführen. Tatsächlich wird uns das dabei helfen, sicherzustellen, dass wir auf dem richtigen Weg bleiben. Der Arbeitsablauf sollte darin bestehen, unsere Funktionen zu erweitern, unsere Tests auszuführen, auf Pass/Fail zu prüfen und entsprechend umzugestalten.

Autorisierung und Initialisierung von TrelloClient

Beginnen wir mit der Funktion __init__ . Die Idee ist, hier die Funktion get_user_oauth_token aufzurufen und den TrelloClient zu initialisieren. Um die Notwendigkeit zu betonen, solche vertraulichen Informationen nur in der .env Datei zu speichern, verwenden wir die Abhängigkeit python-dotenv , um vertrauliche Informationen abzurufen. Nachdem wir unsere Datei pyproject.toml entsprechend geändert haben, beginnen wir mit der Implementierung der Autorisierungsschritte.

 # trellocli/trelloservice.py class TrelloService: """Class to implement the business logic needed to interact with Trello""" def __init__(self) -> None: self.__load_oauth_token_env_var() self.__client = TrelloClient( api_key=os.getenv("TRELLO_API_KEY"), api_secret=os.getenv("TRELLO_API_SECRET"), token=os.getenv("TRELLO_OAUTH_TOKEN") ) def __load_oauth_token_env_var(self) -> None: """Private method to store user's oauth token as an environment variable""" load_dotenv() if not os.getenv("TRELLO_OAUTH_TOKEN"): res = self.get_user_oauth_token() if res.status_code == SUCCESS: dotenv_path = find_dotenv() set_key( dotenv_path=dotenv_path, key_to_set="TRELLO_OAUTH_TOKEN", value_to_set=res.token ) else: print("User denied access.") self.__load_oauth_token_env_var() def get_user_oauth_token(self) -> GetOAuthTokenResponse: """Helper method to retrieve user's oauth token Returns GetOAuthTokenResponse: user's oauth token """ try: res = create_oauth_token() return GetOAuthTokenResponse( token=res["oauth_token"], token_secret=res["oauth_token_secret"], status_code=SUCCESS ) except: return GetOAuthTokenResponse( token="", token_secret="", status_code=TRELLO_AUTHORIZATION_ERROR )


In dieser Implementierung haben wir eine Hilfsmethode erstellt, um alle vorhersehbaren Fehler zu behandeln, z. B. wenn der Benutzer während der Autorisierung auf Deny klickt. Darüber hinaus ist es so eingerichtet, dass es rekursiv nach der Autorisierung des Benutzers fragt, bis eine gültige Antwort zurückgegeben wird, denn Tatsache ist, dass wir nicht fortfahren können, es sei denn, der Benutzer autorisiert unsere App, auf seine Kontodaten zuzugreifen.


Challenge Corner 💡 Beachten Sie TRELLO_AUTHORIZATION_ERROR ? Können Sie diesen Fehler als Paketkonstante deklarieren? Weitere Informationen finden Sie unter „Setup“.

Hilfsfunktionen

Nachdem der Autorisierungsteil nun abgeschlossen ist, gehen wir zu den Hilfsfunktionen über und beginnen mit dem Abrufen der Trello-Boards des Benutzers.

 # trellocli/trelloservice.py def get_all_boards(self) -> GetAllBoardsResponse: """Method to list all boards from user's account Returns GetAllBoardsResponse: array of user's trello boards """ try: res = self.__client.list_boards() return GetAllBoardsResponse( res=res, status_code=SUCCESS ) except: return GetAllBoardsResponse( res=[], status_code=TRELLO_READ_ERROR ) def get_board(self, board_id: str) -> GetBoardResponse: """Method to retrieve board Required Args board_id (str): board id Returns GetBoardResponse: trello board """ try: res = self.__client.get_board(board_id=board_id) return GetBoardResponse( res=res, status_code=SUCCESS ) except: return GetBoardResponse( res=None, status_code=TRELLO_READ_ERROR )


Zum Abrufen der Listen (Spalten) müssen wir die Board Klasse von py-trello auschecken, oder mit anderen Worten, wir müssen einen neuen Parameter des Board Werttyps akzeptieren.

 # trellocli/trelloservice.py def get_all_lists(self, board: Board) -> GetAllListsResponse: """Method to list all lists (columns) from the trello board Required Args board (Board): trello board Returns GetAllListsResponse: array of trello lists """ try: res = board.all_lists() return GetAllListsResponse( res=res, status_code=SUCCESS ) except: return GetAllListsResponse( res=[], status_code=TRELLO_READ_ERROR ) def get_list(self, board: Board, list_id: str) -> GetListResponse: """Method to retrieve list (column) from the trello board Required Args board (Board): trello board list_id (str): list id Returns GetListResponse: trello list """ try: res = board.get_list(list_id=list_id) return GetListResponse( res=res, status_code=SUCCESS ) except: return GetListResponse( res=None, status_code=TRELLO_READ_ERROR )


Challenge Corner 💡 Könnten Sie die Funktionen get_all_labels und get_label selbst implementieren? Überarbeiten Sie die Board Klasse von py-trello . Sehen Sie sich gernediesen Patch an, um zu sehen, wie meine Implementierung aussieht

Funktion zum Hinzufügen einer neuen Karte

Zu guter Letzt haben wir endlich das erreicht, was wir die ganze Zeit angestrebt haben – das Hinzufügen einer neuen Karte. Beachten Sie, dass wir hier nicht alle zuvor deklarierten Funktionen verwenden – das Ziel der Hilfsfunktionen besteht darin, die Skalierbarkeit zu erhöhen.

 # trellocli/trelloservice.py def add_card( self, col: Trellolist, name: str, desc: str = "", labels: List[Label] = [] ) -> AddCardResponse: """Method to add a new card to a list (column) on the trello board Required Args col (Trellolist): trello list name (str): card name Optional Args desc (str): card description labels (List[Label]): list of labels to be added to the card Returns AddCardResponse: newly-added card """ try: # create new card new_card = col.add_card(name=name) # add optional description if desc: new_card.set_description(description=desc) # add optional labels if labels: for label in labels: new_card.add_label(label=label) return AddCardResponse( res=new_card, status_code=SUCCESS ) except: return AddCardResponse( res=new_card, status_code=TRELLO_WRITE_ERROR )


🎉 Nachdem das erledigt ist, denken Sie daran, Ihre README-Datei entsprechend zu aktualisieren und Ihren Code auf GitHub zu übertragen.


Glückwunsch! Du hast gewonnen. Nochmals spielen (j/n)?

Einpacken

Vielen Dank für Ihr Verständnis :) Durch dieses Tutorial haben Sie erfolgreich gelernt, Mocking beim Schreiben von Unit-Tests zu implementieren, Modelle für Kohärenz zu strukturieren, Quellcode zu lesen, um wichtige Funktionalitäten zu finden, und Geschäftslogik mithilfe eines Wrappers eines Drittanbieters zu implementieren.


Halten Sie Ausschau nach Teil 2, in dem wir uns eingehend mit der Implementierung des CLI-Programms selbst befassen.


Bleiben wir in der Zwischenzeit in Kontakt 👀