4 Advanced use of the Python programming interface
5 ==========================================================================
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.
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 :).
20 ++++++++++++++++++++++
21 The Python protocol is based on serialisation done by the cPickle module (C implementation of 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
29 Definition of the “Python object” type::
31 tc1=p.createInterfaceTc("python:obj:1.0","PyObj",[])
33 Definition of two Python nodes that use this type::
35 n2=r.createScriptNode("","node2")
38 p1={'a':1,'b':5.6,'c':[1,2,3]}
40 n2.edAddOutputPort("p1",tc1)
42 n3=r.createScriptNode("","node3")
46 n3.edAddInputPort("p1",tc1)
48 p.edAddDFLink(n2.getOutputPort("p1"),n3.getInputPort("p1"))
50 Definition of a SALOME service node that uses this type::
52 n1=r.createCompoNode("","node1")
55 n1.edAddInputPort("p1",tc1)
56 n1.edAddOutputPort("p1",tc1)
58 p.edAddDFLink(n2.getOutputPort("p1"),n1.getInputPort("p1"))
60 The implementation of component compo1 must handle serialisation / deserialisation in the same
61 way as the example in the run method described below::
65 ret={'a':6, 'b':[1,2,3]}
66 return cPickle.dumps(ret,-1)
69 ++++++++++++++++++++++
70 The json protocol is based on `JSON <http://www.json.org/>`_ (JavaScript Object Notation)
71 serialisation / deserialisation instead of cPickle. 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.
75 All that is necessary to use this protocol in YACS is to replace python by json in the type definition. For example::
77 tc1=p.createInterfaceTc("json:obj:1.0","PyObj",[])
79 The rest is identical, except for implementation of the component that is as follows, using the same example as above::
83 ret={'a':6, 'b':[1,2,3]}
84 return simplejson.dumps(ret)
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.
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::
98 #include "DSC_Engines.idl"
99 #include "SALOME_Exception.idl"
101 interface base :Engines::Superv_Component {
102 string run(in string s) raises (SALOME::SALOME_Exception);
106 m=omniORB.importIDLString(idlcompo,
107 ["-I/local/chris/SALOME/Install/KERNEL_V5/idl/salome"])
109 The second step consists of defining the body of component compo1 and therefore its run method.
111 The following is an example definition made in the body of the Python script::
116 class compo(compo1__POA.base,dsccalcium.PyDSCComponent):
118 print "+++++++++++run+++++++++++",s
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).
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::
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")
137 taking care to activate CORBA with poaManager.activate().
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.