Python Frage zu Import Problemen

Falc410

Vice Admiral
Registriert
Juni 2006
Beiträge
6.613
Hallo,

ich habe hier ein Projekt übernommen und bin kein Python Profi. Nun wollte ich die Struktur ein wenig verändern, aber nun klappen Imports nicht mehr (und ich muss noch jede Menge absolute Pfade in relative ändern, aber das ist ein anderes Thema).

Ich habe folgende Struktur:
Code:
root/
	__init__.py
	start.py

	conf/
		__init__.py
		config.txt
	entity/
		__init__.py
		entityX.py
	util/
		utilY.py
		utilZ.py
Vorher lag utilZ.py im gleichen Verzeichnis wie start.py (also im working dir sozusagen) und hat folgende Zeile:
from entity import entityX
Nachdem ich utilZ.py verschoben habe klappt das natürlich nicht mehr. Laut StackOverflow sollte es so klappen:
from ..entity import entityX

Dann kommt aber: ValueError: Attempted relative import in non-package.

Wie macht man das nun am saubersten?
 
Zuletzt bearbeitet:
Meiner Meinung nach müßte

import entity.entityX

funktionieren.

P.S. Dazu muß das entity-Verzeichnis allerdings entweder ein Kind des selben Verzeichnisses sein, das auch dein Haupt-Skript (start.py) enthält, oder das Elternverzeichnis des entity-Verzeichnisses muß zu den Pfaden hinzugefügt werden, in denen Python nach Modulen sucht.

2. P.S. Aus deiner Verzeichnisstruktur wird man so nicht so richtig schlau. Ich würde dir empfehlen, das in Code-Tags zu packen und pro Verzeichnis-Ebene einmal einzurücken, damit das klarer ersichtlich wird:

Code:
root/
	__init__.py
	start.py

conf/
	__init__.py
	config.txt
entity/
	__init__.py
	entityX.py
util/
	utilY.py
	utilZ.py

Ist das so korrekt?
 
Zuletzt bearbeitet:
Leider nicht, ImportError: No module named entity.entityX
Ergänzung ()

Den PYTHON PATH kann ich nicht anpassen. Das Problem ist das start.py zwar einzelne Module starten soll, zum testen will ich die aber auch direkt aus util/utilY z.B. starten. Je nachdem wer von wo das startet kann ich anscheinend das es funktioniert oder eben nicht.

Das ist mal total verwirrend und unlogisch. Ich hatte gehofft das man wie bei Java Packages definieren kann, aber das geht wohl nicht.

Also entweder ich biege es so um das start.py alles starten kann, dafür die Module aber nicht mehr einzeln betrieben werden können, oder ich muss alles in ein Verzeichnis klatschen. Was auch unschön ist (da wir natürlich noch ein paar mehr Klassen haben als wie beschrieben).

Edit: Der hat mir im Editor die Verzeichnisse richtig eingerückt aber ohne Code Tags die Tabs wieder rausgelöscht. Habs ausgebessert.
 
Zuletzt bearbeitet:
Ich weiß nicht, wie Java das handhabt, aber Python sucht nach Modulen entweder ausgehend vom Ordner, in dem das Skript liegt, oder in den Pfaden, die PYTHONPATH hinzugefügt worden.
Der verlinkte Stackoverflow-Artikel zeigt ja auch noch 2 andere Möglichkeiten, die Pyhon-Suchpfade zu ändern (site.addsitedir und Modfizieren der sys.path-Variablen). Damit könntest du eventuell dynamisch zur Laufzeit den Pfad erweitern, wenn du feste Annahmen darüber machst, wo die Module relativ zum aktuellen main-Skript liegen.
 
Danke dir, ich denke über sys.path müsste es klappen! Das probiere ich gleich mal aus.
 
Falc410 schrieb:
Ich hatte gehofft das man wie bei Java Packages definieren kann, aber das geht wohl nicht.

Das hier hatte ich übersehen. Ein Package ist in Python einfach ein Verzeichnis, das 1 oder mehrere Python-Module enthält. Dein entity-Verzeichnis ist also ein Package.
Ergänzung ()

Falc410 schrieb:
Edit: Der hat mir im Editor die Verzeichnisse richtig eingerückt aber ohne Code Tags die Tabs wieder rausgelöscht. Habs ausgebessert.

Hmm, jetzt wo ich deine korregierte-Verzeichnisstrukur sehe, müßte zumindest aus start.py heraus der import mit

import entity.entityX

eigentlich klappen. Funktioniert das wirklich nicht?? :confused_alt:
 
Doch doch, start.py funktioniert einwandfrei, aber wenn ich in utilX nun ein from entity import X mache dann geht das nur wenn utilX auch von start.py aufgerufen wird. Wenn ich direkt python util/utilX.py starte dann geht es nicht mehr.

Ich wollte einfach die bisherige Projektstruktur ein wenig anpassen aber hatte nicht erwartet das es so einen Rattenschwanz an Veränderungen nachziehen würde. Ich müsste jetzt sicher 50 Dateien refactoren um das wieder zum laufen zu bekommen. Am einfachsten wäre es alle Dateien in einen Ordner zu werfen aber ist ja auch nicht Sinn der Sache.
 
Hast du auch os importiert? Ansonsten klappt sys.path nicht.
 
Cool Master schrieb:
Hast du auch os importiert? Ansonsten klappt sys.path nicht.

Meinst du nicht sys?
Ergänzung ()

Falc410 schrieb:
Doch doch, start.py funktioniert einwandfrei, aber wenn ich in utilX nun ein from entity import X mache dann geht das nur wenn utilX auch von start.py aufgerufen wird. Wenn ich direkt python util/utilX.py starte dann geht es nicht mehr.

Ah ja, verstanden. FRAGE: Warum kannst du PYTHONPATH eigentlich nicht verändern?
 
Nein ich meinte schon os :)

Steht doch aber auch in dem Link von dir:

However, when you're using something that just runs on your own computer (or when you have nonstandard setups, e.g. sometimes in web app frameworks), it's not entirely uncommon to do something like

Code:
from os.path import dirname
sys.path.append(dirname(__file__))
 
Die Software muss auf verschiedene Systemen installiert werden auf denen ich keinen Zugriff erhalte. Im Moment funktioniert es weil extrem viele Pfade hard-gecoded sind, d.h. wir müssen den Admins vorschreiben wohin sie das Programm zu installieren haben.

Ich wollte das jetzt ein wenig flexibler gestalten und gleichzeitig mehr Ordnung schaffen. Denn im Moment befinden sich leider im root working dir nicht nur start.py sondern noch jede Menge andere python Dateien die da eigentlich nichts zu suchen haben und die Admins nur verwirren könnte. Aber ich seh schon, das ist ein grösseres Projekt.

edit: Das man ein import os braucht ist schon klar. Der Fehler wird auch direkt in meiner IDE angezeigt :)

Ich habe vorhin auch einen Bug behoben da ein anderer Entwickler os.getcwd() für das aktuelle Verzeichnis gehalten hat. Ich habe mich immer gewundert warum ich erst ein cd programm und dann python start.py machen musste und warum python programm/start.py nicht geklappt hat. Hab das dann durch os.path.dirname(os.path.abspath(__file__)) ersetzt und schon gehts.

Aber bis man als unerfahrerner Python Entwickler auf sowas kommt dauert es dann doch 1-2h.
 
Zuletzt bearbeitet:
Falc410 schrieb:
d.h. wir müssen den Admins vorschreiben wohin sie das Programm zu installieren haben.

Und was ist da so schlimm dran?
 
Cool Master schrieb:
Nein ich meinte schon os :)

Steht doch aber auch in dem Link von dir:



Code:
from os.path import dirname
sys.path.append(dirname(__file__))

Das os brauchst du in dem Fall für die os.dirname-Funktion. Die sys.path-Variable kommt aus dem sys.
Ergänzung ()

Falc410 schrieb:
Die Software muss auf verschiedene Systemen installiert werden auf denen ich keinen Zugriff erhalte. Im Moment funktioniert es weil extrem viele Pfade hard-gecoded sind, d.h. wir müssen den Admins vorschreiben wohin sie das Programm zu installieren haben.

Man muß die PYTHONPATH-Variable nicht unbedingt systemweit ändern. Man könnte zum Beispiel eine Art bootstrap-Mechanismus davorschalten, der in einem Batch-File (oder auch einem Python-Skript!) erst mal die PYTHONPATH-Variable (eben nur für den aktuellen Prozess) modifziert und dann das Python-Skript startet.

Letzten Endes wäre das aber eigentlich das gleiche, wie sys.path zur Laufzeit zu ändern ... nimmt sich wohl nicht viel. :)
 
Zuletzt bearbeitet:
Ja, daran habe ich auch gedacht. Vorher noch ein shell skript welches ein EXPORT macht. Allerdings muss ich das auch erst noch durchtesten, da einzelne Submodule über ein Python Library Namens zdaemon, als Daemon laufen. Und ich bin nicht sicher wie das genau funktioniert da es zu diesem zdaemon leider so gut wie keine Doku gibt (bis auf das hier https://pypi.python.org/pypi/zdaemon? ). Anscheinend benutzt das auch kein Schwein ausser wir :)
Ergänzung ()

Cool Master schrieb:
Und was ist da so schlimm dran?

Im Moment muss ich damit rechnen für jedes Land eine Anpassung machen zu müssen, da Land X besondere Regeln hat und Land Y wieder andere. Um mir den Aufwand zu ersparen sollte es eben flexibel sein. Ich empfinde das auch als besseres Softwaredesign. Erleichtert ja auch die Bug-Suche wenn man auf relative Pfade anstatt auf absolute setzt.
 
Zurück
Oben