Skip to content

Commit 86e155c

Browse files
committed
Composition > Inheritance
1 parent b051a17 commit 86e155c

File tree

24 files changed

+186
-163
lines changed

24 files changed

+186
-163
lines changed

src/fastcs/backend.py

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import asyncio
2-
from abc import ABC, abstractmethod
32
from collections import defaultdict
43
from collections.abc import Callable
54
from concurrent.futures import Future
@@ -13,12 +12,14 @@
1312
from .mapping import Mapping, SingleMapping
1413

1514

16-
class Backend(ABC):
15+
class Backend:
1716
def __init__(
18-
self, controller: Controller, loop: asyncio.AbstractEventLoop | None = None
17+
self,
18+
controller: Controller,
19+
loop: asyncio.AbstractEventLoop | None = None,
1920
):
20-
self._dispatcher = AsyncioDispatcher(loop)
21-
self._loop = self._dispatcher.loop
21+
self.dispatcher = AsyncioDispatcher(loop)
22+
self._loop = self.dispatcher.loop
2223
self._controller = controller
2324

2425
self._initial_tasks = [controller.connect]
@@ -28,55 +29,35 @@ def __init__(
2829
self._controller.initialise(), self._loop
2930
).result()
3031

31-
self._mapping = Mapping(self._controller)
32+
self.mapping = Mapping(self._controller)
3233
self._link_process_tasks()
3334

34-
self._context = {
35-
"dispatcher": self._dispatcher,
35+
self.context = {
36+
"dispatcher": self.dispatcher,
3637
"controller": self._controller,
37-
"mapping": self._mapping,
38+
"mapping": self.mapping,
3839
}
3940

4041
def _link_process_tasks(self):
41-
for single_mapping in self._mapping.get_controller_mappings():
42+
for single_mapping in self.mapping.get_controller_mappings():
4243
_link_single_controller_put_tasks(single_mapping)
4344
_link_attribute_sender_class(single_mapping)
4445

4546
def run(self):
4647
self._run_initial_tasks()
4748
self._start_scan_tasks()
4849

49-
self._run()
50-
51-
def create_docs(self) -> None:
52-
self._create_docs()
53-
54-
def create_gui(self) -> None:
55-
self._create_gui()
56-
5750
def _run_initial_tasks(self):
5851
for task in self._initial_tasks:
5952
future = asyncio.run_coroutine_threadsafe(task(), self._loop)
6053
future.result()
6154

6255
def _start_scan_tasks(self):
63-
scan_tasks = _get_scan_tasks(self._mapping)
56+
scan_tasks = _get_scan_tasks(self.mapping)
6457

6558
for task in scan_tasks:
6659
asyncio.run_coroutine_threadsafe(task(), self._loop)
6760

68-
@abstractmethod
69-
def _run(self) -> None:
70-
pass
71-
72-
@abstractmethod
73-
def _create_docs(self) -> None:
74-
pass
75-
76-
@abstractmethod
77-
def _create_gui(self) -> None:
78-
pass
79-
8061

8162
def _link_single_controller_put_tasks(single_mapping: SingleMapping) -> None:
8263
for name, method in single_mapping.put_methods.items():

src/fastcs/backends/asyncio_backend.py

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/fastcs/backends/epics/backend.py

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/fastcs/backends/tango/backend.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/fastcs/main.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,51 @@
1+
from dataclasses import dataclass
2+
from typing import Any
3+
14
from .backend import Backend
2-
from .backends.epics.options import EpicsOptions
3-
from .backends.tango.options import TangoOptions
45
from .controller import Controller
6+
from .transport.adapter import TransportAdapter
7+
from .transport.epics.options import EpicsOptions
8+
from .transport.tango.options import TangoOptions
59

610

7-
class FastCS:
8-
def __init__(self, controller: Controller, options: EpicsOptions | TangoOptions):
9-
self.backend: Backend
10-
match options:
11-
case EpicsOptions():
12-
from .backends.epics.backend import EpicsBackend
11+
@dataclass
12+
class FastCSOptions:
13+
transport: EpicsOptions | TangoOptions
14+
controller: Any = None
15+
1316

14-
self.backend = EpicsBackend(controller, options)
17+
class FastCS:
18+
def __init__(
19+
self,
20+
controller: Controller,
21+
options: FastCSOptions,
22+
):
23+
self.backend = Backend(controller)
24+
self.transport: TransportAdapter
25+
match options.transport:
1526
case TangoOptions():
16-
from .backends.tango.backend import TangoBackend
27+
from .transport.tango.adapter import TangoTransport
28+
29+
self.transport = TangoTransport(
30+
self.backend.mapping,
31+
options.transport,
32+
)
33+
case EpicsOptions():
34+
from .transport.epics.adapter import EpicsTransport
1735

18-
self.backend = TangoBackend(controller, options)
36+
self.transport = EpicsTransport(
37+
self.backend.mapping,
38+
self.backend.context,
39+
self.backend.dispatcher,
40+
options.transport,
41+
)
1942

2043
def create_docs(self) -> None:
21-
self.backend.create_docs()
44+
self.transport.create_docs()
2245

2346
def create_gui(self) -> None:
24-
self.backend.create_gui()
47+
self.transport.create_gui()
2548

2649
def run(self) -> None:
2750
self.backend.run()
51+
self.transport.run()

src/fastcs/transport/adapter.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from abc import ABC, abstractmethod
2+
from dataclasses import dataclass
3+
4+
5+
@dataclass
6+
class TransportOptions:
7+
pass
8+
9+
10+
class TransportAdapter(ABC):
11+
@abstractmethod
12+
def run(self) -> None:
13+
pass
14+
15+
@abstractmethod
16+
def create_docs(self) -> None:
17+
pass
18+
19+
@abstractmethod
20+
def create_gui(self) -> None:
21+
pass
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
from typing import cast
2+
3+
from softioc.asyncio_dispatcher import AsyncioDispatcher as Dispatcher
4+
5+
from fastcs.mapping import Mapping
6+
from fastcs.transport.adapter import TransportAdapter
7+
from fastcs.util import AsyncioDispatcher
8+
9+
from .docs import EpicsDocs
10+
from .gui import EpicsGUI
11+
from .ioc import EpicsIOC
12+
from .options import EpicsOptions
13+
14+
15+
class EpicsTransport(TransportAdapter):
16+
def __init__(
17+
self,
18+
mapping: Mapping,
19+
context: dict,
20+
dispatcher: AsyncioDispatcher,
21+
options: EpicsOptions | None = None,
22+
) -> None:
23+
if options is None:
24+
self.options = EpicsOptions()
25+
else:
26+
self.options = options
27+
28+
self._mapping = mapping
29+
self._context = context
30+
self._dispatcher = dispatcher
31+
self._pv_prefix = self.options.ioc.pv_prefix
32+
self._ioc = EpicsIOC(self.options.ioc.pv_prefix, self._mapping)
33+
34+
def create_docs(self) -> None:
35+
EpicsDocs(self._mapping).create_docs(self.options.docs)
36+
37+
def create_gui(self) -> None:
38+
EpicsGUI(self._mapping, self._pv_prefix).create_gui(self.options.gui)
39+
40+
def run(self):
41+
self._ioc.run(
42+
cast(Dispatcher, self._dispatcher), self._context, self.options.ioc
43+
)

0 commit comments

Comments
 (0)