Automatisierter Import funktioniert nicht.

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
2bock
User
Beiträge: 94
Registriert: Freitag 12. September 2003, 07:58
Wohnort: 50.9333300 / 6.3666700

Hallo Leute,

ich wollte eine __init__.py schreiben, die automatisch alle gefundenen Skripte importiert. Die Routine läuft auch wunderbar durch, ich bekomme aber sobald ich auf eines der Skripte zugreifen möchhte gesagt, das das jeweilige Skirpt nicht importiert wurde.

So ein importierender Skriptname ist z. B . test_1.py

Code: Alles auswählen

import os, os.path, sys, imp, string, time


CONST_TESTPATH = "./py_tests/" #'.'
CONST_TESTFILE_CRITERIA_VALUE = str("*")
CONST_TESTFILE_IDENT = "test_"+CONST_TESTFILE_CRITERIA_VALUE+".py" # Suchschema, Suchkriterium
CONST_ENVIROMENT = {'PYTHONPATH':['./pyscripts/lib','./PyScripts/py_tests','./pyscripts/test_plan','./pyscripts/lib/bacnet','./pyscripts/lib/bacdb','./pyscripts/lib/guicom']}
CONST_SPLIT_VALUE = ";"   # für die Umwandlung von Umgebungsvariablenstring in eine Liste.

DEBUG = 1                 # bei 1 werden ausgaben getätigt, bei 0 nicht.
class TestInit:
    testlist = []
    path = os.path.abspath(CONST_TESTPATH) 
    print path
    importCnt = 0
    failedCnt = 0 
    insertVarCnt = 0
    isVarCnt = 0
     
    def __init__(self):
        sys.path.append(self.path)
        self._checkEnviroment(); # Überprüft die Umgebungsvariablen und setzt diese Notfalls.
        if DEBUG : print "-"*82+"\nStatistik: \n\nUmgebungsvariablen wurden ", self.insertVarCnt," hinzugefügt, ",self.isVarCnt, "waren schon gesetzt.\n\n"
        self._importTests()
        if DEBUG : print "-"*82+"\nStatistik: \n\nNach Schema ",CONST_TESTFILE_IDENT," wurden ", self.importCnt," importiert, ",self.failedCnt, "konntent nicht importiert werden."
       
    def _checkEnviroment(self):
        ''' Überprüft ob Umgebungsvariablen gesetzt sind und wenn nicht , dann wird dies Automatisiert nachgeholt. 
        @params None
        @return None'''
        my_Enviroment  = CONST_ENVIROMENT.keys() # Meine Konstanten für das Sytem.
        act_Enviroment = os.environ.keys()       # aktuelle Systemschlüssel des Systems
        
        for env in act_Enviroment: # holt den PYTHONPATH
            if env in my_Enviroment:
                # Variablen nach denen im System gesucht werden soll und die eingetragen werden sollen.
                u_Var_ValuesList = CONST_ENVIROMENT[env]
                
                # Bereits eingetragene Parameter in den Umgebungsvariablen.
                old_u_Var_ParamsString = os.environ[env]
                u_Var_ParamsList = os.environ[env].split(CONST_SPLIT_VALUE)
                
                newEnviroString = "" # Dieser String wird sptäer i die Umgebundvariablen gesetzt.
                
                for param in u_Var_ValuesList: # Eintrag der einzutragenen Werte.
                    for sysParam in u_Var_ParamsList:
                        if  self.completePaths(param) != os.path.normcase(sysParam):
                            print self.completePaths(param) ," != ", os.path.normcase(sysParam)
                            newEnviroString += self.completePaths(param)+ ";"
                            if DEBUG : print newEnviroString, " ist bereits gesetzt." 
                            self.isVarCnt += 1
                        else:
                            if DEBUG : print "Umgebungsvariablen sind gesetzt."
                            self.insertVarCnt += 1
          
                if newEnviroString != "":
                    os.environ[env] = newEnviroString + ";" + old_u_Var_ParamsString
                    if DEBUG : print os.environ
   
    def completePaths(self, unCompletePath ):
        ''' Erzeugt einen vollständigen Pfad, der später in die Umgebungsvariable eingetragen wird. 
        @params unCompletePath - Pfadfragment.
        @return vollständiger Pfad.'''
        ret = os.path.abspath(os.path.join(self.path,unCompletePath))
        return os.path.normcase(ret)
       
    def _importTests(self):
        ''' Importiert jedes gefundene testskript, das dem Suchkriterium entspricht.
        @params None.
        @return None.'''
        ident = CONST_TESTFILE_IDENT.split(CONST_TESTFILE_CRITERIA_VALUE)
        if len(ident) == 1: # Wenn kein Lueckenfueller angegeben wurde, dann suche auch nicht nach diesem Schema
            ident.append("")
        
        for f in os.listdir(self.path):
            if f.startswith(ident[0]) and f.endswith(ident[1]):
                testFile = f.split('.')[0]
                try:
                    exec 'from ' + testFile + ' import *'	
		            #if DEBUG :print testFile + " erfolgreich importiert"
                    self.importCnt += 1
                except Exception,e:
                    if DEBUG :print "Fehlermeldung: Testfile " , testFile , "konnte nicht importiert werden.", e
                    self.failedCnt += 1
                    #sys.stdout =  'Fehlermeldung: Testfile ', testFile , 'konnte nicht importiert werden.',e
             
#if __name__ == '__main__':
TestInit()
Also woran liegt es, dass ich später nicht mehr auf die Klassen zugreifen kann. Und was wenn ich einen Fehler gemacht habe, kann ich zur Löung dieses Problem machen?

Danke für Eure Hilfe.

Greetz from 2bock ;-)
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Statt exec "import" besser __import__ nehmen. Da kannst du dann auch angeben, in welchen Namensraum das importiert werden soll.

Als Faustregel gilt: immer, wenn du exec benutzt, machst du es falsch. Es gibt ganz ganz wenige Fälle, wo man es braucht.
2bock
User
Beiträge: 94
Registriert: Freitag 12. September 2003, 07:58
Wohnort: 50.9333300 / 6.3666700

Ich versuche nun in meinem Skript die Skripte mit folgender Methode zu importieren.

Code: Alles auswählen

def _import(package, module_name):
            return __import__(
               "%s.%s" % (package,module_name),
                globals(), locals(),
                [module_name]
            )
Doch wenn ich nachher auf diese Importierten Klassen zugreifen möchte, erhalte ich folgende Tracebackmeldung. NameError: name 'xy' is not defined.

Gruß 2bock
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Du must den import auch an den Namen binden. Zeig mal wie du die Methode _import() aufrufst...

btw. warum machst du das überhaupt alles so komisch?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
2bock
User
Beiträge: 94
Registriert: Freitag 12. September 2003, 07:58
Wohnort: 50.9333300 / 6.3666700

Hallo Jens.

Mein Ziel ist es aus einem Verzeichnis alle Skripte einzulesen, die mit test_ beginnen. Diese Skripte möchte ich dann importieren, damit ich später über ein anderes Modul diese nutzen kann. Ich will jetzt hier nicht wieder unnötig den gesammten Code reinhacken (den habe ich hier ja schon), deswegen setzte ich hier nur nochmal die _importTests Mehtode rein. Sonst habe ich nix geändert.

Code: Alles auswählen

def _importTests(self):
        ''' Importiert jedes gefundene testskript, das dem Suchkriterium entspricht.
        @params None.
        @return None.'''
        
        def _import( module_name):
	    print  module_name
            return __import__(
               "%s.%s" % (module_name),
                globals(), locals(),
                [module_name]
            )
        
        ident = CONST_TESTFILE_IDENT.split(CONST_TESTFILE_CRITERIA_VALUE)
        if len(ident) == 1: # Wenn kein Lueckenfueller angegeben wurde, dann suche auch nicht nach diesem Schema
            ident.append("")
        
        for f in os.listdir(self.path):
            if f.startswith(ident[0]) and f.endswith(ident[1]):
                testFile = f.split('.')[0]
                try:
		     #__import__(testFile,globals(),locals())
                   _import(testFile)
                    #exec 'from ' + testFile + ' __import__ *'	
		            #if DEBUG :print testFile + " erfolgreich importiert"
                   self.importCnt += 1
                except Exception,e:
                   if DEBUG :print "Fehlermeldung: Testfile " , testFile , "konnte nicht importiert werden.", e
                   self.failedCnt += 1
P.S.: Danke für Deine Hilfe Jens ;-)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ah ok... Du machst ja nur ein _import(testFile) Damit wird zwar das Modul importiert, aber der import wird IMHO an keinem Namen gebunden.

Also wenn du import xyz machst, ist ein Objekt xyz vorhanden... Wenn du aber __import__("xyz") machst dann nicht, denn du müßtest es so machen: xyz = __import__("xyz")

Du könntest einfach eine Liste machen in der du die Module "einfügst":

Code: Alles auswählen

modules = []
for f in os.listdir(self.path):
    ...
    try:
        module = _import(testFile)
    except:
        ...blabla...
    else:
        modules.append(module)
Wie du das Module aber in den richtigen Namensraum bekommst, weiß ich spontan nicht... Aber ich denke mit der Liste bist du eh besser dran :)

EDIT: btw. versuchst du einen unitest zu bauen oder so?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
2bock
User
Beiträge: 94
Registriert: Freitag 12. September 2003, 07:58
Wohnort: 50.9333300 / 6.3666700

Ja geht so in die Richtung, aber die Testskripte sind alle quasi schon fertig und ich will mir die __init__.py mit den ca. 3.000 "from x import *" schenken und das etwas dynamisieren.

Das mit dem NAmensraum ist echt blöd. Habe mal mit der Namensraum sache experimentiert und hab scheinbar ein großes Problem. Mist.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wenn du ein Modul importiert hast, was soll dann passieren???

Man könnte sicherlich mit setattr arbeiten: http://docs.python.org/lib/built-in-funcs.html#l2h-64
Dann kannst du das Modul an einen Namen binden.

Vielleicht müßte man auch nur __all__ erweitern???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Vielleicht interessiert dich ja der PluginController von What's On Air, der Alle Module aus einem parsers-Ordner importiert und dann in einer netten Wrapper-Klasse bereitstellt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
2bock
User
Beiträge: 94
Registriert: Freitag 12. September 2003, 07:58
Wohnort: 50.9333300 / 6.3666700

Hier eine Lösung für alle, die das selbe Prob haben. Man kann in den __builtins__ rumfuhrwerken. Ich habe diesen Weg dann sein lassen. Einfachste Lösung, die ich in all der Rage total übersehen hatte.

exec() reicht völlig aus. Nur man muß beachten, dass der exec import nicht innerhalb einer Klasse durchgeführt wird. Dann funktionierts.

*heul* Hab so festgefahren gedacht, dass ich das offensichtlichste übersehen hatte.

Greetz from 2bock ;-)
Antworten