Probleme mit dem Import von Modulen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
BrotherJ
User
Beiträge: 7
Registriert: Donnerstag 21. November 2024, 18:35

Hallo zusammen,

ich habe Import-Problem bei dieser Paketstruktur
project_name/
├── LICENSE
├── pytest.ini
├── README.md
└── src
└── securesnapbackup
├── backup_config.yaml
├── __init__.py
├── main.py
├── module
└── tests

Hier gebe ich der main.py

Code: Alles auswählen

import os
from securesnapbackup.module.Numerator import Numerator

def main():
    
    numerator = Numerator()
    count = numerator.counting()

if __name__ == "__main__":
    main()
und den Modulen unter "module" den Part "securesnapbackup.module" in der Import-Anweisung mit.

Dann bekomme ich bei der Ausführung immer die Fehler:

Code: Alles auswählen

 python3 src/securesnapbackup/main.py
Traceback (most recent call last):
  File "/home/brotherj/Projekte/SecureSnapBackup/src/securesnapbackup/main.py", line 5, in <module>
    from module.Numerator import Numerator
  File "/home/brotherj/Projekte/SecureSnapBackup/src/securesnapbackup/module/Numerator.py", line 3, in <module>
    from .Logger import Logger
  File "/home/brotherj/Projekte/SecureSnapBackup/src/securesnapbackup/module/Logger.py", line 2, in <module>
    from securesnapbackup.module.DataLoader import DataLoader
ModuleNotFoundError: No module named 'securesnapbackup'
Wenn ich aber auf das Verzeichnis "securesnapbackup" verzichte und alles so gestalte
project_name/
├── LICENSE
├── pytest.ini
├── README.md
└── src
├── backup_config.yaml
├── main.py
├── module
└── tests
und auch beim Import mich auf "module.blabla" beschränke, dann funktioniert das Programm main.py.

Was mache ich falsch mit der Modularisierung? Mein Ziel ist es, das Program später systemweit laufen zu lassen, weil ein Cronjob in einer virtuellen Umgebung sinnlos ist.
Im Übrigen habe ich Python3 auf Debian Linux 12.

Ich hoffe, ich bekomme von Euch gute Tipps.

Viele Grüße
BrotherJ
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

Pakete müssen im Paketsuchpfad von Python sein, also z.B. im lib-Verzeichnis Deines venvs.
`src` ist nur für die Entwicklung da, das Paket muß erst noch installiert werden.
Das Programm wird automatisch nach bin installiert, wenn es im pyproject.yaml unter [entrypoint] steht.
Ansonsten würde man main über seinen Modulpfad ausführen, also

Code: Alles auswählen

$ <venv-name>/bin/python -m securesnapbackup.main
Deine zweite schlechtere Variante funktioniert nur, weil das Verzeichnis der aufgerufenen Datei automatisch im Paktesuchpfad landet.
`module` ist ein zu generischer Name für ein Paket. Die Unterpakete scheinen auch darauf hinzudeuten, dass Du pro Datei eine Klasse hast. Das macht man in Python nicht, weil dann ja die Modul-Ebene überflüssig wäre. Module schreibt man auch komplett klein, damit man sie von Klassen unterscheiden kann.
BrotherJ
User
Beiträge: 7
Registriert: Donnerstag 21. November 2024, 18:35

Sirius3 hat geschrieben: Samstag 23. November 2024, 14:29
Deine zweite schlechtere Variante funktioniert nur, weil das Verzeichnis der aufgerufenen Datei automatisch im Paktesuchpfad landet.
`module` ist ein zu generischer Name für ein Paket. Die Unterpakete scheinen auch darauf hinzudeuten, dass Du pro Datei eine Klasse hast. Das macht man in Python nicht, weil dann ja die Modul-Ebene überflüssig wäre. Module schreibt man auch komplett klein, damit man sie von Klassen unterscheiden kann.
Danke für Deine Antwort. Okay, wie wäre dann eine sinnvollere Struktur? Ich möchte der Übersicht und des Testens wegen lieber pro Klasse eine Datei und die main.py möglichst schlank halten. Zweite Forderung ist, da das ein Backup-Programm wird, sollte das später im Linux/MacOS systemweit zur Verfügung steht. Deswegen mache im Moment nichts mit einer virtuellen Umgebung, sondern starte direkt aus Codium heraus.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@BrotherJ: Es ist nicht übersichtlicher oder leichter zu testen wenn man eine *zusätzliche* unnötige Zwischenschicht in die Namensräume einzieht. Module sind dazu da um zusammengehörige Klassen und Funktionen aufzunehmen und Packages um Module zu organisieren. Wobei auch nur wenn das Sinn macht, denn ein Package `module` macht auch keinen Sinn als *noch* ein zusätzlicher, unnötiger Zwischenschritt.

Wenn ich das Beispiel mit dem `Numerator` anschaue könnte auch gleich noch der Verdacht aufkommen, das auch die Klassen nicht alle sinnvoll sind, wenn der Rest schon so nach Java & Co aussieht.

Das Argument gegen venvs ist keines und das wurde ja auch schon gesagt. Schreib ein ganz normales Projekt das ganz normal installiert werden kann. Dann ist es egal ob das systemweit, nur für den Nutzer, oder in einem venv installiert wird. Oder anders: wenn das nicht in einem venv funktioniert, aber systemweit, dann ist da was kaputt. Beim entwickeln kann man das auch „editable“ in ein venv installieren.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
BrotherJ
User
Beiträge: 7
Registriert: Donnerstag 21. November 2024, 18:35

__blackjack__ hat geschrieben: Samstag 23. November 2024, 17:05 @BrotherJ: Es ist nicht übersichtlicher oder leichter zu testen wenn man eine *zusätzliche* unnötige Zwischenschicht in die Namensräume einzieht. Module sind dazu da um zusammengehörige Klassen und Funktionen aufzunehmen und Packages um Module zu organisieren. Wobei auch nur wenn das Sinn macht, denn ein Package `module` macht auch keinen Sinn als *noch* ein zusätzlicher, unnötiger Zwischenschritt.

Wenn ich das Beispiel mit dem `Numerator` anschaue könnte auch gleich noch der Verdacht aufkommen, das auch die Klassen nicht alle sinnvoll sind, wenn der Rest schon so nach Java & Co aussieht.

Das Argument gegen venvs ist keines und das wurde ja auch schon gesagt. Schreib ein ganz normales Projekt das ganz normal installiert werden kann. Dann ist es egal ob das systemweit, nur für den Nutzer, oder in einem venv installiert wird. Oder anders: wenn das nicht in einem venv funktioniert, aber systemweit, dann ist da was kaputt. Beim entwickeln kann man das auch „editable“ in ein venv installieren.
Zunächst einmal möchte ich darauf hinweisen, dass eine klare und respektvolle Kommunikation für den Fortschritt eines Forums essenziell ist. Deine Antwort klingt leider eher nach einer Schelte als nach einer konstruktiven Diskussion, weshalb ich versuche, die Punkte noch einmal aufzugreifen, um eine gemeinsame Grundlage zu finden.
  • Zusätzliche Zwischenschicht: Was genau meinst du mit "unnötiger Zwischenschicht"? In meinem Beispiel habe ich Module verwendet, um thematisch zusammengehörige Funktionalitäten zu gruppieren, was durchaus Sinn macht. Wenn du eine Verbesserung vorschlägst, wäre es hilfreich, dies genauer zu erläutern. Was würdest du als bessere Struktur empfehlen?
  • Modularisierung und Packages: Du sagst, dass Module dazu da sind, zusammengehörige Klassen und Funktionen aufzunehmen. Genau das habe ich auch getan. Es wäre hilfreich, wenn du erklären könntest, warum du das anders siehst. Wenn du der Meinung bist, dass meine Struktur nicht sinnvoll ist, freue ich mich auf konkrete Verbesserungsvorschläge.
  • Kritik an den Klassen und dem Beispiel Numerator: Die Aussage, dass die Klassen nicht sinnvoll sind, ohne auf konkrete Probleme einzugehen, ist wenig zielführend. Was genau stört dich an der Struktur der Klassen? Und was ist für dich "sinnvoll"? Dein Hinweis auf Java & Co. ist nicht wirklich nachvollziehbar. Ich strebe nicht an, Java zu kopieren, sondern möchte eine praktikable Lösung in Python finden.
  • Frust und konstruktive Kritik: Ich habe eine Frage gestellt, weil ich ein Problem habe und nach Lösungen suche. Es wäre hilfreich, wenn du versuchst, deine Antwort aus einer hilfsbereiten Perspektive zu formulieren. Konstruktive Vorschläge und Erklärungen sind immer wertvoller als pauschale Kritik. Denke bitte daran, dass jeder mal am Anfang steht, und solche Antworten sind oft wenig förderlich für den Wissensaustausch.
  • vens und "normales Projekt: Ich verstehe, dass du der Meinung bist, dass das Argument gegen venvs nicht zutrifft, aber die Frage nach der Verwendung von virtuellen Umgebungen (venvs) ist ein legitimes Thema. Du schreibst, dass man ein „normales Projekt“ erstellen sollte. Was verstehst du genau unter einem „normalen Projekt“? Was unterscheidet sich mein Ansatz von deinem? Ich denke, eine genauere Erläuterung würde hier weiterhelfen, um Missverständnisse zu vermeiden.
Konstruktive und präzise Rückmeldungen wären hier deutlich hilfreicher, als solche pauschalen Aussagen. Ich freue mich auf eine genauere Erläuterung deiner Perspektive.
Sirius3
User
Beiträge: 18270
Registriert: Sonntag 21. Oktober 2012, 17:20

__blackjacks__ Aussagen waren so konstruktiv, wie aus den wenigen Informationen, die Du lieferst möglich ist. Wenn ein Klasse mit vollem Namensraum securesnapbackup.module.Numerator.Numerator heißt, dann liegt die Vermutung nahe, dass in der Datei Numerator.py nur eine Klasse, definiert wird. Da schon das Pakage securesnapbackup Module zusammenfasst, ist die weitere Ebene module wahrscheinlich auch überflüssig. Das sind natürlich nur Vermutungen, langjährige Erfahrung zeigt aber, dass die Trefferquote sehr hoch ist. Wenn das bei Dir anders ist, dann brauchst Du Dich nicht angegriffen fühlen. Bleibt dann aber die schlechte Namensgebung sowohl von `module` als auch von `Numerator.py`. Denn falls Numerator.py mehr als die Klasse Numerator enhält, ist der Name zu spezifisch, wenn module funktional zusammengehörende Module enthält, dann ist der Name zu generisch.

Du hast das Stichwort venv bekommen, wie tief hast Du Dich mit dem Thema befasst? Um während der Entwicklung möglichst nahe an der produktiven Umgebung zu sein, installiert man sein Paket in ein venv, damit man das machen kann, fehlt aber noch ein pyproject.yaml-Datei. Dein Projekt ist in diesem Sinne nicht normal, weil es nicht installierbar ist, und Du versuchst, das Programm direkt aus den Sourcen zu starten.

Wenn Du konkretere Verschläge möchtest, mußt Du mehr von Deinem Code zeigen und genauer erklären, was Du machen möchtest.
BrotherJ
User
Beiträge: 7
Registriert: Donnerstag 21. November 2024, 18:35

Sirius3 hat geschrieben: Samstag 23. November 2024, 17:59 Wenn Du konkretere Verschläge möchtest, mußt Du mehr von Deinem Code zeigen und genauer erklären, was Du machen möchtest.
Das habe ich doch bereits. Ich das Problem geschildert und es steht im Titel. Alles Weitere ist zusätzlicher Input aus Deiner Richtung, den ich gerne erklärt sehen möchte. Du brauchst mir nicht meinen Code schreiben, das schaffe ich alleine. Ich will jetzt im Moment nur wissen, was Dich so an meiner Struktur stört - ohne Statistik bitte.
Benutzeravatar
__blackjack__
User
Beiträge: 14047
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Unnötige Zwischenschicht ist `module`. Das braucht man nicht. Das sieht man schon am Namen, denn da wird ja gar nicht thematisch gruppiert sondern nach dem Datentyp. `main` ist ja auch ein Modul, aber nicht in `module`. Wonach wird denn entschieden welches Modul da rein kommt und welches nicht? Das muss ja irgendwie mit dem Namen erklärbar sein, wenn der das Thema für dieses Package beschreibt. Verbesserungsvorschlag an der Stelle wäre dieses Package weg zu lassen und den Inhalt in das `securesnapbackup`-Package zu stecken. Dann verschwindet aus allen importen das `….module.…`. Es gibt ja letztlich auch keine im regulären Programmcode die diesen Zwischenschritt nicht drin haben. Was die Unnötigkeit noch mal hervorhebt. Da verschwindet keine Information für den Leser die irgendwas aussagen würde.

Das sieht momentan so aus aus als wäre das ein Modul pro Klasse. Das kann *mal* sinnvoll sein. Wenn das immer so ist, dann werden die Module offensichtlich nicht als Organisationseinheit verwendet. Wenn man immer ein Modul mit dem gleichen Namen hat wie die einzige Klasse die man importiert und verwendet, dann hat man unnötig redundante Importe wo man immer Informationen wiederholen muss, die dem Leser keinen Mehrwert liefern.

Code: Alles auswählen

from securesnapbackup.module.Numerator import Numerator

# Verbesserungsvorschlag:

from securesnapbackup import Numerator
Ich habe nicht gesagt das die Klassen nicht sinnvoll sind, sondern nur das man bei der Struktur der Packages/Module und Namen wie `Numerator` und `DataLoader` den Verdacht oder die Befürchtung haben kann, dass es so „javaesque“ weitergeht.

Mit „normalem Projekt“ meine ich eines was man ganz normal, wie fast alle anderen Projekte da draussen, mit ``pip`` installieren kann. Dann kann man beim installieren entscheiden ob das systemweit, nur für den Nutzer, oder eben in einem venv landet. Letzteres ist mindestens mal beim entwickeln sehr praktisch, weil man dann isoliert ist von dem was sonst noch so auf dem System passiert, und umgekehrt auch das System nicht beeinflusst. Und weil man das nicht nur in *einem* venv installieren kann, sondern auch in mehreren, mit unterschiedlichen Python- und/oder Bibliotheksversionen. Und es löst halt direkt das Problem von diesem Thema hier, das Module nicht gefunden werden, wenn man die halt *installiert*. Dann werden die auch immer gefunden, egal von welchem Verzeichnis aus man das Programm startet. Und auch das Programm selbst ist bei aktiviertem venv von überall aufrufbar.

Übrigens ist es auch kein Problem Programme in venvs über einen Cronjob auszuführen. So etwas mache ich ziemlich häufig. Zum Beispiel auf etwas älteren Systemen, wo ich die Python-Installation vom System nicht durch neuere Packages, die ich gerne verwenden würde, gefährden möchte/darf.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
BrotherJ
User
Beiträge: 7
Registriert: Donnerstag 21. November 2024, 18:35

Vielen Dank, das liest bereits wesentlich besser. Und es dient allen, die hier rein schauen.
Antworten