0
# Core Framework
1
2
The foundational classes and interfaces that form the backbone of ophyd's device abstraction system. These components enable device composition, signal management, status tracking, and provide the base functionality that all other ophyd components build upon.
3
4
## Capabilities
5
6
### Device Class
7
8
The base class for all hardware devices in ophyd, providing a standardized interface for reading, configuring, and controlling hardware through a component-based architecture.
9
10
```python { .api }
11
class Device:
12
"""
13
Base class for all devices in ophyd.
14
15
Parameters:
16
- prefix (str): PV prefix for EPICS devices
17
- name (str): Device name for identification
18
- kind (Kind): Component kind classification
19
- read_attrs (list): Attributes to include in read()
20
- configuration_attrs (list): Attributes for configuration
21
- parent (Device): Parent device if nested
22
- child_name_separator (str): Separator for child component names (default: '_')
23
- connection_timeout (float): Timeout for signal connections
24
"""
25
def __init__(self, prefix='', *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, child_name_separator='_', connection_timeout=None, **kwargs): ...
26
27
def read(self):
28
"""
29
Read current values from all readable components.
30
31
Returns:
32
dict: Mapping of component names to reading dictionaries
33
with 'value' and 'timestamp' keys
34
"""
35
36
def describe(self):
37
"""
38
Describe the data format for all readable components.
39
40
Returns:
41
dict: Mapping of component names to description dictionaries
42
with 'dtype', 'shape', and other metadata
43
"""
44
45
def configure(self, d):
46
"""
47
Configure device settings.
48
49
Parameters:
50
- d (dict): Configuration parameters mapping
51
52
Returns:
53
tuple: (old_config, new_config) dictionaries
54
"""
55
56
def read_configuration(self):
57
"""
58
Read current configuration values.
59
60
Returns:
61
dict: Current configuration state
62
"""
63
64
def describe_configuration(self):
65
"""
66
Describe configuration data format.
67
68
Returns:
69
dict: Configuration data descriptions
70
"""
71
72
def trigger(self):
73
"""
74
Trigger device acquisition or measurement.
75
76
Returns:
77
StatusBase: Status object tracking trigger completion
78
"""
79
80
def stage(self):
81
"""
82
Stage device for data acquisition (setup phase).
83
84
Returns:
85
list: List of staged components
86
"""
87
88
def unstage(self):
89
"""
90
Unstage device after data acquisition (cleanup phase).
91
92
Returns:
93
list: List of unstaged components
94
"""
95
96
def wait_for_connection(self, timeout=2.0):
97
"""
98
Wait for all device components to connect.
99
100
Parameters:
101
- timeout (float): Maximum wait time in seconds
102
"""
103
104
def connected(self):
105
"""
106
Check if device is fully connected.
107
108
Returns:
109
bool: True if all components are connected
110
"""
111
112
@property
113
def hints(self):
114
"""
115
Hints for plotting and analysis.
116
117
Returns:
118
dict: Plot hints with 'fields' key
119
"""
120
```
121
122
### Signal Classes
123
124
Fundamental classes for representing individual hardware channels and computed values, forming the building blocks of device components.
125
126
```python { .api }
127
class Signal:
128
"""
129
Base class for readable and writable values.
130
131
Parameters:
132
- name (str): Signal name for identification
133
- value: Initial value (default: 0.0)
134
- dtype: Data type specification
135
- shape: Data shape specification
136
- timestamp (float): Initial timestamp
137
- parent (Device): Parent device
138
- labels (list): Additional signal labels
139
- kind (Kind): Signal classification (default: Kind.hinted)
140
- tolerance (float): Absolute tolerance for set operations
141
- rtolerance (float): Relative tolerance for set operations
142
- metadata (dict): Additional metadata
143
- cl: Control layer
144
- attr_name (str): Parent Device attribute name
145
"""
146
def __init__(self, *, name, value=0.0, dtype=None, shape=None, timestamp=None, parent=None, labels=None, kind=Kind.hinted, tolerance=None, rtolerance=None, metadata=None, cl=None, attr_name="", **kwargs): ...
147
148
def get(self, **kwargs):
149
"""
150
Get current signal value.
151
152
Returns:
153
Current value of the signal
154
"""
155
156
def put(self, value, **kwargs):
157
"""
158
Put value to signal (synchronous).
159
160
Parameters:
161
- value: Value to write
162
"""
163
164
def set(self, value, **kwargs):
165
"""
166
Set signal to value (asynchronous).
167
168
Parameters:
169
- value: Target value
170
171
Returns:
172
StatusBase: Status object tracking set completion
173
"""
174
175
def read(self):
176
"""
177
Read signal value and timestamp.
178
179
Returns:
180
dict: Reading dictionary with 'value' and 'timestamp'
181
"""
182
183
def describe(self):
184
"""
185
Describe signal data format.
186
187
Returns:
188
dict: Description with 'dtype', 'shape', 'source', etc.
189
"""
190
191
def subscribe(self, callback, event_type=None, run=True):
192
"""
193
Subscribe to signal changes.
194
195
Parameters:
196
- callback (callable): Function to call on changes
197
- event_type (str): Type of event to monitor
198
- run (bool): Whether to run callback immediately
199
200
Returns:
201
int: Subscription ID for unsubscribing
202
"""
203
204
def clear_sub(self, cb, event_type=None):
205
"""
206
Clear subscription.
207
208
Parameters:
209
- cb: Subscription ID or callback function
210
- event_type (str): Event type to clear
211
"""
212
213
class SignalRO(Signal):
214
"""
215
Read-only signal that cannot be written to.
216
"""
217
def __init__(self, *, name, value=0, **kwargs): ...
218
219
class DerivedSignal(Signal):
220
"""
221
Signal derived from other signals through a function.
222
223
Parameters:
224
- derived_from (dict): Mapping of signals to derive from
225
- derived_func (callable): Function to compute derived value
226
"""
227
def __init__(self, *, derived_from, derived_func=None, **kwargs): ...
228
```
229
230
### Component System
231
232
The component system enables composition of devices from reusable, declarative building blocks.
233
234
```python { .api }
235
class Component:
236
"""
237
Device component descriptor for building composite devices.
238
239
Parameters:
240
- cls: Component class to instantiate
241
- suffix (str): PV suffix to append to device prefix
242
- lazy (bool): Whether to delay instantiation
243
- trigger_value: Value to set during trigger()
244
- add_prefix (tuple): Additional prefix components
245
- doc (str): Documentation string
246
- kind (Kind): Component classification
247
"""
248
def __init__(self, cls, suffix='', *, lazy=False, trigger_value=None, add_prefix=None, doc=None, kind='normal', **kwargs): ...
249
250
class FormattedComponent(Component):
251
"""
252
Component with string formatting support for dynamic PV names.
253
254
Parameters:
255
- cls: Component class
256
- suffix (str): PV suffix with format strings
257
- **kwargs: Format arguments and component parameters
258
"""
259
def __init__(self, cls, suffix, **kwargs): ...
260
261
class DynamicDeviceComponent(Component):
262
"""
263
Component that creates devices dynamically based on available PVs.
264
"""
265
def __init__(self, defn, **kwargs): ...
266
267
# Component utility functions
268
def kind_context(kind):
269
"""
270
Context manager for setting default component kind.
271
272
Parameters:
273
- kind (Kind): Default kind for components created in context
274
"""
275
276
ALL_COMPONENTS = object() # Sentinel for selecting all components
277
```
278
279
### Status Management
280
281
Status objects track the progress and completion of asynchronous operations.
282
283
```python { .api }
284
class StatusBase:
285
"""
286
Base class for tracking operation status.
287
288
Parameters:
289
- timeout (float): Maximum time to wait for completion (None = wait forever)
290
- settle_time (float): Time to wait after completion before callbacks (default: 0)
291
- done (deprecated): Initial completion state
292
- success (deprecated): Initial success state
293
"""
294
def __init__(self, *, timeout=None, settle_time=0, done=None, success=None): ...
295
296
@property
297
def done(self):
298
"""
299
Whether operation is complete.
300
301
Returns:
302
bool: True if operation finished (success or failure)
303
"""
304
305
@property
306
def success(self):
307
"""
308
Whether operation completed successfully.
309
310
Returns:
311
bool: True if completed without errors
312
"""
313
314
def wait(self, timeout=None):
315
"""
316
Wait for operation completion.
317
318
Parameters:
319
- timeout (float): Maximum wait time
320
321
Raises:
322
StatusTimeoutError: If timeout is exceeded
323
"""
324
325
def add_callback(self, callback):
326
"""
327
Add callback for status completion.
328
329
Parameters:
330
- callback (callable): Function to call when complete
331
"""
332
333
class Status(StatusBase):
334
"""
335
Basic status implementation with manual completion control.
336
"""
337
def __init__(self, obj=None, **kwargs): ...
338
339
def set_finished(self):
340
"""Mark status as successfully completed."""
341
342
def set_exception(self, exc):
343
"""Mark status as failed with exception."""
344
345
class DeviceStatus(StatusBase):
346
"""
347
Status for device operations, can combine multiple sub-statuses.
348
"""
349
def __init__(self, device, **kwargs): ...
350
351
def add_status(self, status):
352
"""Add sub-status to track."""
353
354
class MoveStatus(StatusBase):
355
"""
356
Status specifically for positioner movements.
357
"""
358
def __init__(self, positioner, target, **kwargs): ...
359
360
def wait(status, timeout=None, poll_period=0.05):
361
"""
362
Wait for one or more status objects to complete.
363
364
Parameters:
365
- status (StatusBase or list): Status object(s) to wait for
366
- timeout (float): Maximum total wait time
367
- poll_period (float): Polling interval
368
369
Raises:
370
StatusTimeoutError: If any status times out
371
WaitTimeoutError: If overall timeout is exceeded
372
"""
373
```
374
375
### Object Registry and Utilities
376
377
Utilities for managing ophyd objects and their relationships.
378
379
```python { .api }
380
class OphydObject:
381
"""
382
Base class for all ophyd objects providing common functionality.
383
384
Parameters:
385
- name (str): Object name
386
- parent (OphydObject): Parent object
387
"""
388
def __init__(self, *, name=None, parent=None, **kwargs): ...
389
390
@property
391
def name(self):
392
"""Full dotted name including parent hierarchy."""
393
394
@property
395
def dotted_name(self):
396
"""Dotted name for hierarchical identification."""
397
398
def destroy(self):
399
"""Clean up object resources."""
400
401
# Registry functions
402
def register_instances_keyed_on_name(cls, registry=None):
403
"""
404
Register class instances in a dictionary keyed by name.
405
406
Parameters:
407
- cls: Class to register instances for
408
- registry (dict): Dictionary to store instances
409
"""
410
411
def register_instances_in_weakset(cls, registry=None):
412
"""
413
Register class instances in a weak set.
414
415
Parameters:
416
- cls: Class to register instances for
417
- registry (WeakSet): Set to store instances
418
"""
419
420
def select_version(obj, version):
421
"""
422
Select specific version of an object.
423
424
Parameters:
425
- obj: Object with version support
426
- version: Version identifier
427
"""
428
```
429
430
### Utility Functions
431
432
Helper functions for namespace management, string processing, and instance handling.
433
434
```python { .api }
435
class OrderedDefaultDict(OrderedDict):
436
"""
437
Combination of defaultdict and OrderedDict.
438
439
Provides ordered dictionary functionality with automatic
440
default value creation for missing keys.
441
442
Parameters:
443
- default_factory (callable): Factory function for default values
444
"""
445
def __init__(self, default_factory=None, *a, **kw): ...
446
def __missing__(self, key): ...
447
def copy(self): ...
448
449
def instances_from_namespace(classes, *, ns=None):
450
"""
451
Get instances of specified classes from user namespace.
452
453
Searches the IPython user namespace (or provided namespace)
454
for instances of the specified class types.
455
456
Parameters:
457
- classes: Type or sequence of types to match with isinstance()
458
- ns (dict): Namespace to search (defaults to IPython user_ns)
459
460
Returns:
461
list: Instances matching the specified classes
462
"""
463
464
def ducks_from_namespace(attrs, *, ns=None):
465
"""
466
Get instances with specified attributes (duck typing).
467
468
Finds objects that have all specified attributes, implementing
469
"duck typing" - if it looks like a duck and quacks like a duck...
470
471
Parameters:
472
- attrs: Attribute name(s) to check for
473
- ns (dict): Namespace to search (defaults to IPython user_ns)
474
475
Returns:
476
list: Objects that have all specified attributes
477
"""
478
479
def underscores_to_camel_case(underscores):
480
"""
481
Convert underscore-separated strings to camelCase.
482
483
Parameters:
484
- underscores (str): String with underscores (e.g., "abc_def_ghi")
485
486
Returns:
487
str: CamelCase version (e.g., "abcDefGhi")
488
"""
489
490
def getattrs(obj, gen):
491
"""
492
Get multiple attributes from an object as generator.
493
494
Parameters:
495
- obj: Object to get attributes from
496
- gen: Iterable of attribute names
497
498
Yields:
499
tuple: (attribute_name, attribute_value) pairs
500
"""
501
502
def doc_annotation_forwarder(base_klass):
503
"""
504
Decorator that forwards documentation and annotations from base class.
505
506
Copies __doc__ and __annotations__ from base class method to wrapper.
507
Useful for maintaining documentation in method override patterns.
508
509
Parameters:
510
- base_klass: Base class to forward documentation from
511
512
Returns:
513
callable: Decorator function
514
"""
515
516
def adapt_old_callback_signature(callback):
517
"""
518
Adapt old callback signatures for backward compatibility.
519
520
Wraps callbacks with signature callback() to match expected
521
callback(status) signature for status objects.
522
523
Parameters:
524
- callback: Callable with signature callback() or callback(status)
525
526
Returns:
527
callable: Callback with signature callback(status)
528
"""
529
```
530
531
## Usage Examples
532
533
### Creating a Custom Device
534
535
```python
536
from ophyd import Device, Component, EpicsSignal
537
538
class MyTemperatureController(Device):
539
"""Temperature controller with setpoint and readback."""
540
setpoint = Component(EpicsSignal, 'SP', kind='config')
541
temperature = Component(EpicsSignal, 'RBV', kind='hinted')
542
status = Component(EpicsSignal, 'STAT', kind='omitted')
543
544
def heat_to(self, temperature):
545
"""Heat to target temperature."""
546
return self.setpoint.set(temperature)
547
548
# Create and use device
549
temp_controller = MyTemperatureController('TEMP:CTRL:', name='temp_ctrl')
550
temp_controller.wait_for_connection()
551
552
# Read all values
553
reading = temp_controller.read()
554
print(f"Current temperature: {reading['temp_ctrl_temperature']['value']}")
555
556
# Set temperature and wait
557
status = temp_controller.heat_to(25.0)
558
wait(status)
559
```
560
561
### Working with Signals
562
563
```python
564
from ophyd import Signal, DerivedSignal
565
566
# Create base signals
567
voltage = Signal(name='voltage', value=5.0)
568
current = Signal(name='current', value=2.0)
569
570
# Create derived signal for power
571
def calculate_power(voltage=None, current=None, **kwargs):
572
return voltage * current
573
574
power = DerivedSignal(
575
derived_from={'voltage': voltage, 'current': current},
576
derived_func=calculate_power,
577
name='power'
578
)
579
580
# Subscribe to changes
581
def power_changed(value=None, **kwargs):
582
print(f"Power changed to: {value} W")
583
584
power.subscribe(power_changed)
585
586
# Update base signals
587
voltage.put(6.0) # Triggers power calculation and callback
588
```