11from __future__ import annotations
22
33from collections import Counter
4- from collections .abc import Sequence
4+ from collections .abc import Iterator , Mapping , MutableMapping , Sequence
55from copy import deepcopy
66from typing import get_type_hints
77
@@ -22,7 +22,7 @@ class BaseController(Tracer):
2222
2323 def __init__ (
2424 self ,
25- path : list [str ] | None = None ,
25+ path : list [str | int ] | None = None ,
2626 description : str | None = None ,
2727 ios : Sequence [AttributeIO [T , AttributeIORefT ]] | None = None ,
2828 ) -> None :
@@ -35,8 +35,8 @@ def __init__(
3535
3636 if not hasattr (self , "attributes" ):
3737 self .attributes = {}
38- self ._path : list [str ] = path or []
39- self .__sub_controller_tree : dict [str , Controller ] = {}
38+ self ._path : list [str | int ] = path or []
39+ self .__sub_controller_tree : dict [str | int , BaseController ] = {}
4040
4141 self ._bind_attrs ()
4242
@@ -71,11 +71,11 @@ def connect_attribute_ios(self) -> None:
7171 controller .connect_attribute_ios ()
7272
7373 @property
74- def path (self ) -> list [str ]:
74+ def path (self ) -> list [str | int ]:
7575 """Path prefix of attributes, recursively including parent Controllers."""
7676 return self ._path
7777
78- def set_path (self , path : list [str ]):
78+ def set_path (self , path : list [str | int ]):
7979 if self ._path :
8080 raise ValueError (f"sub controller is already registered under { self .path } " )
8181
@@ -142,7 +142,7 @@ def add_attribute(self, name, attribute: Attribute):
142142 self .attributes [name ] = attribute
143143 super ().__setattr__ (name , attribute )
144144
145- def add_sub_controller (self , name : str , sub_controller : Controller ):
145+ def add_sub_controller (self , name : str | int , sub_controller : BaseController ):
146146 if name in self .__sub_controller_tree .keys ():
147147 raise ValueError (
148148 f"Cannot add sub controller { name } . "
@@ -156,18 +156,18 @@ def add_sub_controller(self, name: str, sub_controller: Controller):
156156
157157 sub_controller .set_path (self .path + [name ])
158158 self .__sub_controller_tree [name ] = sub_controller
159- super ().__setattr__ (name , sub_controller )
159+ super ().__setattr__ (str ( name ) , sub_controller )
160160
161161 if isinstance (sub_controller .root_attribute , Attribute ):
162- self .attributes [name ] = sub_controller .root_attribute
162+ self .attributes [str ( name ) ] = sub_controller .root_attribute
163163
164164 @property
165- def sub_controllers (self ) -> dict [str , Controller ]:
165+ def sub_controllers (self ) -> dict [str | int , BaseController ]:
166166 return self .__sub_controller_tree
167167
168168 def __repr__ (self ):
169169 name = self .__class__ .__name__
170- path = "." .join (self .path ) or None
170+ path = "." .join ([ str ( p ) for p in self .path ] ) or None
171171 sub_controllers = list (self .sub_controllers .keys ()) or None
172172
173173 return f"{ name } (path={ path } , sub_controllers={ sub_controllers } )"
@@ -204,3 +204,48 @@ async def connect(self) -> None:
204204
205205 async def disconnect (self ) -> None :
206206 pass
207+
208+
209+ class SubControllerVector (MutableMapping [int , Controller ], Controller ):
210+ """A collection of SubControllers, with an arbitrary integer index.
211+ An instance of this class can be registered with a parent ``Controller`` to include
212+ it's children as part of a larger controller. Each child of the vector will keep
213+ a string name of the vector.
214+ """
215+
216+ def __init__ (
217+ self , children : Mapping [int , Controller ], description : str | None = None
218+ ) -> None :
219+ self ._children : dict [int , Controller ] = {}
220+ self .update (children )
221+ super ().__init__ (description = description )
222+ for index , child in children .items ():
223+ self .add_sub_controller (index , child )
224+
225+ def __getitem__ (self , key : int ) -> Controller :
226+ return self ._children [key ]
227+
228+ def __setitem__ (self , key : int , value : Controller ) -> None :
229+ if not isinstance (key , int ):
230+ msg = f"Expected int, got { key } "
231+ raise TypeError (msg )
232+ if not isinstance (value , Controller ):
233+ msg = f"Expected Controller, got { value } "
234+ raise TypeError (msg )
235+ self ._children [key ] = value
236+
237+ def __delitem__ (self , key : int ) -> None :
238+ del self ._children [key ]
239+
240+ def __iter__ (self ) -> Iterator [int ]:
241+ yield from self ._children
242+
243+ def __len__ (self ) -> int :
244+ return len (self ._children )
245+
246+ def children (self ) -> Iterator [tuple [str , Controller ]]:
247+ for key , child in self ._children .items ():
248+ yield str (key ), child
249+
250+ def __hash__ (self ):
251+ return hash (id (self ))
0 commit comments