@@ -19,16 +19,26 @@ class CustomParHelper:
19
19
1. Import the CustomParHelper class:
20
20
from utils import CustomParHelper
21
21
22
- 2. Initialize in your extension's __init__ method:
23
- CustomParHelper.Init(self, ownerComp, enable_properties=True, enable_callbacks=True )
22
+ 2. Initialize in your extension's __init__ method as follows :
23
+ CustomParHelper.Init(self, ownerComp)
24
24
25
- Full signature:
26
- CustomParHelper.Init(self, ownerComp, enable_properties= True, enable_callbacks= True, enable_parGroups= True, expose_public= False,
25
+ Full signature and optional parameters :
26
+ CustomParHelper.Init(self, ownerComp, enable_properties: bool = True, enable_callbacks: bool = True, enable_parGroups: bool = True, expose_public: bool = False,
27
27
par_properties: list[str] = ['*'], par_callbacks: list[str] = ['*'],
28
28
except_properties: list[str] = [], except_sequences: list[str] = [], except_callbacks: list[str] = [], except_pages: list[str] = [])
29
29
30
+ Additional options:
31
+ - enable_parGroups: If True, creates properties and methods for parGroups (default: True)
32
+ - expose_public: If True, uses capitalized property and method names (e.g., Par, Eval instead of par, eval)
33
+ - par_properties: List of parameter names to include in property creation, by default all parameters are included
34
+ - par_callbacks: List of parameter names to include in callback handling, by default all parameters are included
35
+ - except_properties: List of parameter names to exclude from property creation
36
+ - except_callbacks: List of parameter names to exclude from callback handling
37
+ - except_pages: List of parameter pages to exclude from property and callback handling
38
+ - except_sequences: List of sequence names to exclude from property and callback handling
39
+
30
40
> NOTE: this class should only be attached to one extension, otherwise it will cause conflicts
31
-
41
+
32
42
3. Access custom parameters as properties (if enable_properties=True (default)):
33
43
- self.par<ParamName>: Access the parameter object
34
44
- self.eval<ParamName>: Get the evaluated value of the parameter
@@ -38,33 +48,24 @@ class CustomParHelper:
38
48
39
49
4. Implement callbacks (if enable_callbacks=True (default)):
40
50
- For regular parameters:
41
- def on <ParamName>(self, _par, _val, _prev):
51
+ def onPar <ParamName>(self, _par, _val, _prev):
42
52
# _par and _prev can be omitted if not needed
43
53
44
54
- For pulse parameters:
45
- def on <PulseParamName>(self, _par):
55
+ def onPar <PulseParamName>(self, _par):
46
56
# _par can be omitted if not needed
47
57
58
+ - For sequence blocks:
59
+ def onSeq<SeqName>N(self, idx):
60
+
48
61
- For sequence parameters:
49
- def on <SeqName>N<ParName>(self, _par, idx, _val, _prev):
62
+ def onSeq <SeqName>N<ParName>(self, _par, idx, _val, _prev):
50
63
# _par and _prev can be omitted if not needed
51
64
52
65
- For parameter groups if enable_parGroups=True (default):
53
66
def onParGroup<GroupName>(self, _parGroup, _val):
54
67
# _parGroup can be omitted if not needed
55
68
56
- > NOTE: to expose public methods, eg. self.OnPar<ParamName> instead of self.onPar<ParamName>, set expose_public=True in the Init function
57
-
58
- Additional options:
59
- - enable_parGroups: If True, creates properties and methods for parGroups (default: True)
60
- - expose_public: If True, uses capitalized property and method names (e.g., Par, Eval instead of par, eval)
61
- - par_properties: List of parameter names to include in property creation, by default all parameters are included
62
- - par_callbacks: List of parameter names to include in callback handling, by default all parameters are included
63
- - except_properties: List of parameter names to exclude from property creation
64
- - except_callbacks: List of parameter names to exclude from callback handling
65
- - except_pages: List of parameter pages to exclude from property and callback handling
66
- - except_sequences: List of sequence names to exclude from property and callback handling
67
-
68
69
> NOTE: This class only works with the docked helper ParExec DATs, which also perform filtering of parameters in a lot of cases.
69
70
'''
70
71
@@ -75,16 +76,16 @@ def onParGroup<GroupName>(self, _parGroup, _val):
75
76
EXCEPT_SEQUENCES : list [str ] = []
76
77
PAR_PROPS : list [str ] = ['*' ]
77
78
PAR_CALLBACKS : list [str ] = ['*' ]
78
- SEQUENCE_PATTERN = r'(\w+?)(\d+)(.+)'
79
- IS_EXPOSE_PUBLIC = False
80
- SELF = None
79
+ SEQUENCE_PATTERN : str = r'(\w+?)(\d+)(.+)'
80
+ IS_EXPOSE_PUBLIC : bool = False
81
+ EXT_SELF = None
81
82
82
83
@staticmethod
83
84
def Init (extension_self , ownerComp : COMP , enable_properties : bool = True , enable_callbacks : bool = True , enable_parGroups : bool = True , expose_public : bool = False ,
84
85
par_properties : list [str ] = ['*' ], par_callbacks : list [str ] = ['*' ],
85
86
except_properties : list [str ] = [], except_sequences : list [str ] = [], except_callbacks : list [str ] = [], except_pages : list [str ] = []) -> None :
86
87
"""Initialize the CustomParHelper."""
87
- CustomParHelper .SELF = extension_self
88
+ CustomParHelper .EXT_SELF = extension_self
88
89
CustomParHelper .IS_EXPOSE_PUBLIC = expose_public
89
90
CustomParHelper .PAR_PROPS = par_properties
90
91
CustomParHelper .PAR_CALLBACKS = par_callbacks
@@ -93,8 +94,8 @@ def Init(extension_self, ownerComp: COMP, enable_properties: bool = True, enable
93
94
CustomParHelper .EXCEPT_CALLBACKS = except_callbacks
94
95
CustomParHelper .EXCEPT_SEQUENCES = except_sequences
95
96
96
- # me : textDAT = me
97
- for _docked in me .docked :
97
+ me_me : textDAT = me # just to have autocomplete on this
98
+ for _docked in me_me .docked :
98
99
if 'extDatExec' in _docked .tags :
99
100
_docked .par .active = enable_properties
100
101
@@ -125,7 +126,7 @@ def CustomParsAsProperties(extension_self, ownerComp: COMP, enable_parGroups: bo
125
126
126
127
127
128
@staticmethod
128
- def _create_propertyEval (extension_self , owner_comp : COMP , Parname : str , enable_parGroups : bool = True ):
129
+ def _create_propertyEval (extension_self , owner_comp : COMP , Parname : str , enable_parGroups : bool = True ) -> None :
129
130
"""Create a property for the evaluated value of a parameter."""
130
131
def getter (instance ):
131
132
return getattr (owner_comp .par , Parname ).eval ()
@@ -134,13 +135,13 @@ def getter_group(instance):
134
135
135
136
property_name = f'{ "Eval" if CustomParHelper .IS_EXPOSE_PUBLIC else "eval" } { Parname } '
136
137
setattr (extension_self .__class__ , property_name , property (getter ))
137
- # this might be overkill
138
+
138
139
if enable_parGroups and CustomParHelper .__isParGroup (getattr (owner_comp .par , Parname )):
139
140
setattr (extension_self .__class__ , f'{ "EvalGroup" if CustomParHelper .IS_EXPOSE_PUBLIC else "evalGroup" } { Parname [:- 1 ]} ' , property (getter_group ))
140
141
141
142
142
143
@staticmethod
143
- def _create_propertyPar (extension_self , owner_comp : COMP , Parname : str , enable_parGroups : bool = True ):
144
+ def _create_propertyPar (extension_self , owner_comp : COMP , Parname : str , enable_parGroups : bool = True ) -> None :
144
145
"""Create a property for the parameter object."""
145
146
def getter (instance ):
146
147
return getattr (owner_comp .par , Parname )
@@ -149,7 +150,7 @@ def getter_group(instance):
149
150
150
151
property_name = f'{ "Par" if CustomParHelper .IS_EXPOSE_PUBLIC else "par" } { Parname } '
151
152
setattr (extension_self .__class__ , property_name , property (getter ))
152
- # this might be overkill
153
+
153
154
if enable_parGroups and CustomParHelper .__isParGroup (getattr (owner_comp .par , Parname )):
154
155
setattr (extension_self .__class__ , f'{ "ParGroup" if CustomParHelper .IS_EXPOSE_PUBLIC else "parGroup" } { Parname [:- 1 ]} ' , property (getter_group ))
155
156
@@ -176,7 +177,7 @@ def OnValueChange(comp: COMP, par: Par, prev: Par) -> None:
176
177
# exceptions are handled in the parExec itself
177
178
# except for sequence parameters
178
179
179
- comp = CustomParHelper .SELF # a bit hacky to be able to call non-exposed methods too
180
+ comp = CustomParHelper .EXT_SELF # a bit hacky to be able to call non-exposed methods too
180
181
181
182
# check if we are a sequence parameter first
182
183
match = re .match (CustomParHelper .SEQUENCE_PATTERN , par .name )
@@ -214,7 +215,7 @@ def OnPulse(comp: COMP, par: Par) -> None:
214
215
# exceptions are handled in the parExec itself
215
216
# except for sequence parameters
216
217
217
- comp = CustomParHelper .SELF # a bit hacky to be able to call non-exposed methods too
218
+ comp = CustomParHelper .EXT_SELF # a bit hacky to be able to call non-exposed methods too
218
219
219
220
# check if we are a sequence parameter first
220
221
match = re .match (CustomParHelper .SEQUENCE_PATTERN , par .name )
@@ -242,19 +243,17 @@ def OnPulse(comp: COMP, par: Par) -> None:
242
243
243
244
@staticmethod
244
245
def OnValuesChanged (changes : list [tuple [Par , Par ]]) -> None :
245
- """Handle value change events for custom parameters.
246
- Using this for ParGroup callbacks only"""
246
+ """Handle value change events for ParGroups."""
247
247
# exceptions are handled in the parExec itself
248
248
# except for sequence parameters
249
249
parGroupsCalled = []
250
250
for change in changes :
251
251
_par = change [0 ]
252
252
# _prev = change[1]
253
253
# _comp = _par.owner
254
- _comp = CustomParHelper .SELF # a bit hacky to be able to call non-exposed methods too
254
+ _comp = CustomParHelper .EXT_SELF # a bit hacky to be able to call non-exposed methods too
255
255
# handle sequence exceptions
256
256
# check if we are a sequence parameter first
257
- # TODO: should we check for sequence exceptions here?
258
257
match = re .match (CustomParHelper .SEQUENCE_PATTERN , _par .name )
259
258
if match :
260
259
sequence_name , sequence_index , parameter_name = match .groups ()
@@ -270,7 +269,7 @@ def OnValuesChanged(changes: list[tuple[Par, Par]]) -> None:
270
269
match = re .match (r'(\w+)(.)' , _par .name )
271
270
if match :
272
271
ParGroup , ParName = match .groups ()
273
- _par = _comp .parGroup [ParGroup ]
272
+ _par = _comp .ownerComp . parGroup [ParGroup ]
274
273
method_name = f'{ "OnParGroup" if CustomParHelper .IS_EXPOSE_PUBLIC else "onParGroup" } { ParGroup } '
275
274
if hasattr (_comp , method_name ):
276
275
method = getattr (_comp , method_name )
@@ -280,10 +279,37 @@ def OnValuesChanged(changes: list[tuple[Par, Par]]) -> None:
280
279
elif arg_count == 3 :
281
280
method (_par , _par .eval ())
282
281
283
-
282
+ @staticmethod
283
+ def OnSeqValuesChanged (changes : list [tuple [Par , Par ]]) -> None :
284
+ """Handle value change events for Sequence blocks."""
285
+ seqsCalled = []
286
+ for change in changes :
287
+ _par = change [0 ]
288
+ # _prev = change[1]
289
+ # _comp = _par.owner
290
+ _comp = CustomParHelper .EXT_SELF # a bit hacky to be able to call non-exposed methods too
291
+ # handle sequence exceptions
292
+ # check if we are a sequence parameter first
293
+ match = re .match (CustomParHelper .SEQUENCE_PATTERN , _par .name )
294
+ if match :
295
+ sequence_name , sequence_index , parameter_name = match .groups ()
296
+ sequence_index = int (sequence_index )
297
+ if sequence_name in CustomParHelper .EXCEPT_SEQUENCES :
298
+ return
299
+ if f'{ sequence_name } { sequence_index } ' not in seqsCalled :
300
+ seqsCalled .append (f'{ sequence_name } { sequence_index } ' )
301
+ else :
302
+ continue
303
+ method_name = f'{ "OnSeq" if CustomParHelper .IS_EXPOSE_PUBLIC else "onSeq" } { sequence_name } N'
304
+ if hasattr (_comp , method_name ):
305
+ method = getattr (_comp , method_name )
306
+ arg_count = method .__code__ .co_argcount
307
+ if arg_count == 2 :
308
+ method (sequence_index )
309
+
284
310
@staticmethod
285
311
def __isParGroup (par : Par ) -> bool :
286
- """Check if a parameter is a ParGroup."""
312
+ """Check if a parameter is a ParGroup. Is there no better way? """
287
313
par_name = par .name [:- 1 ]
288
314
try :
289
315
pg = par .owner .parGroup [par_name ]
0 commit comments