In meinem Artikel „Obsidian Bookmark Seite, aber schöner” nutze ich für meinen Alfred-Workflow ein Python-Skript und die Python-Bibliotheken lxml
und linkpreview
.
Wie im Original-Skript am Ende des Artikels im Nachtrag zu sehen, habe ich Python mit Homebrew auf meinem Rechner installiert und folglich in der „Shebang” den Pfad #!/opt/homebrew/bin/python3
angegeben. Die benötigten Bibliotheken installierte ich global, was damals problemlos funktionierte.
Kürzlich stellte ich jedoch fest, dass der Alfred-Workflow keinen Bookmark mehr erstellte, da das Python-Skript die Bibliotheken nicht mehr fand. Warum? Das weiss ich nicht. Vielleicht war ein Upgrade von Homebrew Schuld, das eine neue Python-Version installierte, welche nun bei dem Versuch die Libraries im Terminal neu zu installieren, den Fehler error: externally-managed-environment
feuerte.
Obwohl man diesen Fehler umgehen kann, indem man pip3
mit dem Parameter: --break-system-packages
aufruft, wäre der korrekte Ansatz, für das Python-Skript eine eigene virtuelle Umgebung zu erstellen. In dieser können alle Abhängigkeiten des Python-Skripts isoliert vom Rest des Systems installiert und verwaltet werden. Und wenn ich es richtig verstehe, wäre dieses Umgebung dann auch etwas besser gegen Änderungen bei dem nächsten Upgrade von Python geschützt.
Trotz intensiver Suche fand ich aber keinen Hinweis darauf, wie man eine virtuelle Umgebung für ein Python-Skript in einem Alfred-Workflow umsetzen kann. Letztendlich habe ich mir jedoch eine Methode ausgedacht, um eine solche Umgebung auch in einem Alfred-Workflow zu nutzen. Ob dies die „ultimative” Lösung ist, ob ich etwas übersehen habe oder ob es bessere Lösungen für das Problem gibt, kann ich nicht sagen. Diese Lösung funktioniert aber, zumindest im Moment.
Lösungsweg
Meine Idee besteht darin, eine entsprechende virtuelle Umgebung im Alfred-Workflow-Ordner im Terminal auf der Kommandozeile zu erstellen und später beim Aufruf des Python-Skripts in dem Alfred-Workflow zu nutzen. AUf der Kommandozeile können dann auch, während die virtuelle Umgebung aktiv ist, die benötigten Libraries installiert werden.
Im dem neuen Ansatz wird das Python-Skript dann nicht mehr direkt im Alfred-Workflow aufgerufen, sondern über ein zsh-Skript. in diesem Skript wird zunächst die virtuelle Umgebung aktiviert. Erst dann wird das Python-Skript aufgerufen, wobei das erstellte Markdown zunächst in eine Variable geschrieben wird. Dies ermöglicht die Deaktivierung der virtuellen Umgebung nach der Ausführung des Python-Skripts und die anschliessenden Übergabe des Inhalt der Variable via des echo
-Befehls an die nächste Aktion, das bisherige zsh-Skript, das den Preview in die Bookmark-Datei für Obsidian schreibt.
Schritt 1: Ermittlung des Pfads des Workflow-Ordners
Alle relevanten Daten eines Alfred-Workflows werden in einem Ordner gespeichert, z.B. ~/Library/Application Support/Alfred/Alfred.alfredpreferences/workflows/user.workflow.6510DB4E-C3AC-4B75-90D8-3CE9B0CE91B2
. Diesen Ordner findet man leicht, indem man auf das Ordnersymbol in einer Skript-Aktion unten rechts klickt. Dadurch der Workflow-Ordner im Finder geöffnet wird.
Schritt 2: Erstellen der virtuellen Umgebung
In diesem Ordner muss die virtuelle Umgebung erstellt werden. Dazu muss man im Terminal das „Arbeitsverzeichnis” auf diesen Ordner setzen. Dazu gibt man im einem Terminal Fenster zunächst ein cd
gefolgt von einem Leerzeichen ein, klickt danach den Titel im Finder-Fenster des Alfred-Workflow-Ordners und zieht das erscheinende Ordnersymbol ins Terminal, wodurch der Pfad als Text erscheint. Mit dem Drücken der Eingabetaste wechselt man dann in den entsprechenden Ordner. Mit dem Befehl pwd
kann man überprüfen, ob man alles geklappt hat un man sich auf der Kommandozeile im richtigen Ordner befindet.
Nun müssen die folgenden Befehlen eingegeben werden:
# Erstellung der virtuellen Umgebung >$ python3 -m venv env # Aktivierung der Umgebung >$ source env/bin/activate # Installation der linkpreview Library innerhalb der (env) >$ pip install linkpreview # Installation der lxml Library (env) >$ pip install lxml # Eventueller Test des Python-Skripts # innerhalb der virtuellen Umgebung (env) >$ python script.py https://ileif.de # Deaktivierung der virtuellen Umgebung (env) >$ deactivate
Innerhalb der virtuellen Umgebung kann auf die 3 beim Aufruf von python
und pip
verzichtet werden, da in der Umgebung die Python Version läut, mit der man sie erstellt hat.
Schritt 3: Anpassungen des Workflows
Um den Workflow anzupassen, sind drei Änderungen erforderlich. Zuerst muss die „Shebang”, also die erste Zeile des Skripts, entfernt werden, da das Python-Skript nun mit dem „virtuellen” Python der Umgebung ausgeführt wird. Das Python-Skript sollte dann wie folgt aussehen und in dem Workflow-Ordner als script.py
gespeichert sein.
import sys from linkpreview import link_preview import requests from bs4 import BeautifulSoup def get_first_paragraph(soup): paragraph = soup.find('p') if paragraph: return paragraph.get_text().strip() return "No excerpt available" def generate_markdown_tile(url): try: # Versuch, den Inhalt der URL zu erhalten response = requests.get(url) response.raise_for_status() # Löst eine Ausnahme aus, wenn der HTTP-Statuscode 4xx oder 5xx ist except requests.exceptions.HTTPError as e: # Gibt eine benutzerdefinierte Fehlermeldung zurück, wenn ein HTTPError auftritt return f"Error fetching URL: {e}" # Falls kein Fehler auftritt, fahre fort mit der normalen Verarbeitung soup = BeautifulSoup(response.content, 'html.parser') preview = link_preview(url, parser="lxml") if preview.image is None: # Falls kein Bild vorhanden ist, kann ggf. eins ergänzt werden # preview.image = "https://example.com/noimage.png" if not preview.description: description = get_first_paragraph(soup) else: description = preview.description markdown_tile = f""" <table padding=50px> <tr> <td> <img src="{preview.image}" alt="{preview.title}" width="200" style="padding: 10px;"> </td> <td> <a href="{url}" style="font-size: 16px;">{preview.title}</a> <br> <p>{description}</p> </td> </tr> </table> """ return markdown_tile if __name__ == "__main__": import sys if len(sys.argv) != 2: print("Usage: python script_name.py <url>") sys.exit(1) url = sys.argv[1] markdown_tile = generate_markdown_tile(url) print(markdown_tile)
Die Python-Skript Aktion in der alten Alfred-Workflow-Lösung wird dann durch das folgende zsh-Skript ersetzt:
# Übergabe der URL url={query} # Aktivierung der virtuellen Umgebung source env/bin/activate # Ausführung des Python-Skripts mit dem übergebenen Parameter markdown=$(python3 script.py "$url") # Deaktivierung der virtuellen Umgebung deactivate # Ausgabe des Ergebnisses echo "$markdown"
Der Workflow sollte dann so aussehen:
Mit diesen Anpassungen sollte der Workflow nun wieder wie vorgesehen laufen. Dieses Verfahren erscheint mir auch als eine praktikable Lösung für andere Python-basierte Lösungen in Alfred-Workflows, die zusätzliche Libraries benötigen. Sollte es jedoch bessere Ansätze geben, bin ich für Hinweise in den Kommentaren dankbar.
Schreibe einen Kommentar