11from typing import List
22import numpy
3+ import p4p .nt
34import pytest
45
56from 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 \0 WORLD" ,
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 \0 WORLD" ,
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