Source code for QInstrument.lib.QFakeInstrument

import logging
from .QAbstractInstrument import QAbstractInstrument

logger = logging.getLogger(__name__)


[docs] class QFakeInstrument(QAbstractInstrument): '''Base class for fake instruments used in UI development without hardware. Provides an in-memory property store and a :meth:`_register` override so that a concrete fake can be derived from both ``QFakeInstrument`` and a real instrument class with minimal boilerplate: .. code-block:: python class QFakeDS345(QFakeInstrument, QDS345): pass MRO resolution ensures that :meth:`_register` here is called instead of the real instrument's version, wiring every standard property to :attr:`_store` rather than to the serial port. :meth:`__init__` initializes :attr:`_store`, then calls ``QAbstractInstrument.__init__`` directly, bypassing ``QSerialInstrument`` so no serial port is created. ``QAbstractInstrument.__init__`` calls ``_registerProperties()`` and ``_registerMethods()`` automatically. Properties whose getters cannot be expressed through :meth:`_register` (non-standard response formats, internal state) must be re-registered by the concrete fake after calling ``super()._registerProperties()``. :meth:`registerProperty` overwrites any previous registration for the same name, so this is safe. Subclasses that do not inherit a real instrument class may define their own ``__init__``, call ``super().__init__()``, and then register properties directly via :meth:`registerProperty`. ''' def __init__(self, *args, **kwargs) -> None: '''Initialize the in-memory store and register all properties. Initializes :attr:`_store` before calling ``QAbstractInstrument.__init__`` explicitly (bypassing ``QSerialInstrument`` so no serial port is created). ``QAbstractInstrument.__init__`` calls ``_registerProperties()`` and ``_registerMethods()``, so :attr:`_store` must exist first. ''' self._store: dict = {} self.identification = f'Fake {type(self).__name__}' QAbstractInstrument.__init__(self, *args, **kwargs) def _register(self, name: str, cmd: str, dtype: type = float) -> None: '''Register a property backed by :attr:`_store`. Overrides the real instrument's ``_register()`` via MRO. *cmd* is ignored; values are stored and retrieved by *name*. Parameters ---------- name : str Property name passed to :meth:`registerProperty`. cmd : str Ignored. Present to match the real instrument's signature. dtype : type, optional Value type for storage coercion. Default: ``float``. ''' def getter(): return self._store.get(name, dtype()) def setter(v): self._store[name] = dtype(v) self.registerProperty(name, getter=getter, setter=setter, ptype=dtype)
[docs] def transmit(self, data) -> None: '''No-op: fake instruments have no transport layer.''' pass
[docs] def receive(self, **kwargs) -> str: '''No-op: fake instruments have no transport layer.''' return ''
[docs] def isOpen(self) -> bool: '''Return ``True``: fake instruments are always available.''' return True
__all__ = ['QFakeInstrument']