I wrote this code as a part of a series of major upgrades to my nestable Robot Framework For Loop that will allow it to evaluate logical expressions written in a single cell from the Robot Framework side, which are parsed in my code as strings.
The user of this method can pass it any of the following expressions on the Robot Framework side (as a small sample of what it supports), and it will work:
${ROBOT_FRAMEWORK_VARIABLE_1}==${ROBOT_FRAMEWORK_VARIABLE_2}
pythonic_variable_1<pythonic_variable_2
(not implemented in the public version yet)1<2
(small arguments with ints)spaced variable 1 >= spaced variable 2
${mixed_variable_1} =>mixed variable 2
It further supports !=
, <=
, and =<
, but it doesn't include =
, !<
, !>
, or any three-character expressions (e.g. !<=
). This was a design choice on my part.
@staticmethod
def _evaluate_boolean_string(condition):
condition = str(condition).replace(" ", "") # Cast the condition as a string with no whitespaces
inverse = False # Assume no !
less = False # Assume no <
greater = False # Assume no >
equal = False # Assume no =
second_equal = False # Assume no ==
# Count the number of conditions that are true.
count = 0 # Initialize the count as 0
start = len(condition) # Initialize the starting index as the last index in condition
start_temp = start
# For all of the parameters...
for param in ['!', '<', '>', '=']:
# Based on which parameter I'm looking at, find the starting index.
if param in condition:
# Advance the count of parameters
count = count + 1
# If the count goes higher than 2, exit the loop early.
if count > 2:
break
# Otherwise, set the parameter to True
elif param == '!':
inverse = True
elif param == '<':
less = True
elif param == '>':
greater = True
elif param == '=' and '==' in condition:
equal = True
second_equal = True
elif param == '=':
equal = True
start_temp = condition.find(param)
# If there is a first variable and...
# If the temporary starting index is less than the current starting index...
if start_temp < start and start_temp != (0 or len(condition)):
# Set the starting index of the comparator to the temporary starting index
start = start_temp
# If there is no first variable or second variable or the user goofed then return False
elif start_temp == 0 \
or (param == '=' and start_temp == len(condition)) \
or count > 2 \
or (param == '=' and count == 0):
# Return False
return False
# Set the first variable to the first variable entered.
first = condition[:start - 1]
# Set the second variable to the second variable entered.
second = condition[start + count:]
# If an exact set of conditions is met, return True. Else, return False.
if (greater or less) and not (greater and less):
if equal:
if greater:
if first >= second:
return True
else:
return False
elif less:
if first <= second:
return True
else:
return False
else:
return False
else:
if greater:
if first > second:
return True
else:
return False
elif less:
if first < second:
return True
else:
return False
else:
return False
elif second_equal or (inverse and equal):
if second_equal:
if first == second:
return True
else:
return False
elif inverse and equal:
if first != second:
return True
else:
return False
else:
return False
By necessity this method needs to be as fast as possible since I'm planning on using it a lot, so I'm primarily after performance-based and simplification-based suggestions.