Salome HOME
CCAR: add the PyNode object that can be created in a container
authorcaremoli <caremoli>
Thu, 8 Oct 2009 14:29:01 +0000 (14:29 +0000)
committercaremoli <caremoli>
Thu, 8 Oct 2009 14:29:01 +0000 (14:29 +0000)
to execute remote Python code.
Example from python interpreter:
import salome_pynode
code="""def f(x):
  return 2*x
"""
node=container.createPyNode("mynode",code)
y=node.execute("f",10)

idl/Makefile.am
idl/SALOME_Component.idl
idl/SALOME_PyNode.idl [new file with mode: 0644]
src/Container/Container_i.cxx
src/Container/Makefile.am
src/Container/SALOME_Container.py
src/Container/SALOME_Container_i.hxx
src/Container/SALOME_PyNode.py [new file with mode: 0644]
src/KERNEL_PY/Makefile.am
src/KERNEL_PY/salome_pynode.py [new file with mode: 0644]

index 556ebe1b178adbc7504ca2e7347786ec06320d52..744d555d53461a2327c706d0595cf4af21cb430e 100644 (file)
@@ -46,6 +46,7 @@ BASEIDL_FILES = \
   nstest.idl \
   DSC_Engines.idl \
   SALOME_Ports.idl \
+  SALOME_PyNode.idl \
   Palm_Ports.idl \
   SALOME_PACOExtension.idl \
   SALOME_ParamPorts.idl
@@ -95,6 +96,7 @@ BASEIDL_SOURCES =\
   nstestSK.cc \
   DSC_EnginesSK.cc \
   SALOME_PortsSK.cc \
+  SALOME_PyNodeSK.cc \
   Calcium_PortsSK.cc \
   Palm_PortsSK.cc \
   SALOME_PACOExtensionSK.cc \
@@ -106,7 +108,7 @@ DYNIDL_SRCS = \
   SALOMEDSDynSK.cc      SALOME_SessionDynSK.cc    SALOME_RessourcesCatalogDynSK.cc \
   DSC_EnginesDynSK.cc   SALOME_ComponentDynSK.cc  SALOME_GenericObjDynSK.cc \
   Palm_PortsDynSK.cc    SALOME_ExceptionDynSK.cc  SALOMEDS_AttributesDynSK.cc \
-  LoggerDynSK.cc        SALOME_PACOExtensionDynSK.cc SALOME_ParamPortsDynSK.cc
+  LoggerDynSK.cc        SALOME_PACOExtensionDynSK.cc SALOME_ParamPortsDynSK.cc SALOME_PyNodeDynSK.cc
 
 MPIIDL_SOURCES = \
   SALOME_MPIObjectSK.cc \
index 6e70b41e17377412761d20f1dc73565641089c8d..fc555dc34cc955bd708204bb10c517f490abd27b 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "SALOMEDS.idl"
 #include "SALOME_Exception.idl"
+#include "SALOME_PyNode.idl"
 
 /*! \file SALOME_Component.idl \brief interfaces for Component and Container
 */
@@ -192,6 +193,13 @@ module Engines
       \param localFile the local file to create by copy
      */
     void copyFile(in Container contai, in string remoteFile, in string localFile);
+
+    //! Create a PyNode in the container
+    /*!
+      \param nodeName the name of the PyNode
+      \param code python code as text to load in the node
+     */
+    PyNode createPyNode(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
new file mode 100644 (file)
index 0000000..cde0a0a
--- /dev/null
@@ -0,0 +1,57 @@
+//  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+//
+//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+//  This library is free software; you can redistribute it and/or
+//  modify it under the terms of the GNU Lesser General Public
+//  License as published by the Free Software Foundation; either
+//  version 2.1 of the License.
+//
+//  This library is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+//  Lesser General Public License for more details.
+//
+//  You should have received a copy of the GNU Lesser General Public
+//  License along with this library; if not, write to the Free Software
+//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+//
+//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+//  File   : SALOME_PyNode.idl
+//  Author : Christian CAREMOLI, EDF
+//  $Header: 
+//
+#ifndef _SALOME_PYNODE_IDL_
+#define _SALOME_PYNODE_IDL_
+
+#include "SALOME_GenericObj.idl"
+#include "SALOME_Exception.idl"
+
+/*! \file SALOME_PyNode.idl \brief interface for remote python execution
+*/
+
+/*! \brief
+This is a package of interfaces used for executing Python code on remote container
+*/
+module Engines
+{
+  typedef sequence<octet> pickledArgs;
+
+  interface PyNode : SALOME::GenericObj
+  {
+
+    /*! \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
+    */
+    pickledArgs execute(in string functionName,in pickledArgs inargs) raises (SALOME::SALOME_Exception);
+
+  } ;
+
+};
+
+#endif
index e7636281badff05efb2bc10f0a079a32e13c3e36..f7124ac82ba1074dd5e62579b0db86329bf985ff 100644 (file)
@@ -1411,3 +1411,49 @@ void Engines_Container_i::copyFile(Engines::Container_ptr container, const char*
     }
 }
 
+/*! \brief create a PyNode object to execute remote python code
+ * \param nodeName the name of the node
+ * \param code the python code to load
+ * \return the PyNode
+ */
+Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
+{
+    Engines::PyNode_var node= Engines::PyNode::_nil();
+
+    PyGILState_STATE gstate = PyGILState_Ensure();
+    PyObject *res = PyObject_CallMethod(_pyCont,
+      (char*)"create_pynode",
+      (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::PyNode::_narrow(obj);
+        return node._retn();
+      }
+    else
+      {
+        SALOME::ExceptionStruct es;
+        es.type = SALOME::INTERNAL_ERROR;
+        es.text = astr.c_str();
+        throw SALOME::SALOME_Exception(es);
+      }
+
+}
index 331023d77f4de316ad7f85669b948b956eac34c7..c3a870cbe4daed1d0ebf494080ad55470005b887 100644 (file)
@@ -46,6 +46,7 @@ salomeinclude_HEADERS = \
 # Scripts to be installed
 dist_salomescript_PYTHON =\
        SALOME_ComponentPy.py \
+  SALOME_PyNode.py \
        SALOME_Container.py
 
 # These files are executable scripts
index 73ba33123249a48e5c8f6377e933a8d727f9e075..cd806273b79be8e50f3c80e6e15e48a062a429e2 100644 (file)
 import os
 import sys
 import string
+import traceback
 from omniORB import CORBA, PortableServer
 import SALOMEDS 
 import Engines, Engines__POA
 from SALOME_NamingServicePy import *
 from SALOME_ComponentPy import *
+import SALOME_PyNode
 
 from SALOME_utilities import *
 from Utils_Identity import getShortHostName
@@ -107,3 +109,14 @@ class SALOME_Container_i:
         return comp_iors 
         
 
+    def create_pynode(self,nodeName,code):
+        try:
+          node=SALOME_PyNode.PyNode_i(nodeName,code,self._poa)
+          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)
index e45b939e6fe6eaf1fca397bd523eac46f0535325..91d40f96f8857287becb9eccc22bf477f23285ab 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <SALOMEconfig.h>
 #include CORBA_SERVER_HEADER(SALOME_Component)
+#include CORBA_SERVER_HEADER(SALOME_PyNode)
 
 #include <iostream>
 #include <signal.h>
@@ -97,6 +98,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);
   // --- local C++ methods
 
   Engines::Component_ptr
diff --git a/src/Container/SALOME_PyNode.py b/src/Container/SALOME_PyNode.py
new file mode 100644 (file)
index 0000000..5b21f77
--- /dev/null
@@ -0,0 +1,74 @@
+#  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+#  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+#  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+#  File   : SALOME_PyNode.py
+#  Author : Christian CAREMOLI, EDF
+#  Module : SALOME
+#  $Header$
+#
+
+import sys,traceback,string
+import linecache
+import cPickle
+import Engines__POA
+import SALOME__POA
+import SALOME
+
+class Generic(SALOME__POA.GenericObj):
+  """A Python implementation of the GenericObj CORBA IDL"""
+  def __init__(self,poa):
+    self.poa=poa
+    self.cnt=1
+
+  def Register(self):
+    self.cnt+=1
+
+  def Destroy(self):
+    self.cnt-=1
+    if self.cnt <= 0:
+      oid=self.poa.servant_to_id(self)
+      self.poa.deactivate_object(oid)
+
+class PyNode_i (Engines__POA.PyNode,Generic):
+  """The implementation of the PyNode CORBA IDL"""
+  def __init__(self, nodeName,code,poa):
+    """Initialize the node : compilation in the local context"""
+    Generic.__init__(self,poa)
+    self.nodeName=nodeName
+    self.code=code
+    linecache.cache[nodeName]=0,None,string.split(code,'\n'),nodeName
+    ccode=compile(code,nodeName,'exec')
+    self.context={}
+    exec ccode in self.context
+
+  def execute(self,funcName,argsin): 
+    """Execute the function funcName found in local context with pickled args (argsin)"""
+    try:
+      argsin,kws=cPickle.loads(argsin)
+      func=self.context[funcName]
+      argsout=func(*argsin,**kws)
+      argsout=cPickle.dumps(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),"PyNode: %s, function: %s" % (self.nodeName,funcName),0))
+
index c94ecdd7de3b10dab56000422793670bc8f4661b..98200fc095c736039b2c0032253c442c45ee2f35 100755 (executable)
@@ -45,6 +45,7 @@ if CORBA_GEN
                iparameters.py \
                salome_version.py \
                salome_notebook.py \
+               salome_pynode.py \
     salome_genericobj.py
 endif
 
diff --git a/src/KERNEL_PY/salome_pynode.py b/src/KERNEL_PY/salome_pynode.py
new file mode 100644 (file)
index 0000000..0a8182b
--- /dev/null
@@ -0,0 +1,61 @@
+#  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+#  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+#  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+#  File   : salome_pynode.py
+#  Author : Christian CAREMOLI, EDF
+#  Module : SALOME
+#  $Header$
+#
+
+"""
+ 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 
+"""
+import omniORB
+import cPickle
+import SALOME
+import Engines
+
+class SmartPyNode(Engines._objref_PyNode):
+  def __init__(self):
+    Engines._objref_PyNode.__init__(self)
+
+  def execute(self,functionName,*args,**kws):
+    try:
+      args=cPickle.dumps((args,kws),-1)
+      results=Engines._objref_PyNode.execute(self,functionName,args)
+      x=cPickle.loads(results)
+      return x
+    except SALOME.SALOME_Exception, e:
+      raise ValueError(e.details.text)
+
+  def __getattr__(self,name):
+    """ a trick to be able to call directly a remote method by its name : no need to use execute"""
+    if name[0]== '_':
+      raise AttributeError, name
+    def afunc(*args,**kws):
+      return self.execute(name,*args,**kws)
+    return afunc
+
+#Register the new proxy for PyNode
+omniORB.registerObjref(Engines._objref_PyNode._NP_RepositoryId, SmartPyNode)
+