Salome HOME
bos #29864 Irrelevant assert in test.
[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, either manually or using a SALOME module generator 
89 such as :ref:`yacsgen`.  
90 A SALOME component implemented in Python can be defined directly in a Python script.  This type of component 
91 can be useful in test phases, for example.
92
93 The first step consists of compiling the IDL Interface directly in the Python script, which has the effect of 
94 creating the necessary CORBA Python modules.  For example, the following shows how CORBA modules compo1 and compo1_POA 
95 are produced that contain the basic interface with a single run method::
96
97   idlcompo="""
98   #include "DSC_Engines.idl"
99   #include "SALOME_Exception.idl"
100   module compo1{
101     interface base :Engines::Superv_Component {
102       string run(in string s) raises (SALOME::SALOME_Exception);
103     };
104   };
105   """
106   m=omniORB.importIDLString(idlcompo,
107                   ["-I/local/chris/SALOME/Install/KERNEL_V5/idl/salome"])
108
109 The second step consists of defining the body of component compo1 and therefore its run method.
110
111 The following is an example definition made in the body of the Python script::
112
113   import compo1
114   import compo1__POA
115
116   class compo(compo1__POA.base,dsccalcium.PyDSCComponent):
117     def run(self,s):
118       print "+++++++++++run+++++++++++",s
119       return "received "+s
120
121   compo1.compo1=compo
122
123 The important point here is that SALOME finds the class with the same name that represents the component 
124 in module compo1 (which is why there is the last line).
125
126 The third step consists of defining a SALOME container local to the script because this component 
127 only exists in the script.  The container name “MyContainerPy” will be defined as follows::
128
129   from omniORB import CORBA
130   from SALOME_ContainerPy import SALOME_ContainerPy_i
131   orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
132   poa = orb.resolve_initial_references("RootPOA")
133   poaManager = poa._get_the_POAManager()
134   poaManager.activate()
135   cpy_i = SALOME_ContainerPy_i(orb, poa, "MyContainerPy")
136
137 taking care to activate CORBA with poaManager.activate().
138
139 All that is necessary afterwards is to create a YACS container and to place a SALOME node in it, in the same 
140 way as for a standard component.
141