Skip to content

Commit a657661

Browse files
authored
Merge pull request #316 from ISISComputingGroup/ruff_pyright_day
Ruff pyright day
2 parents e283376 + 9f20693 commit a657661

File tree

4 files changed

+112
-115
lines changed

4 files changed

+112
-115
lines changed

lewis/core/adapters.py

Lines changed: 55 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,15 @@
2222
implementations in :mod:`lewis.adapters`. It also contains :class:`AdapterCollection` which can
2323
be used to store multiple adapters and manage them together.
2424
"""
25+
2526
import inspect
27+
import logging
2628
import threading
2729
from collections import namedtuple
30+
from types import TracebackType
31+
from typing import Any, Optional, Type
2832

33+
from lewis.core.devices import DeviceBase, InterfaceBase
2934
from lewis.core.exceptions import LewisException
3035
from lewis.core.logging import has_log
3136
from lewis.core.utils import dict_strict_update
@@ -38,13 +43,18 @@ class NoLock:
3843
that device/interface access is synchronous.
3944
"""
4045

41-
def __enter__(self):
46+
def __enter__(self) -> None:
4247
raise RuntimeError(
4348
"The attempted action requires a proper threading.Lock-object, "
4449
"but none was available."
4550
)
4651

47-
def __exit__(self, exc_type, exc_val, exc_tb):
52+
def __exit__(
53+
self,
54+
exctype: Optional[Type[BaseException]],
55+
excinst: Optional[BaseException],
56+
exctb: Optional[TracebackType],
57+
) -> None:
4858
pass
4959

5060

@@ -89,11 +99,11 @@ class Adapter:
8999

90100
default_options = {}
91101

92-
def __init__(self, options=None):
102+
def __init__(self, options: dict[str, Any] | None = None) -> None:
93103
super(Adapter, self).__init__()
94104
self._interface = None
95105

96-
self.device_lock = NoLock()
106+
self.device_lock: threading.Lock | NoLock = NoLock()
97107

98108
options = options or {}
99109
combined_options = dict(self.default_options)
@@ -111,14 +121,14 @@ def __init__(self, options=None):
111121
self._options = options_type(**combined_options)
112122

113123
@property
114-
def protocol(self):
124+
def protocol(self) -> str | None:
115125
if self.interface is None:
116126
return None
117127

118128
return self.interface.protocol
119129

120130
@property
121-
def interface(self):
131+
def interface(self) -> InterfaceBase | None:
122132
"""
123133
The device property contains the device-object exposed by the adapter.
124134
@@ -129,18 +139,18 @@ def interface(self):
129139
return self._interface
130140

131141
@interface.setter
132-
def interface(self, new_interface):
142+
def interface(self, new_interface: InterfaceBase | None) -> None:
133143
self._interface = new_interface
134144

135145
@property
136-
def documentation(self):
146+
def documentation(self) -> str:
137147
"""
138148
This property can be overridden in a sub-class to provide protocol documentation to users
139149
at runtime. By default it returns the indentation cleaned-up docstring of the class.
140150
"""
141151
return inspect.getdoc(self) or ""
142152

143-
def start_server(self):
153+
def start_server(self) -> None:
144154
"""
145155
This method must be re-implemented to start the infrastructure required for the
146156
protocol in question. These startup operations are not supposed to be carried out on
@@ -159,7 +169,7 @@ def start_server(self):
159169
"required for network communication."
160170
)
161171

162-
def stop_server(self):
172+
def stop_server(self) -> None:
163173
"""
164174
This method must be re-implemented to stop and tear down anything that has been setup
165175
in :meth:`start_server`. This method should close all connections to clients that have
@@ -176,7 +186,7 @@ def stop_server(self):
176186
)
177187

178188
@property
179-
def is_running(self):
189+
def is_running(self) -> bool:
180190
"""
181191
This property indicates whether the Adapter's server is running and listening. The result
182192
of calls to :meth:`start_server` and :meth:`stop_server` should be reflected as expected.
@@ -186,7 +196,7 @@ def is_running(self):
186196
"a server is currently running and listening for requests."
187197
)
188198

189-
def handle(self, cycle_delay=0.1):
199+
def handle(self, cycle_delay: float = 0.1) -> None:
190200
"""
191201
This function is called on each cycle of a simulation. It should process requests that are
192202
made via the protocol that exposes the device. The time spent processing should be
@@ -222,18 +232,19 @@ class AdapterCollection:
222232
:param args: List of adapters to add to the container
223233
"""
224234

225-
def __init__(self, *args):
235+
def __init__(self, *args: Adapter) -> None:
226236
self._adapters = {}
227237

228238
self._threads = {}
229239
self._running = {}
230240
self._lock = threading.Lock()
241+
self.log: logging.Logger
231242

232243
for adapter in args:
233244
self.add_adapter(adapter)
234245

235246
@property
236-
def device_lock(self):
247+
def device_lock(self) -> threading.Lock:
237248
"""
238249
This lock is passed to each adapter when it's started. It's supposed to be used to ensure
239250
that the device is only accessed from one thread at a time, for example during network IO.
@@ -242,12 +253,12 @@ def device_lock(self):
242253
"""
243254
return self._lock
244255

245-
def set_device(self, new_device):
256+
def set_device(self, new_device: DeviceBase) -> None:
246257
"""Bind the new device to all interfaces managed by the adapters in the collection."""
247258
for adapter in self._adapters.values():
248259
adapter.interface.device = new_device
249260

250-
def add_adapter(self, adapter):
261+
def add_adapter(self, adapter: Adapter) -> None:
251262
"""
252263
Adds the supplied adapter to the container but raises a ``RuntimeError`` if there's
253264
already an adapter registered for the same protocol.
@@ -256,14 +267,12 @@ def add_adapter(self, adapter):
256267
"""
257268
if adapter.protocol in self._adapters:
258269
raise RuntimeError(
259-
"Adapter for protocol '{}' is already registered.".format(
260-
adapter.protocol
261-
)
270+
"Adapter for protocol '{}' is already registered.".format(adapter.protocol)
262271
)
263272

264273
self._adapters[adapter.protocol] = adapter
265274

266-
def remove_adapter(self, protocol):
275+
def remove_adapter(self, protocol: str) -> None:
267276
"""
268277
Tries to remove the adapter for the specified protocol, raises a ``RuntimeError`` if there
269278
is no adapter registered for that particular protocol.
@@ -272,37 +281,31 @@ def remove_adapter(self, protocol):
272281
"""
273282
if protocol not in self._adapters:
274283
raise RuntimeError(
275-
"Can not remove adapter for protocol '{}', none registered.".format(
276-
protocol
277-
)
284+
"Can not remove adapter for protocol '{}', none registered.".format(protocol)
278285
)
279286

280287
del self._adapters[protocol]
281288

282289
@property
283-
def protocols(self):
290+
def protocols(self) -> list[str]:
284291
"""List of protocols for which adapters are registered."""
285292
return list(self._adapters.keys())
286293

287-
def connect(self, *args):
294+
def connect(self, *args: str) -> None:
288295
"""
289296
This method starts an adapter for each specified protocol in a separate thread, if the
290297
adapter is not already running.
291298
292299
:param args: List of protocols for which to start adapters or empty for all.
293300
"""
294-
for adapter in self._get_adapters(args):
301+
for adapter in self._get_adapters(list(args)):
295302
self._start_server(adapter)
296303

297-
def _start_server(self, adapter):
304+
def _start_server(self, adapter: Adapter) -> None:
298305
if adapter.protocol not in self._threads:
299-
self.log.info(
300-
"Connecting device interface for protocol '%s'", adapter.protocol
301-
)
306+
self.log.info("Connecting device interface for protocol '%s'", adapter.protocol)
302307

303-
adapter_thread = threading.Thread(
304-
target=self._adapter_loop, args=(adapter, 0.01)
305-
)
308+
adapter_thread = threading.Thread(target=self._adapter_loop, args=(adapter, 0.01))
306309
adapter_thread.daemon = True
307310

308311
self._threads[adapter.protocol] = adapter_thread
@@ -313,14 +316,10 @@ def _start_server(self, adapter):
313316
# Block until server is actually listening
314317
self._running[adapter.protocol].wait(2.0)
315318
if not self._running[adapter.protocol].is_set():
316-
raise LewisException(
317-
"Adapter for '%s' failed to start!" % adapter.protocol
318-
)
319+
raise LewisException("Adapter for '%s' failed to start!" % adapter.protocol)
319320

320-
def _adapter_loop(self, adapter, dt):
321-
adapter.device_lock = (
322-
self._lock
323-
) # This ensures that the adapter is using the correct lock
321+
def _adapter_loop(self, adapter: Adapter, dt: float) -> None:
322+
adapter.device_lock = self._lock # This ensures that the adapter is using the correct lock
324323
adapter.start_server()
325324

326325
self._running[adapter.protocol].set()
@@ -331,29 +330,27 @@ def _adapter_loop(self, adapter, dt):
331330

332331
adapter.stop_server()
333332

334-
def disconnect(self, *args):
333+
def disconnect(self, *args: str) -> None:
335334
"""
336335
Stops all adapters for the specified protocols. The method waits for each adapter thread
337336
to join, so it might hang if the thread is not terminating correctly.
338337
339338
:param args: List of protocols for which to stop adapters or empty for all.
340339
"""
341-
for adapter in self._get_adapters(args):
340+
for adapter in self._get_adapters(list(args)):
342341
self._stop_server(adapter)
343342

344-
def _stop_server(self, adapter):
343+
def _stop_server(self, adapter: Adapter) -> None:
345344
if adapter.protocol in self._threads:
346-
self.log.info(
347-
"Disconnecting device interface for protocol '%s'", adapter.protocol
348-
)
345+
self.log.info("Disconnecting device interface for protocol '%s'", adapter.protocol)
349346

350347
self._running[adapter.protocol].clear()
351348
self._threads[adapter.protocol].join()
352349

353350
del self._threads[adapter.protocol]
354351
del self._running[adapter.protocol]
355352

356-
def is_connected(self, *args):
353+
def is_connected(self, *args: str) -> bool | dict[str | None, bool]:
357354
"""
358355
If only one protocol is supplied, a single bool is returned with the connection status.
359356
Otherwise, this method returns a dictionary of adapter connection statuses for the supplied
@@ -363,15 +360,18 @@ def is_connected(self, *args):
363360
:return: Boolean for single adapter or dict of statuses for multiple.
364361
"""
365362
status_dict = {
366-
adapter.protocol: adapter.is_running for adapter in self._get_adapters(args)
363+
adapter.protocol: adapter.is_running for adapter in self._get_adapters(list(args))
367364
}
368365

369366
if len(args) == 1:
370-
return list(status_dict.values())[0]
367+
status = list(status_dict.values())[0]
368+
if status is None:
369+
return False
370+
return status
371371

372372
return status_dict
373373

374-
def configuration(self, *args):
374+
def configuration(self, *args: str) -> dict[str | None, dict[str, Any]]:
375375
"""
376376
Returns a dictionary that contains the options for the specified adapter. The dictionary
377377
keys are the adapter protocols.
@@ -381,22 +381,20 @@ def configuration(self, *args):
381381
"""
382382
return {
383383
adapter.protocol: adapter._options._asdict()
384-
for adapter in self._get_adapters(args)
384+
for adapter in self._get_adapters(list(args))
385385
}
386386

387-
def documentation(self, *args):
387+
def documentation(self, *args: str) -> str:
388388
"""
389389
Returns the concatenated documentation for the adapters specified by the supplied
390390
protocols or all of them if no arguments are provided.
391391
392392
:param args: List of protocols for which to get documentation or empty for all.
393393
:return: Documentation for all selected adapters.
394394
"""
395-
return "\n\n".join(
396-
adapter.documentation for adapter in self._get_adapters(args)
397-
)
395+
return "\n\n".join(adapter.documentation for adapter in self._get_adapters(list(args)))
398396

399-
def _get_adapters(self, protocols):
397+
def _get_adapters(self, protocols: list[str]) -> list[Adapter]:
400398
"""
401399
Internal method to map protocols back to adapters. If the list of protocols contains an
402400
invalid entry (e.g. a protocol for which there is no adapter), a ``RuntimeError``
@@ -409,9 +407,7 @@ def _get_adapters(self, protocols):
409407

410408
if invalid_protocols:
411409
raise RuntimeError(
412-
"No adapter registered for protocols: {}".format(
413-
", ".join(invalid_protocols)
414-
)
410+
"No adapter registered for protocols: {}".format(", ".join(invalid_protocols))
415411
)
416412

417413
return [self._adapters[proto] for proto in protocols or self.protocols]

0 commit comments

Comments
 (0)