Fragen zu eigenen Paketen

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
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Hi, es gibt eine Menge Tutorials, aber die Antworten auf die folgenden Fragen habe ich bislang nicht gefunden.

Bislang arbeite ich alleine an meinen "Paketchen". Sie sind nichts bedeutendes, sondern haben im Grunde nur unternehmensweite Bedeutung.
Inzwischen wächst das Team und ich muss mir Gedanken drüber machen, wie ich Code "sauber" weitergeben kann.

Fragen:

1. Wie kann ich Module "quer" importieren?
Beispiel:

Paket XYZ
- Unterpaket A, Module A1, A2, A3 ...
- Unterpaket B, Module B1, B2, B3 ...

Wie kann ich im Modul B1 über relativen Import Funktionen von A1 importieren?
(Beispielsweise könnte Unterpaket A alle möglichen Funktionen/Klassen enthalten, die mit der Datenbeschaffung zu tun haben, Unterpaket B alle Funktionen/Klassen die mit dem Generieren von Reporten zu tun haben)

2. Wie kann ich Module am Besten "Importierbar" weitergeben?

Die Module kommen nicht irgendwo ins Internet, sondern befinden sich auf Unternehmensverzeichnissen. Im Moment gibt es dafür auch noch keine Quellcode- Verwaltung, Vorschläge wären toll.
Mir ist klar, dass jedes Verzeichnis eine "init.py" enthalten muss. Ich weiß auch, dass man eine setup.py dazulegen kann, aber da wird es schon ungenauer mit meinem Wissen.

Also angenommen, ich habe das Paket XYZ mit den oben beschriebenen Unterpaketen A und B auf meinem Rechner entwickelt. Was genau muss ich noch tun, damit der zweite Partner diese Pakete (nicht manuell mit Copy und Paste, sondern über PIP oder irgendeinen anderen Paketinstallierer) installieren kann? Wie genau deklariere ich, welche Abhängigkeiten zu anderen Paketen existieren?

Wenn jemand ein Tutorial kennt, das diese Fragen beantwortet, dann wäre das natürlich auch hilfreich. (Allerdings nützten mir die meisten Tutorials bislang nichts, da sie genau da begannen zu schweigen, wo die eigentlichen Fragen auftauchten...)

Vielen Dank!
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Zu 1: warum geht das nicht? So wie beschrieben sollte doch ein

from ..B.B1 import wasauchimmer

funktionieren. Vielleicht mit ...B oder so, aber prinzipiell sollten alle Module innerhalb eines Paketes sich relativ importieren koennen.

Zu 2: pip und andere kann HTML-Seiten mit bestimmten Strukturen verstehen, und die durchsuchen. Oder auch Verzeichnisse. Siehe https://packaging.python.org/en/latest/ ... own-index/.

Dazu sollten die in einem git-repository verwaltet, und bei einem neuen Release als source-dist-package erzeugt und dann in die Verzeichnisse oder auf den HTTP server kopiert werden: https://docs.python.org/3/distutils/sourcedist.html

Wie man Abhaengigkeiten definiert steht zb hier: https://packaging.python.org/en/latest/ ... -projects/
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PyGuest: Zur ersten Frage: Ich würde gar nicht relativ importieren sondern einfach immer absolut, also ``from XYZ.A.A1 import some_function``.

Zur `setup.py` steht einiges in der Python-Dokumentation selbst. Da gibt es „Installing Python Modules“ und „Distributing Python Modules“ auf der Einstiegsseite der Dokumentation.

In der Python-Dokumentation wird auch der externe Python Packaging User Guide verlinkt. Da gibt's auch Tutorials und Guides.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

__deets__ hat geschrieben: Mittwoch 25. Mai 2022, 11:34 Zu 1: warum geht das nicht? So wie beschrieben sollte doch ein

from ..B.B1 import wasauchimmer

funktionieren. Vielleicht mit ...B oder so, aber prinzipiell sollten alle Module innerhalb eines Paketes sich relativ importieren koennen.
Fehlermeldung: attempted relative import beyond top-level package
__blackjack__ hat geschrieben: Mittwoch 25. Mai 2022, 11:36 @PyGuest: Zur ersten Frage: Ich würde gar nicht relativ importieren sondern einfach immer absolut, also ``from XYZ.A.A1 import some_function``.
Warum? Das erschwert zumindest mal die Entwicklung des Paketes selbst. Notfalls wäre es so, aber mich wundert es, dass python so etwas nicht können sollte.

Mein Urlaub beginnt genau jetzt, ich schau am Montag mal rein, was geht.

Vielen Dank Euch beiden.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PyGuest: Weil man dann immer genau weiss was da importiert werden soll. Explicit is better than implicit. Es hält auch die Hierarchie flach, weil man so nicht auf die Idee kommt 10 Ebenen an Subpackages zu erstellen. Und warum erschwert das die Entwicklung des Paketes?

Die Fehlermeldung deutet darauf hin, dass `XYZ` nicht im Suchpfad ist, sondern das `A` dort zu finden ist. Zum Beispiel weil Du da was ausführst während `XYZ` das aktuelle Arbeitsverzeichnis ist. Falls `XYZ` nicht installiert ist, muss das Elternverzeichnis von `XYZ` das aktuelle Arbeitsverzeichnis sein. Das darf niemals *in* einem Package oder Subpackage stehen, denn dann ist Chaos angesagt weil Module dann entweder gar nicht, oder über mehrere Wege erreichbar sind.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

PyGuest hat geschrieben: Mittwoch 25. Mai 2022, 11:56
__deets__ hat geschrieben: Mittwoch 25. Mai 2022, 11:34 Zu 1: warum geht das nicht? ...
Fehlermeldung: attempted relative import beyond top-level package
Na dann hast du das aber nicht korrekt dargestellt. Du schriebst, dass beide unterhalb des *Packages* xyz stecken. Wenn das nicht der Fall ist, dann geht's natuerlich nicht. Der Python import Mechanismus ist kein generischer Pfad-Traversierer.

Und ich sehe auch nicht, wo da der Gewinn waere. Wenn du so weit raus reichen musst, dann steht da doch eh das top-Level Paket wieder im Pfad, was ist denn der Gewinn, da noch lauter Punkte vorzupacken?

Code: Alles auswählen

# Module foo.bar.baz
from ...egal.was.anderes import x # was du willst
from egal.was.anderes import x   # was geht.
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Hi,

tut mir leid, dass es so lange gedauert hat. Aber inzwischen habe ich - auch dank Eurer Tipps und dem daraus resultierenden Mut zur Beharrlichkeit - einiges herausgefunden. Mag sein, dass Euch das klar und banal ist, mir war es das nicht und somit habe ich den Fehler an der falschen Stelle gesucht.
Meine Module waren schon so, wie beschrieben. Allerdings hatte ich in einem der Module so eine Art SelbstTest- Funktion eingebaut, an der ich das ausprobiert habe. Wenn ich dieses Modul nun gestartet habe und die Funktion aufrief, dann hat Python nicht in den Pfaden geschaut, weil es dieses Modul nicht als Bestandteil eines Packages interpretiert hat. Und einfach so durch die Verzeichnisse zu gehen - das ist anscheinend (und sicher aus gutem Grund) nicht vorgesehen.

Eine gute Erklärung dafür fand ich hier:
https://qastack.com.de/programming/1413 ... ionth-time

Wenn ich von irgendwo eine Funktion aus dem Package aufrufe, die in Package "relativ" hin und her wandert, dann geht das sehr wohl. Ich denke, dass habt ihr gemeint bzw. das war Euch klar, mir aber nicht.

Code: Alles auswählen

#Datei A1.py
def A1():
	print ("A1")
	
#Datei B1.py
def B1():
	print("B1")
	
#Datei B2:
from .B1 import B1
from ..A.A1 import A1
def B2():
	A1()
	B1()
	print("B2")
wenn ich jetzt das Modul B2 im Editor öffne und ausführe, dann klappt das nicht.
Wenn ich hingegen eine andere Datei in meinem Editor öffne, dann geht das.

Code: Alles auswählen

#Datei Irgendwo.py
sys.path.append('c:\meine_lieblingspakete')
from XYZ.B.B2 import B2
B2()
Dann geht das ohne Probleme

Warum nun überhaupt den "Unfug" mit relativen Pfaden? Bislang habe ich mehr oder weniger kleinere Spielzeuge nur für mich geschrieben. Es war schon hinreichend lästig, dass man unfertige Module/Pakete nicht so ohne weiteres von überall aus nutzen konnte, aber mit einem

Code: Alles auswählen

sys.path.append()
ließ sich das dann doch alles bewerkstelligen.
Nun ist es so, dass noch zwei weitere Kolleg*innen auf den Plan getreten sind. Jede*r hat zwar andere Aufgaben und Projekte, aber es gibt durchaus zentrale Elemente, für die es sinnvoll ist, nur einmal Energie zu investieren (z.B. eine zweckmäßige Ausgestaltung des Loggings, diverse mathematische Spezialfunktionen oder den Zugriff auf bestimmte Datenbanken/Datenquellen). Und um hier möglichst unabhängig arbeiten zu können - jede*r entwickelt, was er braucht und wenn er eine "passende" Version hat, dann stellt mensch sie an eine zentrale Stelle - dafür ist es sinnvoll, den Namen des Paketes nicht vorgeben zu müssen. (Mir ist klar, dass das keine Quellcodeverwaltung/Versionskontrolle etc. darstellt, aber da ich im Moment keine passende leichtgewichtige Variante kenne, ist das m.E. problemangemessen)
In Realität läuft das also so, dass ich ein Paket "mein_paket" mit diversen subpaketen bastle und wenn etwas fertig ist, dann wird es in "unser_paket" hineinkopiert und funktioniert wie von Geisterhand.

Ich weiß, ich bekomme jetzt Schelte, aber noch mal zur Erinnerung: Meine (bzw. unsere) Aufgabe(n) bestehen darin, bestimmte Probleme zu lösen, die Nutzung von Python ist dabei nur eine Erleichterung, nicht Kernaufgabe. Daher kann dort auch nur soviel Energie investiert werden, dass es sich noch lohnt. Es würde sich ja auch keiner eine Fabrikhalle hinstellen, weil er zwei mal im Jahr einen Stuhl bauen muss. Säge und Akkuschrauber müssen dann reichen.

Ich hoffe, ihr bereut Eure Hilfe nicht. Ich bin jedenfalls dankbar und es wird sicher nicht meine letzte Frage sein.
Falls ihr einen guten Tip für eine "leichte" Quellcode- Verwaltung mit Versionskontrolle habt, die idealerweise nicht installiert werden muss und datei-/verzeichnisbasiert arbeitet und vorzugsweise irgendwie Pakete bauen kann, die man ohne Umweg über das Internet weitergeben kann - ich bin gern bereit.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@PyGuest: Wie gesagt, man darf keine Module direkt als Datei ausführen, die in einem Package sind. Das gibt Chaos. Dafür gibt es die ``-m``-Option um Module in Packages als Programm auszuführen: ``python -m XYZ.B.B2``. `XYZ` muss im Suchpfad für Module sein.

Was man auch eher nicht mit `sys.path.append()` macht, sondern in dem man das installiert. Installieren kann auch bedeuten, dass es an der Stelle bleibt wo man den Quelltext stehen hat und der bleibt auch bearbeitbar. ``pip`` hat da Optionen für. Damit kann man dann an einem installierten Package programmieren, ohne das man irgendwo in Verzeichnissen Änderungen vornehmen muss, von denen man die Finger lassen sollte.

Ist Git eine einfache Versionsverwaltung? Das ist momentan der Standard. Falls man nur eine Versionsverwaltung lernen will, ist das IMHO Git, weil das so gut wie jeder verwendet. Die Chancen das man das irgendwann mal braucht sind hoch, und die Chancen das irgendein zufällig gewählter Programmierer das schon kennt, sind ebenfalls hoch.

Ich persönlich setze aus historischen Gründen noch viel Mercurial ein, und weil es mit TortoiseHg ein vergleichbares Programm zu TortoiseSVN für Subversion gibt, wo ich noch nichts (kostenloses) passendes als Ersatz für Git gefunden habe.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich sehe keinen Grund, warum das gewählte Vorgehen zu der beschriebenen Konsequenz führt. Es ist trivial entweder dem einzelnen Entwickler eines unterpaketes abzuverlangen, ein Verzeichnis mit dem allgemeinen namespace Paketnamen zu benutzten bei der Entwicklung. Das führt zu keiner signifikanten Einschränkung. Alternativ kann jeder mit einem toplevel Paketnamen arbeiten, also zb peter, maria, mustafa, und nur das Verzeichnis darüber wird in den sys.path gepackt. Schon kann man “from mustafa import algorithmus” ausführen.

Die eierlegende Wollmilchsau einer nicht zu installierenden und trivial zu benutzenden Quellcodeverwaltung ist mir nicht bekannt. Aus meiner Sicht ist außer git eigentlich nichts mehr zu empfehlen, und das funktioniert auch für einen solchen Fall dank seiner verteiltheit gut mit einem lokalen “ich update meinen Code” und dann einem “das zentrale Repo auf einem Netzlaufwerk wird auf stand gebracht” Arbeitsfluss.
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Gut, dann werde ich mich mal mit git beschäftigen.
Allerdings habe ich keine Option bei pip gefunden, ein lokales Verzeichnis (Netzlaufwerk o.ä.) als Quelle anzugeben. Hat da jemand Erfahrungen?
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

also ich finde da so einiges: https://stackoverflow.com/questions/150 ... v-with-pip

Generell ist das Konzept der "Index", den man auch anderweitig hosten kann, und per Kommandozeile oder sogar Konfiguartionsdatei wenn ich mich recht erinnere einfach setzen.
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Kaum macht man's richtig ...
ich habe zwar probiert

Code: Alles auswählen

pip --help
aber nicht

Code: Alles auswählen

pip install --help
Das schaue ich mir auch mal an. Scheint das zu sein, was ich brauche.
PyGuest
User
Beiträge: 28
Registriert: Mittwoch 25. Mai 2022, 10:57

Vielen Dank für Eure Hilfen.
Habe jetzt auch mal ein paar Experimente mit pip install und setup.py gemacht und ich vermute mal, dass ich auf dem richtigen Weg bin.

Wenn ich mich da durchgewurstelt habe, dann werde ich mal meine Erfahrungen hier etwas ausführlicher zu Forum bringen.
Antworten