33from collections .abc import Iterator
44from copy import copy
55from dataclasses import dataclass
6+ from typing import get_type_hints
67
78from .attributes import Attribute
89from .cs_methods import Command , Put , Scan
@@ -19,7 +20,12 @@ class SingleMapping:
1920
2021
2122class BaseController :
23+ #! Attributes passed from the device at runtime.
24+ attributes : dict [str , Attribute ]
25+
2226 def __init__ (self , path : list [str ] | None = None ) -> None :
27+ if not hasattr (self , "attributes" ):
28+ self .attributes = {}
2329 self ._path : list [str ] = path or []
2430 self .__sub_controller_tree : dict [str , BaseController ] = {}
2531
@@ -37,12 +43,26 @@ def set_path(self, path: list[str]):
3743 self ._path = path
3844
3945 def _bind_attrs (self ) -> None :
40- for attr_name in dir (self ):
41- attr = getattr (self , attr_name )
46+ # Using a dictionary instead of a set to maintain order.
47+ class_dir = {key : None for key in dir (type (self ))}
48+ class_type_hints = get_type_hints (type (self ))
49+
50+ for attr_name in {** class_dir , ** class_type_hints }:
51+ attr = getattr (self , attr_name , None )
4252 if isinstance (attr , Attribute ):
53+ if (
54+ attr_name in self .attributes
55+ and self .attributes [attr_name ] is not attr
56+ ):
57+ raise ValueError (
58+ f"`{ type (self ).__name__ } ` has conflicting attribute "
59+ f"`{ attr_name } ` already present in the attributes dict."
60+ )
4361 new_attribute = copy (attr )
4462 setattr (self , attr_name , new_attribute )
4563
64+ self .attributes [attr_name ] = new_attribute
65+
4666 def register_sub_controller (self , name : str , sub_controller : SubController ):
4767 if name in self .__sub_controller_tree .keys ():
4868 raise ValueError (
@@ -69,7 +89,6 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
6989 scan_methods : dict [str , Scan ] = {}
7090 put_methods : dict [str , Put ] = {}
7191 command_methods : dict [str , Command ] = {}
72- attributes : dict [str , Attribute ] = {}
7392 for attr_name in dir (controller ):
7493 attr = getattr (controller , attr_name )
7594 match attr :
@@ -79,11 +98,14 @@ def _get_single_mapping(controller: BaseController) -> SingleMapping:
7998 scan_methods [attr_name ] = scan_method
8099 case WrappedMethod (fastcs_method = Command (enabled = True ) as command_method ):
81100 command_methods [attr_name ] = command_method
82- case Attribute (enabled = True ):
83- attributes [attr_name ] = attr
84101
102+ enabled_attributes = {
103+ name : attribute
104+ for name , attribute in controller .attributes .items ()
105+ if attribute .enabled
106+ }
85107 return SingleMapping (
86- controller , scan_methods , put_methods , command_methods , attributes
108+ controller , scan_methods , put_methods , command_methods , enabled_attributes
87109 )
88110
89111
0 commit comments