diff --git a/boto3/dynamodb/conditions.py b/boto3/dynamodb/conditions.py index 74b3e8e783..fc349a623e 100644 --- a/boto3/dynamodb/conditions.py +++ b/boto3/dynamodb/conditions.py @@ -20,6 +20,7 @@ ) ATTR_NAME_REGEX = re.compile(r'[^.\[\]]+(?![^\[]*\])') +EXPR_STR_FORMAT_REGEX = re.compile(r"\{(\d+)\}") class ConditionBase: @@ -59,6 +60,14 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + def __repr__(self) -> str: + format_str = EXPR_STR_FORMAT_REGEX.sub( + r"{values[\1]}", self.expression_format + ) + return format_str.format( + values=self._values, operator=self.expression_operator + ) + class AttributeBase: def __init__(self, name): @@ -132,6 +141,9 @@ def __eq__(self, other): def __ne__(self, other): return not self.__eq__(other) + def __repr__(self) -> str: + return self.name + class ConditionAttributeBase(ConditionBase, AttributeBase): """This base class is for conditions that can have attribute methods. diff --git a/tests/unit/dynamodb/test_conditions.py b/tests/unit/dynamodb/test_conditions.py index 9b2be8dc50..736cbf6c36 100644 --- a/tests/unit/dynamodb/test_conditions.py +++ b/tests/unit/dynamodb/test_conditions.py @@ -284,6 +284,10 @@ def test_eq(self): }, ) + def test_eq_repr(self): + actual_repr = str(Equals(self.value, self.value2)) + assert actual_repr == 'mykey = foo' + def test_ne(self): self.build_and_assert_expression( NotEquals(self.value, self.value2), @@ -294,6 +298,10 @@ def test_ne(self): }, ) + def test_ne_repr(self): + actual_repr = str(NotEquals(self.value, self.value2)) + assert actual_repr == 'mykey <> foo' + def test_lt(self): self.build_and_assert_expression( LessThan(self.value, self.value2), @@ -304,6 +312,10 @@ def test_lt(self): }, ) + def test_lt_repr(self): + actual_repr = str(LessThan(self.value, self.value2)) + assert actual_repr == 'mykey < foo' + def test_lte(self): self.build_and_assert_expression( LessThanEquals(self.value, self.value2), @@ -314,6 +326,10 @@ def test_lte(self): }, ) + def test_lte_repr(self): + actual_repr = str(LessThanEquals(self.value, self.value2)) + assert actual_repr == 'mykey <= foo' + def test_gt(self): self.build_and_assert_expression( GreaterThan(self.value, self.value2), @@ -324,6 +340,10 @@ def test_gt(self): }, ) + def test_gt_repr(self): + actual_repr = str(GreaterThan(self.value, self.value2)) + assert actual_repr == 'mykey > foo' + def test_gte(self): self.build_and_assert_expression( GreaterThanEquals(self.value, self.value2), @@ -334,6 +354,10 @@ def test_gte(self): }, ) + def test_gte_repr(self): + actual_repr = str(GreaterThanEquals(self.value, self.value2)) + assert actual_repr == 'mykey >= foo' + def test_in(self): cond = In(self.value, (self.value2)) self.build_and_assert_expression( @@ -346,6 +370,10 @@ def test_in(self): ) assert cond.has_grouped_values + def test_in_repr(self): + actual_repr = str(In(self.value, self.value2)) + assert actual_repr == 'mykey IN foo' + def test_bet(self): self.build_and_assert_expression( Between(self.value, self.value2, 'foo2'), @@ -356,6 +384,10 @@ def test_bet(self): }, ) + def test_bet_repr(self): + actual_repr = str(Between(self.value, self.value2, 'foo2')) + assert actual_repr == 'mykey BETWEEN foo AND foo2' + def test_beg(self): self.build_and_assert_expression( BeginsWith(self.value, self.value2), @@ -366,6 +398,10 @@ def test_beg(self): }, ) + def test_beg_repr(self): + actual_repr = str(BeginsWith(self.value, self.value2)) + assert actual_repr == 'begins_with(mykey, foo)' + def test_cont(self): self.build_and_assert_expression( Contains(self.value, self.value2), @@ -376,6 +412,10 @@ def test_cont(self): }, ) + def test_cont_repr(self): + actual_repr = str(Contains(self.value, self.value2)) + assert actual_repr == 'contains(mykey, foo)' + def test_ae(self): self.build_and_assert_expression( AttributeExists(self.value), @@ -386,6 +426,10 @@ def test_ae(self): }, ) + def test_ae_repr(self): + actual_repr = str(AttributeExists(self.value)) + assert actual_repr == 'attribute_exists(mykey)' + def test_ane(self): self.build_and_assert_expression( AttributeNotExists(self.value), @@ -396,6 +440,10 @@ def test_ane(self): }, ) + def test_ane_repr(self): + actual_repr = str(AttributeNotExists(self.value)) + assert actual_repr == 'attribute_not_exists(mykey)' + def test_size(self): self.build_and_assert_expression( Size(self.value), @@ -406,6 +454,10 @@ def test_size(self): }, ) + def test_size_repr(self): + actual_repr = str(Size(self.value)) + assert actual_repr == 'size(mykey)' + def test_size_can_use_attr_methods(self): size = Size(self.value) self.build_and_assert_expression( @@ -417,6 +469,10 @@ def test_size_can_use_attr_methods(self): }, ) + def test_size_eq_repr(self): + actual_repr = str(Size(self.value).eq(self.value2)) + assert actual_repr == 'size(mykey) = foo' + def test_size_can_use_and(self): size = Size(self.value) ae = AttributeExists(self.value) @@ -429,6 +485,10 @@ def test_size_can_use_and(self): }, ) + def test_size_and_ae_repr(self): + actual_repr = str(Size(self.value) & AttributeExists(self.value)) + assert actual_repr == '(size(mykey) AND attribute_exists(mykey))' + def test_attribute_type(self): self.build_and_assert_expression( AttributeType(self.value, self.value2), @@ -439,6 +499,10 @@ def test_attribute_type(self): }, ) + def test_attribute_type_repr(self): + actual_repr = str(AttributeType(self.value, self.value2)) + assert actual_repr == 'attribute_type(mykey, foo)' + def test_and(self): cond1 = Equals(self.value, self.value2) cond2 = Equals(self.value, self.value2) @@ -452,6 +516,12 @@ def test_and(self): }, ) + def test_and_repr(self): + cond1 = Equals(self.value, self.value2) + cond2 = Equals(self.value, self.value2) + actual_repr = str(And(cond1, cond2)) + assert actual_repr == '(mykey = foo AND mykey = foo)' + def test_or(self): cond1 = Equals(self.value, self.value2) cond2 = Equals(self.value, self.value2) @@ -465,6 +535,12 @@ def test_or(self): }, ) + def test_or_repr(self): + cond1 = Equals(self.value, self.value2) + cond2 = Equals(self.value, self.value2) + actual_repr = str(Or(cond1, cond2)) + assert actual_repr == '(mykey = foo OR mykey = foo)' + def test_not(self): cond = Equals(self.value, self.value2) not_cond = Not(cond) @@ -477,6 +553,11 @@ def test_not(self): }, ) + def test_not_repr(self): + cond = Equals(self.value, self.value2) + actual_repr = str(Not(cond)) + assert actual_repr == '(NOT mykey = foo)' + class TestConditionExpressionBuilder(unittest.TestCase): def setUp(self):