Salome HOME
remove references to yacsgen
[modules/yacs.git] / doc / advancepy.rst
1
2 .. _advancepy:
3
4 Advanced use of the Python programming interface
5 ==========================================================================
6
7 Passing Python objects between calculation nodes
8 --------------------------------------------------
9 The YACS standard data model is used to exchange a number of data types (see :ref:`datatypes`) that are limited to 
10 types supported by CORBA.  The Python language allows to manipulate data types that are not managed by YACS.  
11 In particular, the Python dictionary with heterogeneous data types is not managed by the YACS data model.
12
13 However, Python dictionaries can be exchanged between some types of calculation nodes by using object references with 
14 a non-standard protocol.  The standard protocol is the IDL protocol that corresponds to serialisation of data 
15 managed by CORBA.  There are two other protocols (python and json) that use non-CORBA serialisation mechanisms 
16 that support more data types including dictionaries.  
17 The protocol name appears in the first part of the type Repository ID (before the first :).
18
19 The Python protocol
20 ++++++++++++++++++++++
21 The Python protocol is based on serialisation done by the pickle module.  
22 All that is necessary is to define an object reference type with the Python protocol so that Python objects 
23 can be exchanged between Python inline nodes and with SALOME components implemented in Python.  
24 SALOME components implemented in Python that are required to support this exchange type must be designed 
25 to receive a character string that contains the serialised object.  The component is responsible for deserialising the object.  
26 In the other direction, the component is responsible for serialising the object and must return a character string 
27 for this object type.
28
29 Definition of the “Python object” type::
30
31   tc1=p.createInterfaceTc("python:obj:1.0","PyObj",[])
32
33 Definition of two Python nodes that use this type::
34
35   n2=r.createScriptNode("","node2")
36   p.edAddChild(n2)
37   n2.setScript("""
38   p1={'a':1,'b':5.6,'c':[1,2,3]}
39   """)
40   n2.edAddOutputPort("p1",tc1)
41
42   n3=r.createScriptNode("","node3")
43   n3.setScript("""
44   print "p1=",p1
45   """)
46   n3.edAddInputPort("p1",tc1)
47   p.edAddChild(n3)
48   p.edAddDFLink(n2.getOutputPort("p1"),n3.getInputPort("p1"))
49
50 Definition of a SALOME service node that uses this type::
51
52   n1=r.createCompoNode("","node1")
53   n1.setRef("compo1")
54   n1.setMethod("run")
55   n1.edAddInputPort("p1",tc1)
56   n1.edAddOutputPort("p1",tc1)
57   p.edAddChild(n1)
58   p.edAddDFLink(n2.getOutputPort("p1"),n1.getInputPort("p1"))
59
60 The implementation of component compo1 must handle serialisation / deserialisation in the same 
61 way as the example in the run method described below::
62
63   def run(self,s):
64     o=pickle.loads(s)
65     ret={'a':6, 'b':[1,2,3]}
66     return pickle.dumps(ret,-1)
67  
68 The json protocol
69 ++++++++++++++++++++++
70 The json protocol is based on `JSON <http://www.json.org/>`_ (JavaScript Object Notation) 
71 serialisation / deserialisation instead of pickle. JSON supports fewer data types and requires that 
72 the simplejson Python module should be installed, but it has the advantage that it is more interoperable.  
73 In particular, there are C++ libraries that serialise/deserialise the JSON.
74
75 All that is necessary to use this protocol in YACS is to replace python by json in the type definition.  For example::
76
77   tc1=p.createInterfaceTc("json:obj:1.0","PyObj",[])
78
79 The rest is identical, except for implementation of the component that is as follows, using the same example as above::
80
81   def run(self,s):
82     o=simplejson.loads(s)
83     ret={'a':6, 'b':[1,2,3]}
84     return simplejson.dumps(ret)
85
86 Definition of inline Python components
87 --------------------------------------------------
88 Normally, a Python SALOME component must be developed outside YACS.
89 A SALOME component implemented in Python can be defined directly in a Python script.  This type of component 
90 can be useful in test phases, for example.
91
92 The first step consists of compiling the IDL Interface directly in the Python script, which has the effect of 
93 creating the necessary CORBA Python modules.  For example, the following shows how CORBA modules compo1 and compo1_POA 
94 are produced that contain the basic interface with a single run method::
95
96   idlcompo="""
97   #include "DSC_Engines.idl"
98   #include "SALOME_Exception.idl"
99   module compo1{
100     interface base :Engines::Superv_Component {
101       string run(in string s) raises (SALOME::SALOME_Exception);
102     };
103   };
104   """
105   m=omniORB.importIDLString(idlcompo,
106                   ["-I/local/chris/SALOME/Install/KERNEL_V5/idl/salome"])
107
108 The second step consists of defining the body of component compo1 and therefore its run method.
109
110 The following is an example definition made in the body of the Python script::
111
112   import compo1
113   import compo1__POA
114
115   class compo(compo1__POA.base,dsccalcium.PyDSCComponent):
116     def run(self,s):
117       print "+++++++++++run+++++++++++",s
118       return "received "+s
119
120   compo1.compo1=compo
121
122 The important point here is that SALOME finds the class with the same name that represents the component 
123 in module compo1 (which is why there is the last line).
124
125 The third step consists of defining a SALOME container local to the script because this component 
126 only exists in the script.  The container name “MyContainerPy” will be defined as follows::
127
128   from omniORB import CORBA
129   from SALOME_ContainerPy import SALOME_ContainerPy_i
130   orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
131   poa = orb.resolve_initial_references("RootPOA")
132   poaManager = poa._get_the_POAManager()
133   poaManager.activate()
134   cpy_i = SALOME_ContainerPy_i(orb, poa, "MyContainerPy")
135
136 taking care to activate CORBA with poaManager.activate().
137
138 All that is necessary afterwards is to create a YACS container and to place a SALOME node in it, in the same 
139 way as for a standard component.
140