Skip to content

Commit

Permalink
Improved _NoDevice mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
Dennis-van-Gils committed Jun 12, 2024
1 parent af48c3d commit e1c6498
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 85 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
Changelog
=========

1.4.0 (2024-06-11)
1.4.0 (2024-06-12)
------------------
* Using ``qtpy`` library instead of my own Qt5/6 mechanism
* Improved ``_NoDevice`` mechanism
* Removed redundant ``attach_device()``
* Extra check in ``Worker_jobs`` if ``func`` is actually a callable.
* Using singletons ``Uninitialized_Worker_DAQ/jobs`` as default attribute
values instead of using ``None``. This solves pylint warnings on '... is not a
Expand Down
1 change: 0 additions & 1 deletion docs/api-qdeviceio.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ Signals
Methods
--------------------

.. automethod:: dvg_qdeviceio.QDeviceIO.attach_device
.. automethod:: dvg_qdeviceio.QDeviceIO.create_worker_DAQ
.. automethod:: dvg_qdeviceio.QDeviceIO.create_worker_jobs
.. automethod:: dvg_qdeviceio.QDeviceIO.start
Expand Down
106 changes: 35 additions & 71 deletions src/dvg_qdeviceio.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ class DAQ_TRIGGER(IntEnum):
# fmt: on


class _NoDevice:
name = "NoDevice"
is_alive = False
mutex = QtCore.QMutex()


# ------------------------------------------------------------------------------
# QDeviceIO
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -137,7 +143,7 @@ def __init__(
.. _`QDeviceIO_args`:
Args:
dev (:obj:`object` | :obj:`None`, optional):
dev (:obj:`object` | :obj:`_NoDevice`, optional):
Reference to a user-supplied *device* class instance containing
I/O methods. In addition, `dev` should also have the following
members. If not, they will be injected into the `dev` instance for
Expand All @@ -153,7 +159,7 @@ def __init__(
* **dev.is_alive** (:obj:`bool`) -- Device is up and \
communicatable? Default: :const:`True`.
Default: :obj:`None`
Default: :obj:`_NoDevice`
**kwargs:
All remaining keyword arguments will be passed onto inherited class
Expand All @@ -163,7 +169,7 @@ def __init__(
.. rubric:: Attributes:
Attributes:
dev (:obj:`object` | :obj:`None`):
dev (:obj:`object` | :obj:`_NoDevice`):
Reference to a user-supplied *device* class instance containing
I/O methods.
Expand Down Expand Up @@ -247,12 +253,19 @@ def my_GUI_redraw_routine():
_request_worker_DAQ_pause = Signal()
_request_worker_DAQ_unpause = Signal()

def __init__(self, dev=None, **kwargs):
def __init__(self, dev=_NoDevice(), **kwargs):
super().__init__(**kwargs) # Pass **kwargs onto QtCore.QObject()

self.dev = self._NoDevice()
if dev is not None:
self.attach_device(dev)
if not hasattr(dev, "name"):
dev.name = "myDevice"

if not hasattr(dev, "mutex"):
dev.mutex = QtCore.QMutex()

if not hasattr(dev, "is_alive"):
dev.is_alive = True # Assume the device is alive from the start

self.dev = dev

self._thread_DAQ = None
self._thread_jobs = None
Expand All @@ -275,54 +288,6 @@ def __init__(self, dev=None, **kwargs):
self._mutex_wait_worker_DAQ = QtCore.QMutex()
self._mutex_wait_worker_jobs = QtCore.QMutex()

class _NoDevice:
name = "NoDevice"
is_alive = False
mutex = QtCore.QMutex()

# --------------------------------------------------------------------------
# attach_device
# --------------------------------------------------------------------------

def attach_device(self, dev):
"""Attach a reference to a user-supplied *device* class instance
containing I/O methods. In addition, `dev` should also have the
following members. If not, they will be injected into the `dev`
instance for you:
* **dev.name** (:obj:`str`) -- Short display name for the \
device. Default: "myDevice".
* **dev.mutex** (:class:`PySide6.QtCore.QMutex`) -- To allow \
for properly multithreaded device I/O operations. It will \
be used by :class:`Worker_DAQ` and :class:`Worker_jobs`.
* **dev.is_alive** (:obj:`bool`) -- Device is up and \
communicatable? Default: :const:`True`.
Args:
dev (:obj:`object`):
Reference to a user-supplied *device* class instance containing
I/O methods.
"""
if not hasattr(dev, "name"):
dev.name = "myDevice"

if not hasattr(dev, "mutex"):
dev.mutex = QtCore.QMutex()

if not hasattr(dev, "is_alive"):
dev.is_alive = True # Assume the device is alive from the start

if isinstance(self.dev, self._NoDevice):
self.dev = dev
else:
pft(
"Device can be attached only once. Already attached to "
f"'{self.dev.name}'."
)
sys.exit(22)

# --------------------------------------------------------------------------
# Create workers
# --------------------------------------------------------------------------
Expand Down Expand Up @@ -457,11 +422,8 @@ def my_DAQ_function():
All remaining keyword arguments will be passed onto inherited class
:class:`PySide6.QtCore.QObject`.
"""
if isinstance(self.dev, self._NoDevice):
pft(
"Can't create worker_DAQ, because there is no device attached."
" Did you forget to call 'attach_device()' first?"
)
if isinstance(self.dev, _NoDevice):
pft("Can't create worker_DAQ, because there is no device attached.")
sys.exit(99)

self.worker_DAQ = Worker_DAQ(
Expand Down Expand Up @@ -582,10 +544,9 @@ def my_jobs_function(func, args):
All remaining keyword arguments will be passed onto inherited
class :class:`PySide6.QtCore.QObject`.
"""
if isinstance(self.dev, self._NoDevice):
if isinstance(self.dev, _NoDevice):
pft(
"Can't create worker_jobs, because there is no device attached."
" Did you forget to call 'attach_device()' first?"
)
sys.exit(99)

Expand Down Expand Up @@ -1071,7 +1032,7 @@ def __init__(
self.debug_color = ANSI.CYAN

self.qdev = qdev
self.dev = None if qdev is None else qdev.dev
self.dev = _NoDevice() if qdev is None else qdev.dev

self._DAQ_trigger = DAQ_trigger
self.DAQ_function = DAQ_function
Expand Down Expand Up @@ -1460,13 +1421,6 @@ def wake_up(self):
self._qwc.wakeAll()


# fmt: off
Uninitialized_Worker_DAQ = Worker_DAQ(None) # pyright: ignore [reportArgumentType]
"""Singleton to compare against to test for an uninitialized `Worker_DAQ`
instance."""
# fmt: on


# ------------------------------------------------------------------------------
# Worker_jobs
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -1523,7 +1477,7 @@ def __init__(
self.debug_color = ANSI.YELLOW

self.qdev = qdev
self.dev = None if qdev is None else qdev.dev
self.dev = _NoDevice() if qdev is None else qdev.dev

self.jobs_function = jobs_function
self._has_started = False
Expand Down Expand Up @@ -1760,6 +1714,16 @@ def process_queue(self):
self._qwc.wakeAll()


# ------------------------------------------------------------------------------
# Singletons
# ------------------------------------------------------------------------------

# fmt: off
Uninitialized_Worker_DAQ = Worker_DAQ(None) # pyright: ignore [reportArgumentType]
"""Singleton to compare against to test for an uninitialized `Worker_DAQ`
instance."""
# fmt: on

# fmt: off
Uninitialized_Worker_jobs = Worker_jobs(None) # pyright: ignore [reportArgumentType]
"""Singleton to compare against to test for an uninitialized `Worker_jobs`
Expand Down
12 changes: 0 additions & 12 deletions tests/test_dvg_qdeviceio.py
Original file line number Diff line number Diff line change
Expand Up @@ -376,17 +376,6 @@ def jobs_function(func, args):
assert cnt_jobs_updated == 3


def test_attach_device_twice():
print_title("Attach device twice")

qdev = QDeviceIO(FakeDevice())
with pytest.raises(SystemExit) as pytest_wrapped_e:
qdev.attach_device(FakeDevice())
assert pytest_wrapped_e.type == SystemExit
dprint(f"Exit code: {pytest_wrapped_e.value.code}")
assert pytest_wrapped_e.value.code == 22


def test_Worker_DAQ___no_device_attached():
print_title("Worker_DAQ - no device attached")

Expand Down Expand Up @@ -661,7 +650,6 @@ def DAQ_function():
test_Worker_jobs()
test_Worker_jobs__start_dead()
test_Worker_jobs__jobs_function()
test_attach_device_twice()
test_Worker_DAQ___no_device_attached()
test_Worker_jobs__no_device_attached()
test_Worker_DAQ___start_without_create()
Expand Down

0 comments on commit e1c6498

Please sign in to comment.