2009-04-22 14 views
65

Ich schreibe ein Python-Paket mit Modulen, die Datendateien in einem ./data/ Unterverzeichnis öffnen müssen. Im Moment habe ich die Pfade zu den Dateien in meinen Klassen und Funktionen fest codiert. Ich möchte robusteren Code schreiben, der auf das Unterverzeichnis zugreifen kann, unabhängig davon, wo es auf dem System des Benutzers installiert ist.Python-Zugriffsdaten im Paket Unterverzeichnis

Ich habe eine Vielzahl von Methoden ausprobiert, aber bisher hatte ich kein Glück. Es scheint, dass die meisten der "aktuellen Verzeichnis" -Befehle das Verzeichnis des Python-Interpreters des Systems und nicht das Verzeichnis des Moduls zurückgeben.

Dies scheint wie ein triviales, häufiges Problem zu sein. Aber ich kann es nicht herausfinden. Teil des Problems ist, dass meine Dateien nicht .py Dateien sind, so dass ich keine Importfunktionen und dergleichen verwenden kann.

Irgendwelche Vorschläge?

Gerade jetzt mein Paketverzeichnis wie folgt aussieht:

/ 
__init__.py 
module1.py 
module2.py 
data/ 
    data.txt 

I data.txt von module*.py

Dank zugreifen bin versucht!

Antwort

24

Sie können mit Unterstrich-underscore- Datei-Unterstrich-Strich (__file__) den Pfad zu dem Paket zu erhalten, wie folgt aus:

import os 
this_dir, this_filename = os.path.split(__file__) 
DATA_PATH = os.path.join(this_dir, "data", "data.txt") 
print open(DATA_PATH).read() 
+24

Dies funktioniert nicht, wenn die Dateien in einer Distribution (IE. Ei) sind. Verwenden Sie pkg_resources, um an die Datendatei zu gelangen. – Chris

+0

In der Tat ist das kaputt. – Federico

6

Ich glaube, ich habe eine Antwort gesucht.

Ich mache ein Modul data_path.py, die ich in meinen anderen Modulen importieren enthält:

data_path = os.path.join(os.path.dirname(__file__),'data') 

Und dann öffne ich alle meine Dateien mit

open(os.path.join(data_path,'filename'), <param>) 
+0

Dies funktioniert nicht, wenn sich die Ressource in einer Archivverteilung befindet (z. B. ein gezipptes Ei). Bevorzugen Sie so etwas: 'pkg_resources.resource_string ('pkg_name', 'data/file.txt')' – ankostis

+0

@ankostis setuptools ist schlau genug, um das Archiv zu extrahieren, wenn es erkennt, dass Sie '__file__' irgendwo benutzt haben. In meinem Fall verwende ich eine Bibliothek, die wirklich Pfade und keine Streams will. Natürlich könnte ich die Dateien temporär auf die Festplatte schreiben, aber faul benutze ich einfach die Funktion von setuptools. – letmaik

95

Die Standardmethode hierfür ist setuptools packages und pkg_resources.

Sie können Ihr Paket nach der folgenden Hierarchie anlegen und konfigurieren Sie das Paket Setup-Datei es Ressourcen, um Ihre Daten zu zeigen, wie pro diesen Link:

http://docs.python.org/distutils/setupscript.html#installing-package-data

Sie können dann wieder finden und verwenden, um diese Dateien pkg_resources, gemäß diesem Link:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources 

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/') 
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db') 
+0

Ich denke, dass dies der bevorzugte Weg ist, ich bin mir nicht ganz sicher warum, aber Projekte zeigen Warnungen, wenn Sie auf das Paket/Modul mit '__file__' verweisen. – lukecampbell

+1

Wird * pkg_resources * keine Laufzeitabhängigkeit von * setuptools * erzeugen? Zum Beispiel verteile ich ein Debian-Paket neu, warum würde ich nur deshalb von 'python-setuptools' abhängen? Bisher funktioniert '__file__' für mich. – mlt

+3

Warum das besser ist: Die ResourceManager-Klasse bietet einheitlichen Zugriff auf Paketressourcen, unabhängig davon, ob diese Ressourcen als Dateien und Verzeichnisse existieren oder in einem Archiv einer Art komprimiert sind. – vrdhn

11

zu stelle eine Lösung zur Verfügung, die heute funktioniert. Verwenden Sie diese API definitiv, um nicht alle diese Räder neu zu erfinden.

Ein echter Dateiname wird benötigt. Gezippte Eier werden in ein Cache-Verzeichnis extrahiert:

from pkg_resources import resource_filename, Requirement 

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Gibt ein lesbares dateiähnliches Objekt für die angegebene Ressource zurück; Es kann eine tatsächliche Datei, ein StringIO oder ein ähnliches Objekt sein. Der Stream befindet sich im "Binärmodus", in dem Sinne, dass die Bytes, die in der Ressource enthalten sind, unverändert gelesen werden.

from pkg_resources import resource_stream, Requirement 

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png") 

Paketermittlung und Ressourcenzugriff mittels pkg_resources

3

Sie müssen einen Namen für das gesamte Modul, sind Sie Verzeichnisbaum angegeben nicht Liste dieses Detail, für mich hat das funktioniert:

import pkg_resources 
print( 
    pkg_resources.resource_filename(__name__, 'data/data.txt') 
) 

NoticeTogetools scheint nicht Dateien auf der Grundlage einer Namensübereinstimmung mit gepackten Datendateien aufzulösen, so müssen Sie die Präfix ziemlich egal was enthalten. Sie können os.path.join('data', 'data.txt) verwenden, wenn Sie alternative Verzeichnisseparatoren benötigen. Im Allgemeinen finde ich keine Kompatibilitätsprobleme mit hartcodierten Unix-Stil-Verzeichnisseparatoren.

Verwandte Themen