From 7c2056e96071f6e562365ff6d6dfdf6a8ba6a4fb Mon Sep 17 00:00:00 2001 From: abulvenz Date: Sat, 25 May 2024 00:16:26 +0000 Subject: [PATCH] feat: Optionally comparing fields in Var.contains, e.g. on rx.Base based types. (#3375) * feat: Optionally comparing fields, e.g. on rx.Base based types. * feat: Minimally invasive change. Leave the current implementation as is. Added test. * fix: Supporting old-school python versions. * fix: Adding masenf's suggestions to use var instead of string. --- reflex/vars.py | 25 +++++++++++++++++-------- tests/test_var.py | 3 +++ 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/reflex/vars.py b/reflex/vars.py index 601caac5d..287502b43 100644 --- a/reflex/vars.py +++ b/reflex/vars.py @@ -838,19 +838,19 @@ class Var: if invoke_fn: # invoke the function on left operand. operation_name = ( - f"{left_operand_full_name}.{fn}({right_operand_full_name})" # type: ignore - ) + f"{left_operand_full_name}.{fn}({right_operand_full_name})" + ) # type: ignore else: # pass the operands as arguments to the function. operation_name = ( - f"{left_operand_full_name} {op} {right_operand_full_name}" # type: ignore - ) + f"{left_operand_full_name} {op} {right_operand_full_name}" + ) # type: ignore operation_name = f"{fn}({operation_name})" else: # apply operator to operands (left operand right_operand) operation_name = ( - f"{left_operand_full_name} {op} {right_operand_full_name}" # type: ignore - ) + f"{left_operand_full_name} {op} {right_operand_full_name}" + ) # type: ignore operation_name = format.wrap(operation_name, "(") else: # apply operator to left operand ( left_operand) @@ -1353,11 +1353,12 @@ class Var: "'in' operator not supported for Var types, use Var.contains() instead." ) - def contains(self, other: Any) -> Var: + def contains(self, other: Any, field: Union[Var, None] = None) -> Var: """Check if a var contains the object `other`. Args: other: The object to check. + field: Optionally specify a field to check on both object and the other var. Raises: VarTypeError: If the var is not a valid type: dict, list, tuple or str. @@ -1393,8 +1394,16 @@ class Var: raise VarTypeError( f"'in ' requires string as left operand, not {other._var_type}" ) + + _var_name = None + if field is None: + _var_name = f"{self._var_name}.includes({other._var_full_name})" + else: + field = Var.create_safe(field, _var_is_string=isinstance(field, str)) + _var_name = f"{self._var_name}.some(e=>e[{field._var_name_unwrapped}]==={other._var_full_name})" + return self._replace( - _var_name=f"{self._var_name}.includes({other._var_full_name})", + _var_name=_var_name, _var_type=bool, _var_is_string=False, merge_var_data=other._var_data, diff --git a/tests/test_var.py b/tests/test_var.py index a58c49392..3a1fb08a8 100644 --- a/tests/test_var.py +++ b/tests/test_var.py @@ -454,6 +454,9 @@ def test_str_contains(var, expected): other_var = BaseVar(_var_name="other", _var_type=str) assert str(var.contains(other_state_var)) == f"{{{expected}.includes(state.other)}}" assert str(var.contains(other_var)) == f"{{{expected}.includes(other)}}" + assert ( + str(var.contains("1", "hello")) == f'{{{expected}.some(e=>e[`hello`]==="1")}}' + ) @pytest.mark.parametrize(