scope von exec 'string' in globals() ??

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
bossi

Wenn ich folgende Funktion:

Code: Alles auswählen

def setup():
    exec 'foo=5' in globals()
und auch

Code: Alles auswählen

setup()
foo
ist die Shellantwort:
5
Dies ist auch zu erwarten, und das ist was ich möchte.
Wenn ich nun aber die selbe Setup-Funktion in ein File Test.py schreibe und folgenden Code in eine (neue) Shell eingebe:

Code: Alles auswählen

from test import *
setup()
test
kriege ich folgende Fehlermeldung:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'test' is not defined
Was ist der Unterschied. Was muss ich machen damit dies auch bei Modulefunction functioniert???

Gruss,

Bossi
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

globals() bezieht sich immer auf das momentane Modul, welches durch die Definition der Funktion bestimmt ist (also in Deinem Fall das importierte Modul).

Wenn Du es in einem anderen Modul definieren willst mittels exec, dann muß setup() als Parameter das Pseudodict globals() mitkriegen.

Ganz davon abgesehen: was willst Du eigentlich machen? exec ist böse, und nur um eine Variable in einem anderen Modul zu setzen noch viel mehr.

Schon mal mit globals probiert?

--- Heiko.
Gast

Ich gab natürlich nicht
bossi hat geschrieben:

Code: Alles auswählen

from test import *
setup()
test
kriege ich folgende Fehlermeldung:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'test' is not defined
ein sondern:

Code: Alles auswählen

from test import *
setup()
foo
kriege ich folgende Fehlermeldung:
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name 'foo' is not defined
Gruss,
Bossi
Gast

modelnine hat geschrieben: Wenn Du es in einem anderen Modul definieren willst mittels exec, dann muß setup() als Parameter das Pseudodict globals() mitkriegen.
--- Heiko.
Das habe ich leider nicht verstanden. Gibt es globals().setup() ?? Ich mochte ein Object im global namespace erzeugen.
modelnine hat geschrieben: Ganz davon abgesehen: was willst Du eigentlich machen? exec ist böse, und nur um eine Variable in einem anderen Modul zu setzen noch viel mehr.

--- Heiko.
Ich möchte neue Function von einem zentralen messserver verschicken. die funktion werden dann wieder auf dem mess-server ausgeführt.

besten dank für die Hilfe
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Schaue er sich sys._getframe an
TUFKAB – the user formerly known as blackbird
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Ich möchte neue Function von einem zentralen messserver verschicken. die funktion werden dann wieder auf dem mess-server ausgeführt.
Du empfängst also eine Datei von einem Server mit einem Client, und möchtest die Datei ausführen. Da ist Dein Modulgedanke doch gar nicht schlecht. Dann definier doch einfach in der importierten Datei entsprechende Funktionen die Du aus dem Hauptprogramm aufrufst um das Messverfahren zu starten.

Also sowas:

main.py

Code: Alles auswählen

import meinmessverfahren

meinmessverfahren.setup()

def start():
    print "Ich brauche", meinmessverfahren.eier, "Eier"
    print "Und ich brauche", meinmessverfahren.mehl, "kg Mehl"
    print "Und jetzt kann ich backen."

start()
meinmessverfahren.py

Code: Alles auswählen

# Standardglobals.
eier = 15

def setup():
    global mehl

    mehl = eier/30.0
Wenn Du messverfahren.py austauscht, dann startest Du einfach das Messscript neu, es importiert das Messverfahren und startet es.

Aber: ohne dass Du irgendwelchen Code den Du zu gebrauchen denkst postest ist es unheimlich schwierig was dazu zu sagen.

--- Heiko.
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Und schaue er sich nicht sys._getframe an; das führt nur zu Spaghetticode außer er braucht es umbedingt. Sorry blackbird. ;-)

--- Heiko.
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

modelnine hat geschrieben:Und schaue er sich nicht sys._getframe an; das führt nur zu Spaghetticode außer er braucht es umbedingt. Sorry blackbird. ;-)

--- Heiko.
8)
TUFKAB – the user formerly known as blackbird
Gast

modelnine hat geschrieben:
Aber: ohne dass Du irgendwelchen Code den Du zu gebrauchen denkst postest ist es unheimlich schwierig was dazu zu sagen.

--- Heiko.
Also ich bastle einem Mess-Server der den Zugriff von verschieden Threats auf die Messgeräte regelt. Da Ganze ist auch ein I-learn-python (und programmiern) projekt.

Der Source-Code des Servers ist:

Code: Alles auswählen

import pickle
import Queue
import socket
import threading
import code
import test
from sendclass import *

## def martin(was):
##    print "martin is " + was;

## def gina(was, wasnoch):
##    print "gina is " + was + " und "+ wasnoch;

class Command:
    def __init__( self, func, *args):
            self.func=func;
            self.args=args;
    def __call__(self):
                apply(self.func, self.args);

# A revised version of our thread class:
class ServerThread ( threading.Thread ):

   # Note that we do not override Thread's __init__ method.
   # The Queue module makes this not necessary.

   def run(self):

      # Have our thread serve "forever":
      while True:

         # Get a client out of the queue
         client = clientPool.get()

         # Check if we actually have an actual client in the client variable:
         if client != None:

            print 'Received connection:', client[1][0]
            client[0].send('1');
            command=client[0].recv(1024)
            if command[0:5].upper()=='SETUP':
                file_handler=file('test.py','r')
                class_all=install_class(file_handler, 'test')
                client[0].send(repr(len(class_all)+1));
                if client[0].recv(1024)=='1':
                    print "Settin up a client ."
                for i in class_all:
                    client[0].send(i)
                    if client[0].recv(1024)=='1':
                        print "."
                client[0].send('print \'Installed Object: test \'');
                if client[0].recv(1024)=='1':
                    print ". the client is setup"
            else:
                while True:
                   if command[0:4].upper()=='CODE':
                       if command.__len__()>4 :
                           src_code=command[4:]
                       else:
                           src_code=client[0].recv(1024);
                       exec code.compile_command(src_code) in globals();
                       client[0].send("1");
                   elif command[0:6].upper()=='PICKLE':
                       if command.__len__()>6:
                           func_def=command[6:]
                       else:
                           func_def=client[0].recv(1024);
                       function=pickle.loads(func_def);
                       client[0].send(pickle.dumps(function.__call__()));
                   elif command[0:4].upper() ==  'QUIT':
                       client[0].close()
                       print 'Closed connection:', client[1][0];
                       break;

                   else:
                       print 'Error: ' + command + ' is no Command';
                   command=client[0].recv(1024)

# Create our Queue:
clientPool = Queue.Queue(0)
test=test.test()


# Start two threads:
for x in xrange(10):
   ServerThread().start()

# Set up the server:
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('', 2727))
server.listen(5)

# Have the server serve "forever":
while True:
   clientPool.put(server.accept())
Das module sendclass ist

Code: Alles auswählen

def install_class_from_string(string, name):
    index=0
    lines=string.splitlines()
    num=lines.__len__()
    res=''
    while index<num:
        if lines[index].strip().startswith('def'):
            func=lines[index] + '\n';
            index=index+1
            while index<num:  
                if lines[index].strip().startswith('def'):
                    break;
                func=func + lines[index] + '\n';
                index=index+1
 ##            print 'Start func: \n' + func + 'End func\n' 
            res=res+rewrite_func(func, name);
        else:
            res=res+lines[index] + '\n';
            index=index+1;
##     res=res + 'print \'Installed Object: ' + name +'\'';
    return res
    
def rewrite_func(string, name):
  def getDefName(string):
     string=string.strip()
     return string[4:string.find('(')].strip()
  def getDefArg(string):
     argstr=string[string.find('(')+1:string.find(')')];
     num=argstr.count(',')+1;
     args=argstr.split(',');
     allargs='';
     for i in range(0,num):
         if not(args[i].find('=')==-1):
             args[i]=args[i][0:args[i].find('=')];
         if not(args[i].strip()=='self'):
                allargs=allargs + ', ' + args[i].strip();
     return allargs
  res=''
  lastisdef=False;
  iscommend=False;
  func_name=''
  args=''
  for i in string.splitlines():
     if i.strip().startswith('def') :
        res= res + i + '\n';
        lastisdef=True;
        func_name=getDefName(i);
        args=getDefArg(i)
     elif lastisdef and i.strip().startswith('"""'):
        if i.count('"""') < 2:
           iscommend=True;
        lastisdef=False;
        res= res + i + '\n';
     elif iscommend:
        lastisdef=False;
        res= res + i + '\n';
        if i.find('"""'):
           iscommend=False;
     else:
        lastisdef=False;
     if func_name=='__init__':
         return string
     
  res=res + '\tclient.send(\'Pickle\')\n';
  res=res + '\ta=Command(' +  name + '.' + func_name + args + ') \n';
  res=res + '\tclient.send(pickle.dumps(a)) \n';
  res=res + '\tret=client.recv(1024) \n';
  res=res + '\treturn pickle.loads(ret) \n';
  return res


def getclassdefinition(file, name):
    class_all=[]
    class_str=''
    index=0
    def getclassname(string):
        if not(string.find('(')==-1):
            return string[6:string.find('(')].strip()
        else:
            return string[6:string.find(':')].strip()
    lines=file.readlines();
    num=lines.__len__()
    while index<num:
        if lines[index].startswith('class'):
            if getclassname(lines[index])==name:
                class_str=class_str+lines[index]
                index=index+1
                while index<num:
                    if not(lines[index].startswith(' ') or lines[index]=='\n'):
                        break
                    class_str=class_str+lines[index];
                    index=index+1
                class_all.append(class_str)
            else:
                index=index+1
                while index<num:
                    if not(lines[index].startswith(' ') or lines[index]=='\n'):
                        break
                    index=index+1
        else:
            class_all.append(lines[index]);
            index=index+1;
    return class_all


def install_class(myfile, name):
    class_def=getclassdefinition(myfile, name);
    num=len(class_def)-1
    class_def[num]=install_class_from_string(class_def[num], name)
    return class_def
test.py ist

Code: Alles auswählen

from time import sleep


class test1:
    pass



class test:
    """ Class description
          slkdfj
          """
    
    voltage=3.3

    def __init__(self, voltage=3.3):
        self.voltage=voltage
        
    def getVoltage(self):
        """ Function description
               sdfsdfsd """
        print 'Got the voltage'
        return self.voltage

    def setVolatge(self, voltage=3.3):
        """ single """
        print 'Set the voltage'
        self.voltage=voltage

    def sleep(time=30):
        sleep(time)
und der client ist :

Code: Alles auswählen

import pickle
import socket
import threading

import code

class Command:
    def __init__( self, func, *args):
            self.func=func;
            self.args=args;
    def __call__(self):
                apply(self.func, self.args);


def install_function(self, string):
   def getname(string):
      string=string.strip()
      return string[4:string.find('(')].strip()
   def getarg(string):
      argstr=string[string.find('(')+1:string.find(')')];
      num=argstr.count(',')+1;
      args=argstr.split(',');
      allargs='';
      for i in range(0,num):
         args[i]=args[i][0:args[i].find('=')];
         allargs=allargs + ', ' + args[i].strip();
      return allargs
   res=''
   lastisdef=False;
   iscommend=False;
   func_name=''
   args=''
   for i in string.splitlines():
      if i.startswith('def') :
         res= res + i + '\n';
         lastisdef=True;
         func_name=getname(i);
         args=getarg(i)
      elif lastisdef and i.find('"""'):
         if i.count('"""') < 2:
            iscommend=True;
         lastisdef=False;
         res= res + i + '\n';
      elif iscommend:
         lastisdef=False;
         res= res + i + '\n';
         if i.find('"""'):
            iscommend=False;
      else:
         lastisdef=False;
   res=res + '\tclient.send(\'Pickle\')\n';
   res=res + '\ta=Command(' +  func_name + args + ') \n';
   res=res + '\tclient.send(pickle.dumps(a)) \n';
   res=res + '\tret=client.recv(1024) \n';
   res=res + '\treturn pickle.loads(ret) \n'; 
   exec code.compile_command(res) in globals();
   client.send('Code');
   client.send(string);
   if client.recv(1024)=='1':
      print "Installed Function " + func_name + " successfully!"


def setup():
  exec 'client=socket.socket(socket.AF_INET, socket.SOCK_STREAM)' in globals()
  client.connect(('localhost', 2727));
  ack=client.recv(10)
  if ack[0:1]=='1' :
          print 'Connection succesfull!'
  client.send('SETUP')
  num=int(client.recv(1024))
  print num
  for i in range(num):
          client.send("1")
          src=client.recv(1024)
          print 'begin of source \n' + src +'end of source \n'
          exec code.compile_command(src) in globals()
  client.send("1");
Das Ziel ist, dass ich auf der Client-Seite einige GUI habe und aber auch in eine shell messbefehle eintippen kann. Ich möchte deshalb deshalb alle objekte für die Messgräte (die sind nur einige; ich werde also per exec nicht beliebig viele objekte erzeugen) auf der obersten Ebene instanzieren, dass Messroutinen auf allen Ebene können laufen. Der User sollte von der Kommunikation des Client/Server (auch text-basiert) nichts wissen muessen! Und seine Scripte sowohl local als auch auf dem Server ohne änderung laufen lassen können.
Sicherheitspolitische bedenken gegen meine Server habe ich mal ausser acht gelassen. Er wird in einer geschlossen umgebung laufen.

Gruss
Bossi
bossi

War das verständlich? Gebt mir bescheid falls Ihr noch mehr informationen über den server/client braucht.
nach dem setup() auf der client seite sollte es ein objekt test geben. Wenn ich z.B. test.sleep() in die shell eintippe sollte der threat auf der server seite eine halbe minute schlafen. Das ganze Funktioniert auch wenn client keine module ist.
modelnine
User
Beiträge: 670
Registriert: Sonntag 15. Januar 2006, 18:42
Wohnort: Celle
Kontaktdaten:

Also... Dein Programm ist in der momentanen Form höllisch unübersichtlich, und ich kann nicht so wirklich erkennen was Du machen willst.

Wie hast Du Dir eigentlich das Skript vorgestellt was vom Server auf den Client geschoben wird? Hat der Client einen bestimmten Funktionsumfang den er freigeben muß? Kann der Server nicht auf dem Client direkt die Funktionen zum Messen aufrufen und die Ausgabe sammeln?

Da Python-Quelldateien durchs Netz zu schieben immer irgendwie etwas von "nicht ganz sauber" hat würd ich Dir eher vorschlagen: bastel einen Client, der seine Messmethoden (die ja irgendwie vorgegeben sind) per XMLRPC veröffentlicht, und dann vom Server aus gesteuert wird. Zum Beispiel kannst Du pro Client einen Thread im Server aufmachen, und dann im Server ein Messmodul importieren, was per RPC den Client bedient, und die Daten gleich bei sich sammeln kann.

Wenn das Modell etwas für Dich wäre kann ich gerne mal ein Beispiel posten.

--- Heiko.
bossi

Ja, mein programm ist sehr organisch gewachsen. Dies ist zudem mein erstes Software projektchen seit langen Jahren. Ich kenne leider XML-RPM nicht, aber es tönt schon so dass dies genau das macht was ich eigentlich will. Ich wäre deshalb sehr dankbar wenn du mir ein Beispiel schicken könntest.

Also ich habe mir folgendes vorgestellt (Ich weiss dass meine Programm nicht der einfachste weg zum ziel ist ... aber bei diesem projekt ist auch einbisschen der Weg das Ziel):

Alle Messgeräte sind an einem server angeschlossen (per gpib). Der Server verwaltet auch alle Messprozeduren von einfachen Auslesefunction bis zu ganzen Messroutinen (damit der verwaltungsaufwand klein bleibt . Diese Messprozeduren sollten nun von überall her aufgerufen werden. Die Hauptaufgabe des Servers ist das verschieden clients nicht gleichzeitig auf ein Messgerät zugreifen. Auslese und schreib aktionen bestehen aus mehren gpib kommandos, wärend dieser Zeit muss das Messgerät blockiert sein (Ausserdem verschickt server periodisch den Status der messgeräte für etwelche GUIS).
So sollte mein Program funktionieren:
Der Server versteht 4 Kommandos : Setup, Code, Pickle und QUIT
SETUP: Schickt den source code von sämtliche messprozduren zum client. Allerdings wird der 'Inhalt' (ausser dem __doc__-Teil) ersetze mit code den die aufgerufene prozedure nicht local aber auf der server seite ausführen lässt.
CODE: Damit können neue Messfunktionen auf dem Server platziert werden. (SETUP) in die andere Richtung.
PICKLE: Damit können Messfunktion ausgeführt werden. Es gibt das Hilfsobjekt Command, das ein Representant der auszuführenden Funtion ist und eine Callfunktion hat. Das objekt wird dann gepickelt und verschickt ungepickled und es es wird call aufgerufen. (Dies könnte auch beliebig anderst implementiert werden). Dieses Hilfsobjekt ist inzwischen auch komplexer damit instancemethods übertragen werden können.
QUIT: Um die connection frei zu geben.

Der Vorteil ist das man die Messprozeduren nur ein einem Ort haben und ändern muss. Alle Clients haben dann automatisch die gleiche Prozeduren und Objekte zur Verfügung.
Ausserdem haben clients die gleichen objekte sie könned dir() und __doc__ benützen als wären die objekte lokal. Ausserdem kann ich Messprozeduren die ich auf meinem Rechner entwickelt habe ohne dazutun auf den fest auf dem Server installieren.

Wenn es mal funktioniert ... wäre die auch ein einfacher layer um Messung von überall her zu beobachten und zu steuern
Gast

bossi hat geschrieben: Die Hauptaufgabe des Servers ist das verschieden clients nicht gleichzeitig auf ein Messgerät zugreifen.
Die Hauptaufgabe des Servers ist zu steuern, dass verschieden Clients nicht gleichzeitig auf ein Messgerät zugreifen
Antworten