11import inspect
22from collections .abc import Callable
3- from typing import Annotated , Final , TypeVar , cast
3+ from typing import TypeVar
44
5- from bluesky .run_engine import call_in_bluesky_event_loop
65from daq_config_server import ConfigClient
7- from ophyd import Device as OphydV1Device
8- from ophyd .sim import make_fake_device
96from ophyd_async .core import (
10- DEFAULT_TIMEOUT ,
117 PathProvider ,
128)
13- from ophyd_async .core import Device as OphydV2Device
14- from ophyd_async .core import wait_for_connection as v2_device_wait_for_connection
159
1610from dodal .log import LOGGER
1711from dodal .utils import (
1812 AnyDevice ,
19- BeamlinePrefix ,
20- DeviceInitializationController ,
21- SkipType ,
22- skip_device ,
2313)
2414
25- DEFAULT_CONNECTION_TIMEOUT : Final [float ] = 5.0
26-
27- ACTIVE_DEVICES : dict [str , AnyDevice ] = {}
2815BL = ""
2916
3017
@@ -33,134 +20,15 @@ def set_beamline(beamline: str):
3320 BL = beamline
3421
3522
36- def clear_devices ():
37- global ACTIVE_DEVICES
38- for name in list (ACTIVE_DEVICES ):
39- clear_device (name )
40-
41-
42- def clear_device (name : str ):
43- global ACTIVE_DEVICES
44- device = ACTIVE_DEVICES [name ]
45- if isinstance (device , OphydV1Device ):
46- device .destroy ()
47- del ACTIVE_DEVICES [name ]
48-
49-
50- def list_active_devices () -> list [str ]:
51- global ACTIVE_DEVICES
52- return list (ACTIVE_DEVICES .keys ())
53-
54-
5523def active_device_is_same_type (
5624 active_device : AnyDevice , device : Callable [..., AnyDevice ]
5725) -> bool :
5826 return inspect .isclass (device ) and isinstance (active_device , device )
5927
6028
61- def wait_for_connection (
62- device : AnyDevice ,
63- timeout : float = DEFAULT_CONNECTION_TIMEOUT ,
64- mock : bool = False ,
65- ) -> None :
66- if isinstance (device , OphydV1Device ):
67- device .wait_for_connection (timeout = timeout )
68- elif isinstance (device , OphydV2Device ):
69- call_in_bluesky_event_loop (
70- v2_device_wait_for_connection (
71- coros = device .connect (mock = mock , timeout = timeout )
72- ),
73- )
74- else :
75- raise TypeError (
76- f"Invalid type { device .__class__ .__name__ } in _wait_for_connection"
77- )
78-
79-
8029T = TypeVar ("T" , bound = AnyDevice )
8130
8231
83- @skip_device ()
84- def device_instantiation (
85- device_factory : Callable [..., T ],
86- name : str ,
87- prefix : str ,
88- wait : bool ,
89- fake : bool ,
90- post_create : Callable [[T ], None ] | None = None ,
91- bl_prefix : bool = True ,
92- ** kwargs ,
93- ) -> T :
94- """Method to allow generic creation of singleton devices. Meant to be used to easily
95- define lists of devices in beamline files. Additional keyword arguments are passed
96- directly to the device constructor.
97-
98- Args:
99- device_factory (Callable): The device class.
100- name (str): The name for ophyd.
101- prefix (str): The PV prefix for the most (usually all) components.
102- wait (bool): Whether to run .wait_for_connection().
103- fake (bool): Whether to fake with ophyd.sim.
104- post_create (Callable): (optional) a function to be run on the device after
105- creation.
106- bl_prefix (bool): If true, add the beamline prefix when instantiating.
107- **kwargs: Arguments passed on to every device factory.
108-
109- Returns:
110- The instance of the device.
111- """
112- already_existing_device : AnyDevice | None = ACTIVE_DEVICES .get (name )
113- if fake :
114- device_factory = cast (Callable [..., T ], make_fake_device (device_factory ))
115- if already_existing_device is None :
116- device_instance = device_factory (
117- name = name ,
118- prefix = (
119- f"{ (BeamlinePrefix (BL ).beamline_prefix )} { prefix } "
120- if bl_prefix
121- else prefix
122- ),
123- ** kwargs ,
124- )
125- ACTIVE_DEVICES [name ] = device_instance
126- if wait :
127- wait_for_connection (device_instance , mock = fake )
128-
129- else :
130- if not active_device_is_same_type (already_existing_device , device_factory ):
131- raise TypeError (
132- f"Can't instantiate device of type { device_factory } with the same "
133- f"name as an existing device. Device name '{ name } ' already used for "
134- f"a(n) { type (already_existing_device )} ."
135- )
136- device_instance = cast (T , already_existing_device )
137- if post_create :
138- post_create (device_instance )
139- return device_instance
140-
141-
142- def device_factory (
143- * ,
144- use_factory_name : Annotated [bool , "Use factory name as name of device" ] = True ,
145- timeout : Annotated [float , "Timeout for connecting to the device" ] = DEFAULT_TIMEOUT ,
146- mock : Annotated [bool , "Use Signals with mock backends for device" ] = False ,
147- skip : Annotated [
148- SkipType ,
149- "mark the factory to be (conditionally) skipped when beamline is imported by external program" ,
150- ] = False ,
151- ) -> Callable [[Callable [[], T ]], DeviceInitializationController [T ]]:
152- def decorator (factory : Callable [[], T ]) -> DeviceInitializationController [T ]:
153- return DeviceInitializationController (
154- factory ,
155- use_factory_name ,
156- timeout ,
157- mock ,
158- skip ,
159- )
160-
161- return decorator
162-
163-
16432def set_path_provider (provider : PathProvider ):
16533 global PATH_PROVIDER
16634
0 commit comments