lewis.core.adapters
This module contains Adapter
, which serves as a base class for concrete adapter
implementations in lewis.adapters
. It also contains AdapterCollection
which can
be used to store multiple adapters and manage them together.
Members
Base class for adapters |
|
A container to manage the adapters of a device |
|
A dummy context manager that raises a RuntimeError when it's used. |
- class lewis.core.adapters.Adapter(options: dict[str, Any] | None = None)[source]
Bases:
object
Base class for adapters
This class serves as a base class for concrete adapter implementations that expose a device via a certain communication protocol. It defines the minimal interface that an adapter must provide in order to fit seamlessly into other parts of the framework (most importantly
Simulation
).Sub-classes should re-define the
protocol
-member to something appropriate. While it is explicitly supported to modify it in concrete device interface implementations, it is good to have a default (for exampleepics
orstream
).An adapter should provide everything that is needed for the communication via the protocol it defines. This might involve constructing a server-object, configuring it and starting the service (this should happen in
start_server()
). Due to the large differences between protocols it is very hard to provide general guidelines here. Please take a look at the implementations of existing adapters (EpicsAdapter
,StreamAdapter
),to get some examples.In principle, an adapter can exist on its own, but it only really becomes useful when a device is bound to it. To do this, assign an object derived from
lewis.core.devices.DeviceBase
to thedevice
-property. Sub-classes have to implement_bind_device()
to achieve actual binding behavior.It is possible to pass a dictionary with configuration options to Adapter. The keys of the dictionary are accessible as properties of the
_options
-member. Only keys that are in thedefault_options
member of the class are accepted. Inheriting classes must overridedefault_options
to be a dictionary with the possible options for the adapter.Each adapter has a
lock
member, which contains aNoLock
by default. To make device access thread-safe, any adapter should acquire this lock before interacting with the device (or interface). This means that before starting the server component of an Adapter, a proper Lock-object needs to be assigned tolock
.- Parameters:
options – Configuration options for the adapter.
- property documentation: str
This property can be overridden in a sub-class to provide protocol documentation to users at runtime. By default it returns the indentation cleaned-up docstring of the class.
- handle(cycle_delay: float = 0.1) None [source]
This function is called on each cycle of a simulation. It should process requests that are made via the protocol that exposes the device. The time spent processing should be approximately
cycle_delay
seconds, during which the adapter may block the current process. It is desirable to stick to the provided time, but deviations are permissible if necessary due to the way the protocol works.- Parameters:
cycle_delay – Approximate time spent processing requests.
- property interface: InterfaceBase | None
The device property contains the device-object exposed by the adapter.
The property can be set from the outside, at that point the adapter will call
_bind_device()
(which is implemented in each adapter sub-class) and thus re-bind its commands etc. to call the new device.
- property is_running: bool
This property indicates whether the Adapter’s server is running and listening. The result of calls to
start_server()
andstop_server()
should be reflected as expected.
- start_server() None [source]
This method must be re-implemented to start the infrastructure required for the protocol in question. These startup operations are not supposed to be carried out on construction of the adapter in order to preserve control over when services are started during a run of a simulation.
Note
This method may be called multiple times over the lifetime of the Adapter, so it is important to make sure that this does not cause problems.
See also
See
stop_server()
for shutting down the adapter.
- stop_server() None [source]
This method must be re-implemented to stop and tear down anything that has been setup in
start_server()
. This method should close all connections to clients that have been established since the adapter has been started.Note
This method may be called multiple times over the lifetime of the Adapter, so it is important to make sure that this does not cause problems.
- class lewis.core.adapters.AdapterCollection(*args: Adapter)[source]
Bases:
object
A container to manage the adapters of a device
This container is designed to keep all adapters that expose a device in one place and interact with them in a uniform way.
Adapters can be passed as arguments upon construction or added later on using
add_adapter()
(and removed usingremove_adapter()
). The available protocols can be queried using theprotocols()
property.Each adapter can be started and stopped separately by supplying protocol names to
connect()
anddisconnect()
, both methods accept an arbitrary number of arguments, so that any subset of the stored protocols can be handled at any time. Supplying no protocol names at all will start/stop all adapters. These semantics also apply foris_connected()
and documentation.This class also makes sure that all adapters use the same Lock for device interaction.
- Parameters:
args – List of adapters to add to the container
- add_adapter(adapter: Adapter) None [source]
Adds the supplied adapter to the container but raises a
RuntimeError
if there’s already an adapter registered for the same protocol.- Parameters:
adapter – Adapter to add to the container
- configuration(*args: str) dict[str | None, dict[str, Any]] [source]
Returns a dictionary that contains the options for the specified adapter. The dictionary keys are the adapter protocols.
- Parameters:
args – List of protocols for which to list options, empty for all adapters.
- Returns:
Dict of protocol: option-dict pairs.
- connect(*args: str) None [source]
This method starts an adapter for each specified protocol in a separate thread, if the adapter is not already running.
- Parameters:
args – List of protocols for which to start adapters or empty for all.
- property device_lock: allocate_lock
This lock is passed to each adapter when it’s started. It’s supposed to be used to ensure that the device is only accessed from one thread at a time, for example during network IO.
Simulation
uses this lock to block the device during the simulation cycle calculations.
- disconnect(*args: str) None [source]
Stops all adapters for the specified protocols. The method waits for each adapter thread to join, so it might hang if the thread is not terminating correctly.
- Parameters:
args – List of protocols for which to stop adapters or empty for all.
- documentation(*args: str) str [source]
Returns the concatenated documentation for the adapters specified by the supplied protocols or all of them if no arguments are provided.
- Parameters:
args – List of protocols for which to get documentation or empty for all.
- Returns:
Documentation for all selected adapters.
- is_connected(*args: str) bool | dict[str | None, bool] [source]
If only one protocol is supplied, a single bool is returned with the connection status. Otherwise, this method returns a dictionary of adapter connection statuses for the supplied protocols. If no protocols are supplied, all adapter statuses are returned.
- Parameters:
args – List of protocols for which to start adapters or empty for all.
- Returns:
Boolean for single adapter or dict of statuses for multiple.
- property protocols: list[str]
List of protocols for which adapters are registered.
- remove_adapter(protocol: str) None [source]
Tries to remove the adapter for the specified protocol, raises a
RuntimeError
if there is no adapter registered for that particular protocol.- Parameters:
protocol – Protocol to remove from container
- set_device(new_device: DeviceBase) None [source]
Bind the new device to all interfaces managed by the adapters in the collection.