From f595ec9d0ec24162bbdb62dc98e12e300bcb2926 Mon Sep 17 00:00:00 2001 From: caremoli Date: Tue, 25 Jan 2011 17:52:00 +0000 Subject: [PATCH] CCAR: add a CORBA object PyScriptNode that can be created in a container and is able to execute python script code in the process of the container. Creation : operation createPyScriptNode of Container interface Execution : operation execute of PyScriptNode interface --- idl/SALOME_Component.idl | 7 ++++ idl/SALOME_PyNode.idl | 18 +++++++++-- src/Container/Container_i.cxx | 48 ++++++++++++++++++++++++++++ src/Container/SALOME_Container.py | 12 +++++++ src/Container/SALOME_Container_i.hxx | 1 + src/Container/SALOME_PyNode.py | 32 ++++++++++++++++++- src/KERNEL_PY/salome_pynode.py | 18 ++++++++++- 7 files changed, 132 insertions(+), 4 deletions(-) diff --git a/idl/SALOME_Component.idl b/idl/SALOME_Component.idl index e91c8b046..a8b862ebf 100644 --- a/idl/SALOME_Component.idl +++ b/idl/SALOME_Component.idl @@ -217,6 +217,13 @@ module Engines \param code python code as text to load in the node */ PyNode createPyNode(in string nodeName, in string code) raises(SALOME::SALOME_Exception); + + //! Create a PyScriptNode in the container + /*! + \param nodeName the name of the PyScriptNode + \param code python code as text to load in the node + */ + PyScriptNode createPyScriptNode(in string nodeName, in string code) raises(SALOME::SALOME_Exception); }; /*! \brief Interface of the %component. diff --git a/idl/SALOME_PyNode.idl b/idl/SALOME_PyNode.idl index da9164db6..01762e166 100644 --- a/idl/SALOME_PyNode.idl +++ b/idl/SALOME_PyNode.idl @@ -36,6 +36,7 @@ This is a package of interfaces used for executing Python code on remote contain module Engines { typedef sequence pickledArgs; + typedef sequence listofstring; interface PyNode : SALOME::GenericObj { @@ -43,13 +44,26 @@ module Engines /*! \brief execute a python function defined in the node \param functionName the python function defined in the node to execute - \param inargs input argument values provided as a python pickle - \return output argument values as a python pickle + \param inargs input argument values (tuple,dict) provided as a python pickle + \return output argument values (tuple) as a python pickle */ pickledArgs execute(in string functionName,in pickledArgs inargs) raises (SALOME::SALOME_Exception); } ; + interface PyScriptNode : SALOME::GenericObj + { + + /*! \brief execute a python script defined in the node + + \param outargsname output argument names + \param inargs input argument values (dict) provided as a python pickle + \return output argument values (tuple) as a python pickle + */ + pickledArgs execute(in listofstring outargsname, in pickledArgs inargs) raises (SALOME::SALOME_Exception); + + } ; + }; #endif diff --git a/src/Container/Container_i.cxx b/src/Container/Container_i.cxx index 3f8768718..ae0d32362 100644 --- a/src/Container/Container_i.cxx +++ b/src/Container/Container_i.cxx @@ -1621,6 +1621,54 @@ Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, cons } +//============================================================================= +/*! \brief create a PyScriptNode object to execute remote python code + * \param nodeName the name of the node + * \param code the python code to load + * \return the PyScriptNode + */ +//============================================================================= +Engines::PyScriptNode_ptr Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code) +{ + Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil(); + + PyGILState_STATE gstate = PyGILState_Ensure(); + PyObject *res = PyObject_CallMethod(_pyCont, + (char*)"create_pyscriptnode", + (char*)"ss", + nodeName, + code); + if(res==NULL) + { + //internal error + PyErr_Print(); + PyGILState_Release(gstate); + SALOME::ExceptionStruct es; + es.type = SALOME::INTERNAL_ERROR; + es.text = "can not create a python node"; + throw SALOME::SALOME_Exception(es); + } + long ierr=PyInt_AsLong(PyTuple_GetItem(res,0)); + PyObject* result=PyTuple_GetItem(res,1); + std::string astr=PyString_AsString(result); + Py_DECREF(res); + PyGILState_Release(gstate); + + if(ierr==0) + { + CORBA::Object_var obj = _orb->string_to_object(astr.c_str()); + node = Engines::PyScriptNode::_narrow(obj); + return node._retn(); + } + else + { + SALOME::ExceptionStruct es; + es.type = SALOME::INTERNAL_ERROR; + es.text = astr.c_str(); + throw SALOME::SALOME_Exception(es); + } +} + //============================================================================= /* int checkifexecutable(const char *filename) * diff --git a/src/Container/SALOME_Container.py b/src/Container/SALOME_Container.py index c830f8d96..fb74760cb 100644 --- a/src/Container/SALOME_Container.py +++ b/src/Container/SALOME_Container.py @@ -137,3 +137,15 @@ class SALOME_Container_i: exc_typ,exc_val,exc_fr=sys.exc_info() l=traceback.format_exception(exc_typ,exc_val,exc_fr) return 1,"".join(l) + + def create_pyscriptnode(self,nodeName,code): + try: + node=SALOME_PyNode.PyScriptNode_i(nodeName,code,self._poa,self) + id_o = self._poa.activate_object(node) + comp_o = self._poa.id_to_reference(id_o) + comp_iors = self._orb.object_to_string(comp_o) + return 0,comp_iors + except: + exc_typ,exc_val,exc_fr=sys.exc_info() + l=traceback.format_exception(exc_typ,exc_val,exc_fr) + return 1,"".join(l) diff --git a/src/Container/SALOME_Container_i.hxx b/src/Container/SALOME_Container_i.hxx index 80ddfa6ad..11a5cbfe7 100644 --- a/src/Container/SALOME_Container_i.hxx +++ b/src/Container/SALOME_Container_i.hxx @@ -105,6 +105,7 @@ public: virtual Engines::Salome_file_ptr createSalome_file(const char* origFileName); void copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile); Engines::PyNode_ptr createPyNode(const char* nodeName, const char* code); + Engines::PyScriptNode_ptr createPyScriptNode(const char* nodeName, const char* code); // --- local C++ methods Engines::Component_ptr diff --git a/src/Container/SALOME_PyNode.py b/src/Container/SALOME_PyNode.py index cf50f8ca6..d0f8f5273 100644 --- a/src/Container/SALOME_PyNode.py +++ b/src/Container/SALOME_PyNode.py @@ -60,7 +60,7 @@ class PyNode_i (Engines__POA.PyNode,Generic): self.context["my_container"] = self.my_container exec ccode in self.context - def execute(self,funcName,argsin): + def execute(self,funcName,argsin): """Execute the function funcName found in local context with pickled args (argsin)""" try: argsin,kws=cPickle.loads(argsin) @@ -73,3 +73,33 @@ class PyNode_i (Engines__POA.PyNode,Generic): l=traceback.format_exception(exc_typ,exc_val,exc_fr) raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyNode: %s, function: %s" % (self.nodeName,funcName),0)) +class PyScriptNode_i (Engines__POA.PyScriptNode,Generic): + """The implementation of the PyScriptNode CORBA IDL that executes a script""" + def __init__(self, nodeName,code,poa,my_container): + """Initialize the node : compilation in the local context""" + Generic.__init__(self,poa) + self.nodeName=nodeName + self.code=code + self.my_container=my_container._container + linecache.cache[nodeName]=0,None,string.split(code,'\n'),nodeName + self.ccode=compile(code,nodeName,'exec') + self.context={} + self.context["my_container"] = self.my_container + + def execute(self,outargsname,argsin): + """Execute the script stored in attribute ccode with pickled args (argsin)""" + try: + argsname,kws=cPickle.loads(argsin) + self.context.update(kws) + exec self.ccode in self.context + argsout=[] + for arg in outargsname: + if not self.context.has_key(arg): + raise KeyError("There is no variable %s in context" % arg) + argsout.append(self.context[arg]) + argsout=cPickle.dumps(tuple(argsout),-1) + return argsout + except: + exc_typ,exc_val,exc_fr=sys.exc_info() + l=traceback.format_exception(exc_typ,exc_val,exc_fr) + raise SALOME.SALOME_Exception(SALOME.ExceptionStruct(SALOME.BAD_PARAM,"".join(l),"PyScriptNode: %s, outargsname: %s" % (self.nodeName,outargsname),0)) diff --git a/src/KERNEL_PY/salome_pynode.py b/src/KERNEL_PY/salome_pynode.py index b9ce2c0dd..53ed53183 100644 --- a/src/KERNEL_PY/salome_pynode.py +++ b/src/KERNEL_PY/salome_pynode.py @@ -25,7 +25,7 @@ """ When imported this module adds to CORBA proxy (from PyNode type) automatic pickle and unpickle of arguments and results when calling execute method. It also converts the SALOME exception into a standard python - exception + exception """ import omniORB import cPickle @@ -53,6 +53,22 @@ class SmartPyNode(Engines._objref_PyNode): return self.execute(name,*args,**kws) return afunc +class SmartPyScriptNode(Engines._objref_PyScriptNode): + def __init__(self): + Engines._objref_PyScriptNode.__init__(self) + + def execute(self,outargsname,*args,**kws): + #the tuple args are ignored + try: + args=cPickle.dumps(((),kws),-1) + results=Engines._objref_PyScriptNode.execute(self,outargsname,args) + x=cPickle.loads(results) + return x + except SALOME.SALOME_Exception, e: + raise ValueError(e.details.text) + #Register the new proxy for PyNode omniORB.registerObjref(Engines._objref_PyNode._NP_RepositoryId, SmartPyNode) +#Register the new proxy for PyScriptNode +omniORB.registerObjref(Engines._objref_PyScriptNode._NP_RepositoryId, SmartPyScriptNode) -- 2.39.2