Skip to content

Commit 877a89c

Browse files
Code review changes from Michael. Includes:
- SetBlocking returns the old blocking state value. Added test. - Fix some style issues - Make completion function on the dispatcher optional, to maintain some compatibility with the previous API
1 parent fdeca46 commit 877a89c

File tree

6 files changed

+49
-26
lines changed

6 files changed

+49
-26
lines changed

docs/reference/api.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,16 @@ record creation function.
377377

378378
.. function:: SetBlocking(blocking)
379379

380-
This can be used to globally set the default `blocking` flag, which will
381-
apply to all records created after this point. This allows blocking to be
380+
This can be used to globally set the default of the `blocking` flag, which
381+
will apply to all records created after this point. This allows blocking to be
382382
easily set/unset when creating groups of records.
383383

384+
Returns the previous value of the `blocking` flag, which enables code like this::
385+
386+
old_blocking = SetBlocking(new_blocking)
387+
create_records()
388+
SetBlocking(old_blocking)
389+
384390
This does not change the blocking value for any already created records.
385391

386392
.. seealso::

softioc/asyncio_dispatcher.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ def aioJoin(worker=worker, loop=self.loop):
3232
else:
3333
self.loop = loop
3434

35-
def __call__(self, func, completion, func_args=(), completion_args=()):
35+
def __call__(
36+
self,
37+
func,
38+
func_args=(),
39+
completion = None,
40+
completion_args=()):
3641
async def async_wrapper():
3742
try:
38-
if inspect.iscoroutinefunction(func):
39-
await func(*func_args)
40-
else:
41-
ret = func(*func_args)
42-
# Handle the case of a synchronous function that returns a
43-
# coroutine, like the lambda for on_update_name does
44-
if inspect.isawaitable(ret):
45-
await ret
46-
completion(*completion_args)
43+
ret = func(*func_args)
44+
if inspect.isawaitable(ret):
45+
await ret
46+
if completion:
47+
completion(*completion_args)
4748
except Exception:
4849
logging.exception("Exception when awaiting callback")
4950
asyncio.run_coroutine_threadsafe(async_wrapper(), self.loop)

softioc/cothread_dispatcher.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@ def __init__(self):
1010
# processing doesn't interfere with other callback processing.
1111
self.__dispatcher = cothread.cothread._Callback()
1212

13-
def __call__(self, func, completion, func_args=(), completion_args=()):
13+
def __call__(
14+
self,
15+
func,
16+
func_args=(),
17+
completion = None,
18+
completion_args=()):
1419
def wrapper():
1520
func(*func_args)
16-
completion(*completion_args)
21+
if completion:
22+
completion(*completion_args)
1723
self.__dispatcher(wrapper)

softioc/device.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
from inspect import iscoroutinefunction
21
import os
32
import time
43
import ctypes
54
from ctypes import *
65
import numpy
7-
from threading import Event
86

97
from . import alarm
108
from . import fields
@@ -19,17 +17,19 @@
1917

2018

2119
# This is set from softioc.iocInit
22-
# dispatcher(func, *args) will queue a callback to happen
2320
dispatcher = None
2421

2522
# Global blocking flag, used to mark asynchronous (False) or synchronous (True)
2623
# processing modes for Out records.
2724
# Default False to maintain behaviour from previous versions.
2825
blocking = False
2926

30-
def SetBlocking(val):
27+
# Set the current global blocking flag, and return the previous value.
28+
def SetBlocking(new_val):
3129
global blocking
32-
blocking = val
30+
old_val = blocking
31+
blocking = new_val
32+
return old_val
3333

3434

3535
# EPICS processing return codes
@@ -163,7 +163,6 @@ def __init__(self, name, **kargs):
163163
if self._blocking:
164164
self._callback = create_callback_capsule()
165165

166-
167166
self.__super.__init__(name, **kargs)
168167

169168
def init_record(self, record):
@@ -188,7 +187,6 @@ def __completion(self, record):
188187
'''Signals that all on_update processing is finished'''
189188
if self._blocking:
190189
signal_processing_complete(record, self._callback)
191-
pass
192190

193191
def _process(self, record):
194192
'''Processing suitable for output records. Performs immediate value
@@ -218,10 +216,9 @@ def _process(self, record):
218216
record.PACT = self._blocking
219217
dispatcher(
220218
self.__on_update,
221-
self.__completion,
222219
func_args=(python_value,),
223-
completion_args=(record,)
224-
)
220+
completion = self.__completion,
221+
completion_args=(record,))
225222

226223
return EPICS_OK
227224

softioc/imports.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,7 @@ def signal_processing_complete(record, callback):
3535
_extension.signal_processing_complete(
3636
record.PRIO,
3737
record.record.value,
38-
callback
39-
)
38+
callback)
4039

4140
def expect_success(status, function, args):
4241
assert status == 0, 'Expected success'

tests/test_records.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,20 @@ def test_blocking_global_flag_creates_attributes(self):
536536
bo3 = builder.boolOut("OUTREC3", blocking=True)
537537
self.check_record_blocking_attributes(bo3)
538538

539+
def test_blocking_returns_old_state(self):
540+
"""Test that SetBlocking returns the previously set value"""
541+
old_val = SetBlocking(True)
542+
assert old_val is False # Default is False
543+
544+
old_val = SetBlocking(False)
545+
assert old_val is True
546+
547+
# Test it correctly maintains state when passed the current value
548+
old_val = SetBlocking(False)
549+
assert old_val is False
550+
old_val = SetBlocking(False)
551+
assert old_val is False
552+
539553
def blocking_test_func(self, device_name, conn):
540554

541555
builder.SetDeviceName(device_name)

0 commit comments

Comments
 (0)