66
77from __future__ import annotations
88
9+ import inspect
910from typing import Optional
1011
1112from pylabrobot .liquid_handling .backends .hamilton .protocol import HamiltonProtocol
@@ -69,6 +70,38 @@ def __init__(self, dest: Address):
6970 self .dest_address = dest # Alias for compatibility
7071 self .sequence_number = 0
7172 self .source_address : Optional [Address ] = None
73+ self ._log_params : dict = {} # Initialize empty - will be populated by _assign_params() if called
74+
75+ def _assign_params (self , exclude : set = None ):
76+ """Auto-assign __init__ parameters to self attributes.
77+
78+ This method inspects the __init__ signature and automatically assigns
79+ all parameters (except those in exclude) to self attributes. It also
80+ builds and stores a params dict for logging purposes.
81+
82+ Args:
83+ exclude: Set of parameter names to exclude from assignment.
84+ Defaults to {'self', 'dest'}.
85+
86+ Note:
87+ This method must be called from within __init__ after super().__init__()
88+ to access the calling frame's local variables.
89+ """
90+ exclude = exclude or {'self' , 'dest' }
91+ sig = inspect .signature (self .__init__ )
92+ frame = inspect .currentframe ().f_back
93+
94+ # Build params dict while assigning
95+ params = {}
96+ for param_name in sig .parameters :
97+ if param_name not in exclude :
98+ if param_name in frame .f_locals :
99+ value = frame .f_locals [param_name ]
100+ setattr (self , param_name , value )
101+ params [param_name ] = value
102+
103+ # Store for logging
104+ self ._log_params = params
72105
73106 def build_parameters (self ) -> HoiParams :
74107 """Build HOI parameters for this command.
@@ -81,6 +114,21 @@ def build_parameters(self) -> HoiParams:
81114 """
82115 return HoiParams ()
83116
117+ def get_log_params (self ) -> dict :
118+ """Get parameters to log for this command.
119+
120+ Returns the params dict built by _assign_params() during __init__.
121+ This eliminates duplicate signature inspection and provides efficient
122+ access to logged parameters.
123+
124+ Subclasses can override to customize formatting (e.g., unit conversions,
125+ array truncation).
126+
127+ Returns:
128+ Dictionary of parameter names to values (empty dict if _assign_params() not called)
129+ """
130+ return self ._log_params
131+
84132 def build (self , src : Optional [Address ] = None , seq : Optional [int ] = None , response_required : bool = True ) -> bytes :
85133 """Build complete Hamilton message using CommandMessage.
86134
0 commit comments