2626class OperatorPrecedence (enum .Enum ):
2727 """The precedence of an operator."""
2828
29+ ADDITION = 1
2930 SUBTRACTION = 1
30- ADDITION = 2
31- DIVISION = 3
32- MULTIPLICATION = 4
31+ MULTIPLICATION = 2
32+ DIVISION = 2
3333 PRIMARY = 9
3434
3535 def __lt__ (self , other : OperatorPrecedence ) -> bool :
@@ -43,37 +43,66 @@ def __lt__(self, other: OperatorPrecedence) -> bool:
4343 """
4444 return self .value < other .value
4545
46+ def __le__ (self , other : OperatorPrecedence ) -> bool :
47+ """Test the precedence of this operator is less than or equal to the other operator.
48+
49+ Args:
50+ other: The other operator (on the right-hand side).
51+
52+ Returns:
53+ Whether the precedence of this operator is less than or equal to the other operator.
54+ """
55+ return self .value <= other .value
56+
57+
58+ class Operator (enum .Enum ):
59+ """The precedence of an operator."""
60+
61+ ADDITION = "+"
62+ SUBTRACTION = "-"
63+ MULTIPLICATION = "*"
64+ DIVISION = "/"
65+
66+ @property
67+ def precedence (self ) -> OperatorPrecedence :
68+ """Return the precedence of this operator.
69+
70+ Returns:
71+ The precedence of this operator.
72+ """
73+ match self :
74+ case Operator .SUBTRACTION :
75+ return OperatorPrecedence .SUBTRACTION
76+ case Operator .ADDITION :
77+ return OperatorPrecedence .ADDITION
78+ case Operator .DIVISION :
79+ return OperatorPrecedence .DIVISION
80+ case Operator .MULTIPLICATION :
81+ return OperatorPrecedence .MULTIPLICATION
82+
4683 def __str__ (self ) -> str :
4784 """Return the string representation of the operator precedence.
4885
4986 Returns:
5087 The string representation of the operator precedence.
5188 """
52- match self :
53- case OperatorPrecedence .SUBTRACTION :
54- return "-"
55- case OperatorPrecedence .ADDITION :
56- return "+"
57- case OperatorPrecedence .DIVISION :
58- return "/"
59- case OperatorPrecedence .MULTIPLICATION :
60- return "*"
61- case OperatorPrecedence .PRIMARY :
62- return "primary"
89+ return str (self .value )
6390
6491
6592class StackItem :
6693 """Stack item for the formula formatter."""
6794
68- def __init__ (self , value : str , precedence : OperatorPrecedence ):
95+ def __init__ (self , value : str , precedence : OperatorPrecedence , num_steps : int ):
6996 """Initialize the StackItem.
7097
7198 Args:
7299 value: The value of the stack item.
73100 precedence: The precedence of the stack item.
101+ num_steps: The number of steps of the stack item.
74102 """
75103 self .value = value
76104 self .precedence = precedence
105+ self .num_steps = num_steps
77106
78107 def __str__ (self ) -> str :
79108 """Return the string representation of the stack item.
@@ -83,7 +112,7 @@ def __str__(self) -> str:
83112 Returns:
84113 str: The string representation of the stack item.
85114 """
86- return f'("{ self .value } ", { self .precedence } )'
115+ return f'("{ self .value } ", { self .precedence } , { self . num_steps } )'
87116
88117 def as_left_value (self , outer_precedence : OperatorPrecedence ) -> str :
89118 """Return the value of the stack item with parentheses if necessary.
@@ -105,12 +134,14 @@ def as_right_value(self, outer_precedence: OperatorPrecedence) -> str:
105134 Returns:
106135 str: The value of the stack item with parentheses if necessary.
107136 """
137+ if self .num_steps > 1 :
138+ return (
139+ f"({ self .value } )" if self .precedence <= outer_precedence else self .value
140+ )
108141 return f"({ self .value } )" if self .precedence < outer_precedence else self .value
109142
110143 @staticmethod
111- def create_binary (
112- lhs : StackItem , operator : OperatorPrecedence , rhs : StackItem
113- ) -> StackItem :
144+ def create_binary (lhs : StackItem , operator : Operator , rhs : StackItem ) -> StackItem :
114145 """Create a binary stack item.
115146
116147 Args:
@@ -121,10 +152,11 @@ def create_binary(
121152 Returns:
122153 StackItem: The binary stack item.
123154 """
124- pred = OperatorPrecedence (operator )
155+ pred = OperatorPrecedence (operator . precedence )
125156 return StackItem (
126157 f"{ lhs .as_left_value (pred )} { operator } { rhs .as_right_value (pred )} " ,
127158 pred ,
159+ lhs .num_steps + 1 + rhs .num_steps ,
128160 )
129161
130162 @staticmethod
@@ -137,7 +169,7 @@ def create_primary(value: float) -> StackItem:
137169 Returns:
138170 StackItem: The literal stack item.
139171 """
140- return StackItem (str (value ), OperatorPrecedence .PRIMARY )
172+ return StackItem (str (value ), OperatorPrecedence .PRIMARY , 1 )
141173
142174
143175class FormulaFormatter :
@@ -174,49 +206,48 @@ def _format(self, postfix_expr: list[FormulaStep]) -> str:
174206 case ConstantValue ():
175207 self ._stack .append (StackItem .create_primary (step .value ))
176208 case Adder ():
177- self ._format_binary (OperatorPrecedence .ADDITION )
209+ self ._format_binary (Operator .ADDITION )
178210 case Subtractor ():
179- self ._format_binary (OperatorPrecedence .SUBTRACTION )
211+ self ._format_binary (Operator .SUBTRACTION )
180212 case Multiplier ():
181- self ._format_binary (OperatorPrecedence .MULTIPLICATION )
213+ self ._format_binary (Operator .MULTIPLICATION )
182214 case Divider ():
183- self ._format_binary (OperatorPrecedence .DIVISION )
215+ self ._format_binary (Operator .DIVISION )
184216 case Averager ():
185217 value = (
186218 # pylint: disable=protected-access
187219 f"avg({ ', ' .join (self ._format ([f ]) for f in step .fetchers )} )"
188220 )
189- self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY ))
221+ self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY , 1 ))
190222 case Clipper ():
191223 the_value = self ._stack .pop ()
192224 min_value = step .min_value if step .min_value is not None else "-inf"
193225 max_value = step .max_value if step .max_value is not None else "inf"
194226 value = f"clip({ min_value } , { the_value .value } , { max_value } )"
195- self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY ))
227+ self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY , 1 ))
196228 case Maximizer ():
197229 left , right = self ._pop_two_from_stack ()
198230 value = f"max({ left .value } , { right .value } )"
199- self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY ))
231+ self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY , 1 ))
200232 case Minimizer ():
201233 left , right = self ._pop_two_from_stack ()
202234 value = f"min({ left .value } , { right .value } )"
203- self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY ))
235+ self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY , 1 ))
204236 case MetricFetcher ():
205237 metric_fetcher = step
238+ value = metric_fetcher ._name # pylint: disable=protected-access
206239 if engine_reference := getattr (
207240 metric_fetcher .stream , "_engine_reference" , None
208241 ):
209- value = str (engine_reference )
210- else :
211- value = metric_fetcher ._name # pylint: disable=protected-access
212- self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY ))
242+ value = f"[{ value } ]({ str (engine_reference )} )"
243+ self ._stack .append (StackItem (value , OperatorPrecedence .PRIMARY , 1 ))
213244 case OpenParen ():
214245 pass # We gently ignore this one.
215246
216247 assert len (self ._stack ) == 1
217248 return self ._stack [0 ].value
218249
219- def _format_binary (self , operator : OperatorPrecedence ) -> None :
250+ def _format_binary (self , operator : Operator ) -> None :
220251 """Format a binary operation.
221252
222253 Pops the arguments of the binary expression from the stack
0 commit comments