Skip to content

Commit d38df9b

Browse files
Refactor some tests to use p4p
It is necessary as ChannelAccess does not support int64 natively, instead transferring it using a double. This means the value returned from caget is actually a float, which is inconvenient. Fortunately p4p (using PVAccess) does support int64! I deleted some test cases as they were really testing the behaviour of caget/caput, and not pythonSoftIoc itself.
1 parent 1d9468f commit d38df9b

File tree

1 file changed

+26
-81
lines changed

1 file changed

+26
-81
lines changed

tests/test_record_values.py

Lines changed: 26 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List
22
import numpy
3+
import p4p.nt
34
import pytest
45

56
from enum import Enum
@@ -137,38 +138,10 @@ def record_values_names(fixture_value):
137138
numpy.array([1.5, 2.6, 3.7], dtype=numpy.float64),
138139
numpy.ndarray,
139140
),
140-
(
141-
"wIn_int",
142-
builder.WaveformIn,
143-
567,
144-
numpy.array([567.], dtype=numpy.float64),
145-
numpy.ndarray,
146-
),
147-
(
148-
"wOut_int",
149-
builder.WaveformOut,
150-
567,
151-
numpy.array([567.], dtype=numpy.float64),
152-
numpy.ndarray,
153-
),
154-
(
155-
"wIn_float",
156-
builder.WaveformIn,
157-
12.345,
158-
numpy.array([12.345], dtype=numpy.float64),
159-
numpy.ndarray,
160-
),
161-
(
162-
"wOut_float",
163-
builder.WaveformOut,
164-
12.345,
165-
numpy.array([12.345], dtype=numpy.float64),
166-
numpy.ndarray,
167-
),
168141
(
169142
"wIn_bytes",
170143
builder.WaveformIn,
171-
b"HELLO\0WORLD",
144+
[72, 69, 76, 76, 79, 0, 87, 79, 82, 76, 68],
172145
numpy.array(
173146
[72, 69, 76, 76, 79, 0, 87, 79, 82, 76, 68], dtype=numpy.uint8
174147
),
@@ -177,7 +150,7 @@ def record_values_names(fixture_value):
177150
(
178151
"wOut_bytes",
179152
builder.WaveformOut,
180-
b"HELLO\0WORLD",
153+
[72, 69, 76, 76, 79, 0, 87, 79, 82, 76, 68],
181154
numpy.array(
182155
[72, 69, 76, 76, 79, 0, 87, 79, 82, 76, 68], dtype=numpy.uint8
183156
),
@@ -317,15 +290,26 @@ def record_value_asserts(
317290
):
318291
"""Asserts that the expected value and expected type are matched with
319292
the actual value. Handles both scalar and waveform data"""
293+
294+
# This function is shared between functions that may pass in either a
295+
# native Python type, or the value returned from p4p, which must be
296+
# unwrapped
297+
if type(actual_value) == p4p.nt.enum.ntenum:
298+
actual_val_type = type(actual_value.raw["value"].get("index"))
299+
elif isinstance(actual_value, p4p.nt.scalar.ntwrappercommon):
300+
actual_val_type = type(actual_value.raw["value"])
301+
else:
302+
actual_val_type = type(actual_value)
303+
320304
try:
321305
if type(expected_value) == float and isnan(expected_value):
322306
assert isnan(actual_value) # NaN != Nan, so needs special case
323307
elif creation_func in [builder.WaveformOut, builder.WaveformIn]:
324308
assert numpy.array_equal(actual_value, expected_value)
325-
assert type(actual_value) == expected_type
309+
assert actual_val_type == expected_type
326310
else:
327311
assert actual_value == expected_value
328-
assert type(actual_value) == expected_type
312+
assert actual_val_type == expected_type
329313
except AssertionError as e:
330314
msg = (
331315
"Failed with parameters: "
@@ -479,18 +463,10 @@ def is_valid(configuration):
479463
# Wait for message that IOC has started
480464
select_and_recv(parent_conn, "R")
481465

482-
# Cannot do these imports before the subprocess starts, as the subprocess
483-
# would inherit cothread's internal state which would break things!
484-
from cothread import Yield
485-
from cothread.catools import caget, caput, _channel_cache
486-
from cothread.dbr import DBR_CHAR_STR
466+
from p4p.client.thread import Context
467+
ctx = Context('pva')
487468

488469
try:
489-
# cothread remembers connected IOCs. As we potentially restart the same
490-
# named IOC multiple times, we have to purge the cache else the
491-
# result from caget/caput cache would be a DisconnectError during the
492-
# second test
493-
_channel_cache.purge()
494470

495471
for configuration in record_configurations:
496472
(
@@ -501,52 +477,24 @@ def is_valid(configuration):
501477
expected_type,
502478
) = configuration
503479

504-
# Infer some required keywords from parameters
505-
kwargs = {}
506-
put_kwarg = {}
507-
if creation_func in [builder.longStringIn, builder.longStringOut]:
508-
kwargs["datatype"] = DBR_CHAR_STR
509-
510-
if (creation_func in [builder.WaveformIn, builder.WaveformOut]
511-
and type(initial_value) is bytes):
512-
# There's a bug in caput that means DBR_CHAR_STR doesn't
513-
# truncate the array of the target record, meaning .get()
514-
# returns all NELM rather than just NORD elements. Instead we
515-
# encode the data ourselves
516-
initial_value = numpy.frombuffer(
517-
initial_value, dtype = numpy.uint8)
518-
519480
if set_enum == SetValueEnum.CAPUT:
520481
if get_enum == GetValueEnum.GET:
521482
select_and_recv(parent_conn)
522-
caput(
523-
DEVICE_NAME + ":" + record_name,
524-
initial_value,
525-
wait=True,
526-
**kwargs,
527-
**put_kwarg,
528-
)
483+
ctx.put(DEVICE_NAME + ":" + record_name,
484+
initial_value,
485+
None,
486+
timeout=TIMEOUT,
487+
wait=True,
488+
)
529489

530490
if get_enum == GetValueEnum.GET:
531491
parent_conn.send("G") # "Get"
532492

533-
# Ensure IOC process has time to execute.
534-
# I saw failures on MacOS where it appeared the IOC had not
535-
# processed the put'ted value as the caget returned the same
536-
# value as was originally passed in.
537-
Yield(timeout=TIMEOUT)
538-
539493
if get_enum == GetValueEnum.GET:
540494
rec_val = select_and_recv(parent_conn)
541495
else:
542-
rec_val = caget(
543-
DEVICE_NAME + ":" + record_name,
544-
timeout=TIMEOUT,
545-
**kwargs,
546-
)
547-
# '+' operator used to convert cothread's types into Python
548-
# native types e.g. "+ca_int" -> int
549-
rec_val = +rec_val
496+
rec_val = ctx.get(DEVICE_NAME + ":" + record_name,
497+
timeout=TIMEOUT,)
550498

551499
if (
552500
creation_func in [builder.WaveformOut, builder.WaveformIn]
@@ -569,9 +517,6 @@ def is_valid(configuration):
569517
creation_func, rec_val, expected_value, expected_type
570518
)
571519
finally:
572-
# Purge cache to suppress spurious "IOC disconnected" exceptions
573-
_channel_cache.purge()
574-
575520
parent_conn.send("D") # "Done"
576521

577522
ioc_process.join(timeout=TIMEOUT)

0 commit comments

Comments
 (0)