ChimeraTK-ApplicationCore 04.09.00
Loading...
Searching...
No Matches
testPythonWithArray.py
Go to the documentation of this file.
1#!/usr/bin/python3
2
3import sys
4import os
5import os.path
6import numpy as np
7from typing import Callable
8import time
9import traceback
10
11# fmt: off
12# Hack to insert the python path for the locally compiled module in the
13# test script
14sys.path.insert(0, os.path.abspath(os.path.join(os.curdir, "..")))
15import PyApplicationCore as ac # NOQA
16# fmt: on
17
18
19class MyMod(ac.ApplicationModule):
20
21 def __init__(self, owner, name, description):
22 super().__init__(owner, name, description)
23
24 # can we do this somehow in the class definition instead of the constructor body?
25 self.myOutput1 = ac.ArrayOutput(ac.DataType.int32, self, "ArrayOut1", "SomeUnit", 10, "my fancy description")
26 self.myOutput2 = ac.ArrayOutput(ac.DataType.int32, self, "ArrayOut2", "SomeUnit", 10, "my fancy description")
27 self.myOutputRB = ac.ArrayOutputPushRB(
28 ac.DataType.int32,
29 self,
30 "ArrayOutRB",
31 "SomeUnit",
32 2,
33 "my fancy description")
34
35 self.myInput1 = ac.ArrayPushInput(ac.DataType.int32, self, "ArrayIn1", "unit", 2, "description")
36 self.myInput2 = ac.ArrayPushInput(ac.DataType.int32, self, "ArrayIn2", "unit", 5, "description")
37 self.myInput3 = ac.ArrayPushInput(ac.DataType.float32, self, "ArrayIn3", "unit", 2, "description")
38 self.myInputPoll = ac.ArrayPollInput(ac.DataType.int32, self, "ArrayInPOLL", "unit", 2, "description")
39 self.myInputWB = ac.ArrayPushInputWB(ac.DataType.int32, self, "ArrayInWB", "unit", 1, "description")
40
41 # these outputs are used to transport subject-to-test data to the C++ side for checking in the BOOST test case
42 self.testError = ac.ScalarOutput(ac.DataType.string, self, "TestError", "", "")
43
44 def prepare(self):
45 self.myOutputRB.setAndWrite([42, 43])
46
47 def mainLoop(self):
48 try:
49 assert self.myOutput1.getName() == "/SomeName/ArrayOut1"
50 assert self.myOutput1.getUnit() == "SomeUnit"
51 assert "Root for Python Modules - Module's description - my fancy description" in self.myOutput1.getDescription()
52 assert self.myOutput1.getValueType() == ac.DataType.int32
53 assert self.myOutput1.getVersionNumber() == ac.VersionNumber(None)
54 assert self.myOutput1.isReadOnly() == False
55 assert self.myOutput1.isReadable() == False
56 assert self.myOutput1.isWriteable()
57 assert str(self.myOutput1.getId()).startswith('0x')
58 assert self.myOutput1.getId() != self.myOutput2.getId()
59 assert self.myOutput1.dataValidity() == ac.DataValidity.ok
60
61 while True:
62 val = self.myInput1.get()
63 valSum = sum(val)
64 self.myOutput1.setAndWrite(range(valSum, valSum + 10))
65
66 valcopy = np.array(self.myInput1, copy=True)
67 assert (self.myInput1 == valcopy).all()
68
69 valcopy[0] = 3
70
71 assert ((self.myInput1 == valcopy) == [False, True]).all()
72 assert ((self.myInput1 != valcopy) == [True, False]).all()
73 assert ((self.myInput1 <= valcopy) == [False, True]).all()
74 assert ((self.myInput1 < valcopy) == [False, False]).all()
75 assert ((self.myInput1 >= valcopy) == [True, True]).all()
76 assert ((self.myInput1 > valcopy) == [True, False]).all()
77
78 assert ((valcopy == self.myInput1) == [False, True]).all()
79 assert ((valcopy != self.myInput1) == [True, False]).all()
80 assert ((valcopy >= self.myInput1) == [False, True]).all()
81 assert ((valcopy > self.myInput1) == [False, False]).all()
82 assert ((valcopy <= self.myInput1) == [True, True]).all()
83 assert ((valcopy < self.myInput1) == [True, False]).all()
84
85 assert ((self.myInput1 == self.myInput1) == [True, True]).all()
86 assert ((self.myInput1 == self.myInputPoll) == [False, False]).all()
87
88 # input arrays: test support both for numpy arrays and python lists; implementation may differ
89 self.myInput1.set(np.array([12, 23], dtype=np.int32))
90 assert self.myInput1[0] == 12
91 assert self.myInput1[1] == 23
92 assert ((self.myInput1 == [12, 23]) == [True, True]).all()
93
94 self.myInput1.set([123, 234])
95 assert self.myInput1[0] == 123
96 assert self.myInput1[1] == 234
97 assert ((self.myInput1 == [123, 234]) == [True, True]).all()
98
99 # check that np.float32 is correctly taken over (bug regression)
100 self.myInput3.set(np.array([1.1, 6.6], dtype=np.float32))
101 assert self.myInput3[0] == np.float32(1.1)
102 assert self.myInput3[1] == np.float32(6.6)
103 self.myInput3.set([1.2, 6.7])
104 assert self.myInput3[0] == np.float32(1.2)
105 assert self.myInput3[1] == np.float32(6.7)
106 self.myInput3.set([np.float64(1.1), np.float64(6.6)])
107 assert self.myInput3[0] == np.float32(1.1)
108 assert self.myInput3[1] == np.float32(6.6)
109 self.myInput3.set([np.float32(1.1), np.float32(6.6)])
110 # index access returns a numpy scalar of the matching type (np.float32)
111 assert type(self.myInput3[0]) is np.float32
112 assert type(self.myInput3[1]) is np.float32
113 assert self.myInput3[0] == np.float32(1.1)
114 assert self.myInput3[1] == np.float32(6.6)
115 # test array slicing (separate implementation)
116 self.myInput3[0:2:1] = 1.3
117 assert self.myInput3[0] == np.float32(1.3)
118 assert self.myInput3[1] == np.float32(1.3)
119 self.myInput3[0:2:1] = np.float32(1.5) # 1.5 is precisely representable as float32
120 assert self.myInput3[0] == 1.5
121 assert self.myInput3[1] == 1.5
122 # test array index access (separate implementation)
123 self.myInput3[1] = 6.5
124 assert self.myInput3[0] == 1.5
125 assert self.myInput3[1] == 6.5
126 self.myInput3[1] = np.float32(6.75) # 6.75 is precisely representable as float32
127 assert self.myInput3[1] == 6.75
128
129 # TODO probably it will also make sense to go over all other types, including bool...
130
131
132 # calling members of np.array is directly possible
133 assert self.myInput1.shape == (2,)
134
135 # val is not a deep copy
136 assert val[0] == self.myInput1[0]
137 val[0] = 4
138 assert val[0] == self.myInput1[0]
139 self.myInput1[0] = 3
140 assert self.myInput1[0] == 3
141 assert val[0] == self.myInput1[0]
142 assert val[0] == 3
143
144 val = self.myInput2.readAndGet()
145 valSum = sum(val)
146 self.myOutput2.set(range(valSum, valSum + 10))
147 self.myOutput2.write()
148
149 for i in range(0, 5):
150 self.myInputPoll.read() # non-blocking (poll)
151 assert (self.myInputPoll == [43, 2]).all()
152
153 self.myInputWB.read()
154 assert self.myInputWB == 15
155 self.myInputWB.setAndWrite([28])
156 assert self.myInputWB == 28
157
158 self.myOutputRB.setAndWrite([120, 121])
159 self.myOutputRB.read()
160 assert (self.myOutputRB == [130, 131]).all()
161
162 self.myInput1.read()
163
164 except AssertionError as e:
165 print("\n".join(traceback.format_exception(e)))
166 sys.stdout.flush()
167 self.testError.setAndWrite("\n".join(traceback.format_exception(e)))
168
169# We cannot check the return channel of a ArrayOutputPushRB through the control system, so we use a second
170# module for this purpose
171
172
173class MySecondMod(ac.ApplicationModule):
174 def __init__(self, owner, name, description):
175 super().__init__(owner, name, description)
176
177 self.input = ac.ArrayPushInputWB(ac.DataType.int32, self, "/SomeName/ArrayOutRB", "", 2, "")
178
179 # these outputs are used to transport subject-to-test data to the C++ side for checking in the BOOST test case
180 self.testError = ac.ScalarOutput(ac.DataType.string, self, "TestError", "", "")
181
182 def mainLoop(self):
183 try:
184 assert (self.input == [42, 43]).all() # initial value as set in prepare()
185 self.input.read()
186 assert (self.input == [120, 121]).all()
187 self.input.setAndWrite([130, 131])
188 except AssertionError as e:
189 self.testError.setAndWrite("\n".join(traceback.format_exception(e)))
190
191
192ac.app.mod = MyMod(ac.app, "SomeName", "Module's description")
193ac.app.mod2 = MySecondMod(ac.app, "Foo", "Bar")
__init__(self, owner, name, description)
__init__(self, owner, name, description)
void mainLoop() override