Skip to content

Commit e5fa971

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 e5fa971

1 file changed

Lines changed: 25 additions & 81 deletions

File tree

‎tests/test_record_values.py‎

Lines changed: 25 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,25 @@ 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 native Python
295+
# type, or the value returned from p4p, which must be unwrapped
296+
if type(actual_value) == p4p.nt.enum.ntenum:
297+
actual_val_type = type(actual_value.raw["value"].get("index"))
298+
elif isinstance(actual_value, p4p.nt.scalar.ntwrappercommon):
299+
actual_val_type = type(actual_value.raw["value"])
300+
else:
301+
actual_val_type = type(actual_value)
302+
320303
try:
321304
if type(expected_value) == float and isnan(expected_value):
322305
assert isnan(actual_value) # NaN != Nan, so needs special case
323306
elif creation_func in [builder.WaveformOut, builder.WaveformIn]:
324307
assert numpy.array_equal(actual_value, expected_value)
325-
assert type(actual_value) == expected_type
308+
assert actual_val_type == expected_type
326309
else:
327310
assert actual_value == expected_value
328-
assert type(actual_value) == expected_type
311+
assert actual_val_type == expected_type
329312
except AssertionError as e:
330313
msg = (
331314
"Failed with parameters: "
@@ -479,18 +462,10 @@ def is_valid(configuration):
479462
# Wait for message that IOC has started
480463
select_and_recv(parent_conn, "R")
481464

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
465+
from p4p.client.thread import Context
466+
ctx = Context('pva')
487467

488468
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()
494469

495470
for configuration in record_configurations:
496471
(
@@ -501,52 +476,24 @@ def is_valid(configuration):
501476
expected_type,
502477
) = configuration
503478

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-
519479
if set_enum == SetValueEnum.CAPUT:
520480
if get_enum == GetValueEnum.GET:
521481
select_and_recv(parent_conn)
522-
caput(
523-
DEVICE_NAME + ":" + record_name,
524-
initial_value,
525-
wait=True,
526-
**kwargs,
527-
**put_kwarg,
528-
)
482+
ctx.put(DEVICE_NAME + ":" + record_name,
483+
initial_value,
484+
None,
485+
timeout=TIMEOUT,
486+
wait=True,
487+
)
529488

530489
if get_enum == GetValueEnum.GET:
531490
parent_conn.send("G") # "Get"
532491

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-
539492
if get_enum == GetValueEnum.GET:
540493
rec_val = select_and_recv(parent_conn)
541494
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
495+
rec_val = ctx.get(DEVICE_NAME + ":" + record_name,
496+
timeout=TIMEOUT,)
550497

551498
if (
552499
creation_func in [builder.WaveformOut, builder.WaveformIn]
@@ -569,9 +516,6 @@ def is_valid(configuration):
569516
creation_func, rec_val, expected_value, expected_type
570517
)
571518
finally:
572-
# Purge cache to suppress spurious "IOC disconnected" exceptions
573-
_channel_cache.purge()
574-
575519
parent_conn.send("D") # "Done"
576520

577521
ioc_process.join(timeout=TIMEOUT)

0 commit comments

Comments
 (0)