Fixing tests
This commit is contained in:
parent
9450328527
commit
6303d07bac
@ -2,7 +2,6 @@ from __future__ import unicode_literals
|
||||
import re
|
||||
import six
|
||||
import re
|
||||
import enum
|
||||
from collections import deque
|
||||
from collections import namedtuple
|
||||
|
||||
@ -199,46 +198,47 @@ class ConditionExpressionParser:
|
||||
op = self._make_op_condition(node)
|
||||
return op
|
||||
|
||||
class Kind(enum.Enum):
|
||||
"""Defines types of nodes in the syntax tree."""
|
||||
class Kind:
|
||||
"""Enum defining types of nodes in the syntax tree."""
|
||||
|
||||
# Condition nodes
|
||||
# ---------------
|
||||
OR = enum.auto()
|
||||
AND = enum.auto()
|
||||
NOT = enum.auto()
|
||||
PARENTHESES = enum.auto()
|
||||
FUNCTION = enum.auto()
|
||||
BETWEEN = enum.auto()
|
||||
IN = enum.auto()
|
||||
COMPARISON = enum.auto()
|
||||
OR = 'OR'
|
||||
AND = 'AND'
|
||||
NOT = 'NOT'
|
||||
PARENTHESES = 'PARENTHESES'
|
||||
FUNCTION = 'FUNCTION'
|
||||
BETWEEN = 'BETWEEN'
|
||||
IN = 'IN'
|
||||
COMPARISON = 'COMPARISON'
|
||||
|
||||
# Operand nodes
|
||||
# -------------
|
||||
EXPRESSION_ATTRIBUTE_VALUE = enum.auto()
|
||||
PATH = enum.auto()
|
||||
EXPRESSION_ATTRIBUTE_VALUE = 'EXPRESSION_ATTRIBUTE_VALUE'
|
||||
PATH = 'PATH'
|
||||
|
||||
# Literal nodes
|
||||
# --------------
|
||||
LITERAL = enum.auto()
|
||||
LITERAL = 'LITERAL'
|
||||
|
||||
|
||||
class Nonterminal(enum.Enum):
|
||||
"""Defines nonterminals for defining productions."""
|
||||
CONDITION = enum.auto()
|
||||
OPERAND = enum.auto()
|
||||
COMPARATOR = enum.auto()
|
||||
FUNCTION_NAME = enum.auto()
|
||||
IDENTIFIER = enum.auto()
|
||||
AND = enum.auto()
|
||||
OR = enum.auto()
|
||||
NOT = enum.auto()
|
||||
BETWEEN = enum.auto()
|
||||
IN = enum.auto()
|
||||
COMMA = enum.auto()
|
||||
LEFT_PAREN = enum.auto()
|
||||
RIGHT_PAREN = enum.auto()
|
||||
WHITESPACE = enum.auto()
|
||||
class Nonterminal:
|
||||
"""Enum defining nonterminals for productions."""
|
||||
|
||||
CONDITION = 'CONDITION'
|
||||
OPERAND = 'OPERAND'
|
||||
COMPARATOR = 'COMPARATOR'
|
||||
FUNCTION_NAME = 'FUNCTION_NAME'
|
||||
IDENTIFIER = 'IDENTIFIER'
|
||||
AND = 'AND'
|
||||
OR = 'OR'
|
||||
NOT = 'NOT'
|
||||
BETWEEN = 'BETWEEN'
|
||||
IN = 'IN'
|
||||
COMMA = 'COMMA'
|
||||
LEFT_PAREN = 'LEFT_PAREN'
|
||||
RIGHT_PAREN = 'RIGHT_PAREN'
|
||||
WHITESPACE = 'WHITESPACE'
|
||||
|
||||
|
||||
Node = namedtuple('Node', ['nonterminal', 'kind', 'text', 'value', 'children'])
|
||||
@ -286,7 +286,7 @@ class ConditionExpressionParser:
|
||||
if match:
|
||||
match_text = match.group()
|
||||
break
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
raise ValueError("Cannot parse condition starting at: " +
|
||||
remaining_expression)
|
||||
|
||||
@ -387,7 +387,7 @@ class ConditionExpressionParser:
|
||||
children=[])
|
||||
elif name.startswith('['):
|
||||
# e.g. [123]
|
||||
if not name.endswith(']'):
|
||||
if not name.endswith(']'): # pragma: no cover
|
||||
raise ValueError("Bad path element %s" % name)
|
||||
return self.Node(
|
||||
nonterminal=self.Nonterminal.IDENTIFIER,
|
||||
@ -642,7 +642,7 @@ class ConditionExpressionParser:
|
||||
"Unmatched ) at", nodes)
|
||||
close_paren = nodes.popleft()
|
||||
children = self._apply_booleans(output)
|
||||
all_children = [left_paren, *children, close_paren]
|
||||
all_children = [left_paren] + list(children) + [close_paren]
|
||||
return deque([
|
||||
self.Node(
|
||||
nonterminal=self.Nonterminal.CONDITION,
|
||||
@ -650,7 +650,7 @@ class ConditionExpressionParser:
|
||||
text=" ".join([t.text for t in all_children]),
|
||||
value=None,
|
||||
children=list(children),
|
||||
), *nodes])
|
||||
)] + list(nodes))
|
||||
else:
|
||||
output.append(nodes.popleft())
|
||||
|
||||
@ -747,11 +747,12 @@ class ConditionExpressionParser:
|
||||
return AttributeValue(node.value)
|
||||
elif node.kind == self.Kind.FUNCTION:
|
||||
# size()
|
||||
function_node, *arguments = node.children
|
||||
function_node = node.children[0]
|
||||
arguments = node.children[1:]
|
||||
function_name = function_node.value
|
||||
arguments = [self._make_operand(arg) for arg in arguments]
|
||||
return FUNC_CLASS[function_name](*arguments)
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
raise ValueError("Unknown operand: %r" % node)
|
||||
|
||||
|
||||
@ -768,12 +769,13 @@ class ConditionExpressionParser:
|
||||
self._make_op_condition(rhs))
|
||||
elif node.kind == self.Kind.NOT:
|
||||
child, = node.children
|
||||
return OpNot(self._make_op_condition(child), None)
|
||||
return OpNot(self._make_op_condition(child))
|
||||
elif node.kind == self.Kind.PARENTHESES:
|
||||
child, = node.children
|
||||
return self._make_op_condition(child)
|
||||
elif node.kind == self.Kind.FUNCTION:
|
||||
function_node, *arguments = node.children
|
||||
function_node = node.children[0]
|
||||
arguments = node.children[1:]
|
||||
function_name = function_node.value
|
||||
arguments = [self._make_operand(arg) for arg in arguments]
|
||||
return FUNC_CLASS[function_name](*arguments)
|
||||
@ -784,24 +786,25 @@ class ConditionExpressionParser:
|
||||
self._make_operand(low),
|
||||
self._make_operand(high))
|
||||
elif node.kind == self.Kind.IN:
|
||||
query, *possible_values = node.children
|
||||
query = node.children[0]
|
||||
possible_values = node.children[1:]
|
||||
query = self._make_operand(query)
|
||||
possible_values = [self._make_operand(v) for v in possible_values]
|
||||
return FuncIn(query, *possible_values)
|
||||
elif node.kind == self.Kind.COMPARISON:
|
||||
lhs, comparator, rhs = node.children
|
||||
return OP_CLASS[comparator.value](
|
||||
return COMPARATOR_CLASS[comparator.value](
|
||||
self._make_operand(lhs),
|
||||
self._make_operand(rhs))
|
||||
else:
|
||||
else: # pragma: no cover
|
||||
raise ValueError("Unknown expression node kind %r" % node.kind)
|
||||
|
||||
def _print_debug(self, nodes):
|
||||
def _print_debug(self, nodes): # pragma: no cover
|
||||
print('ROOT')
|
||||
for node in nodes:
|
||||
self._print_node_recursive(node, depth=1)
|
||||
|
||||
def _print_node_recursive(self, node, depth=0):
|
||||
def _print_node_recursive(self, node, depth=0): # pragma: no cover
|
||||
if len(node.children) > 0:
|
||||
print(' ' * depth, node.nonterminal, node.kind)
|
||||
for child in node.children:
|
||||
@ -922,6 +925,9 @@ class OpDefault(Op):
|
||||
class OpNot(Op):
|
||||
OP = 'NOT'
|
||||
|
||||
def __init__(self, lhs):
|
||||
super(OpNot, self).__init__(lhs, None)
|
||||
|
||||
def expr(self, item):
|
||||
lhs = self.lhs.expr(item)
|
||||
return not lhs
|
||||
@ -1002,15 +1008,6 @@ class OpOr(Op):
|
||||
return lhs or rhs
|
||||
|
||||
|
||||
class OpIn(Op):
|
||||
OP = 'IN'
|
||||
|
||||
def expr(self, item):
|
||||
lhs = self.lhs.expr(item)
|
||||
rhs = self.rhs.expr(item)
|
||||
return lhs in rhs
|
||||
|
||||
|
||||
class Func(object):
|
||||
"""
|
||||
Base class for a FilterExpression function
|
||||
@ -1034,14 +1031,14 @@ class FuncAttrExists(Func):
|
||||
|
||||
def __init__(self, attribute):
|
||||
self.attr = attribute
|
||||
super().__init__(attribute)
|
||||
super(FuncAttrExists, self).__init__(attribute)
|
||||
|
||||
def expr(self, item):
|
||||
return self.attr.get_type(item) is not None
|
||||
|
||||
|
||||
def FuncAttrNotExists(attribute):
|
||||
return OpNot(FuncAttrExists(attribute), None)
|
||||
return OpNot(FuncAttrExists(attribute))
|
||||
|
||||
|
||||
class FuncAttrType(Func):
|
||||
@ -1050,7 +1047,7 @@ class FuncAttrType(Func):
|
||||
def __init__(self, attribute, _type):
|
||||
self.attr = attribute
|
||||
self.type = _type
|
||||
super().__init__(attribute, _type)
|
||||
super(FuncAttrType, self).__init__(attribute, _type)
|
||||
|
||||
def expr(self, item):
|
||||
return self.attr.get_type(item) == self.type.expr(item)
|
||||
@ -1062,7 +1059,7 @@ class FuncBeginsWith(Func):
|
||||
def __init__(self, attribute, substr):
|
||||
self.attr = attribute
|
||||
self.substr = substr
|
||||
super().__init__(attribute, substr)
|
||||
super(FuncBeginsWith, self).__init__(attribute, substr)
|
||||
|
||||
def expr(self, item):
|
||||
if self.attr.get_type(item) != 'S':
|
||||
@ -1078,7 +1075,7 @@ class FuncContains(Func):
|
||||
def __init__(self, attribute, operand):
|
||||
self.attr = attribute
|
||||
self.operand = operand
|
||||
super().__init__(attribute, operand)
|
||||
super(FuncContains, self).__init__(attribute, operand)
|
||||
|
||||
def expr(self, item):
|
||||
if self.attr.get_type(item) in ('S', 'SS', 'NS', 'BS', 'L'):
|
||||
@ -1090,7 +1087,7 @@ class FuncContains(Func):
|
||||
|
||||
|
||||
def FuncNotContains(attribute, operand):
|
||||
return OpNot(FuncContains(attribute, operand), None)
|
||||
return OpNot(FuncContains(attribute, operand))
|
||||
|
||||
|
||||
class FuncSize(Func):
|
||||
@ -1098,7 +1095,7 @@ class FuncSize(Func):
|
||||
|
||||
def __init__(self, attribute):
|
||||
self.attr = attribute
|
||||
super().__init__(attribute)
|
||||
super(FuncSize, self).__init__(attribute)
|
||||
|
||||
def expr(self, item):
|
||||
if self.attr.get_type(item) is None:
|
||||
@ -1116,7 +1113,7 @@ class FuncBetween(Func):
|
||||
self.attr = attribute
|
||||
self.start = start
|
||||
self.end = end
|
||||
super().__init__(attribute, start, end)
|
||||
super(FuncBetween, self).__init__(attribute, start, end)
|
||||
|
||||
def expr(self, item):
|
||||
return self.start.expr(item) <= self.attr.expr(item) <= self.end.expr(item)
|
||||
@ -1128,7 +1125,7 @@ class FuncIn(Func):
|
||||
def __init__(self, attribute, *possible_values):
|
||||
self.attr = attribute
|
||||
self.possible_values = possible_values
|
||||
super().__init__(attribute, *possible_values)
|
||||
super(FuncIn, self).__init__(attribute, *possible_values)
|
||||
|
||||
def expr(self, item):
|
||||
for possible_value in self.possible_values:
|
||||
@ -1138,11 +1135,7 @@ class FuncIn(Func):
|
||||
return False
|
||||
|
||||
|
||||
OP_CLASS = {
|
||||
'NOT': OpNot,
|
||||
'AND': OpAnd,
|
||||
'OR': OpOr,
|
||||
'IN': OpIn,
|
||||
COMPARATOR_CLASS = {
|
||||
'<': OpLessThan,
|
||||
'>': OpGreaterThan,
|
||||
'<=': OpLessThanOrEqual,
|
||||
|
@ -6,6 +6,7 @@ import decimal
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
import six
|
||||
|
||||
import boto3
|
||||
from moto.compat import OrderedDict
|
||||
@ -89,7 +90,7 @@ class DynamoType(object):
|
||||
|
||||
Returns DynamoType or None.
|
||||
"""
|
||||
if isinstance(key, str) and self.is_map() and key in self.value:
|
||||
if isinstance(key, six.string_types) and self.is_map() and key in self.value:
|
||||
return DynamoType(self.value[key])
|
||||
|
||||
if isinstance(key, int) and self.is_list():
|
||||
@ -994,7 +995,6 @@ class DynamoDBBackend(BaseBackend):
|
||||
dynamo_types = [DynamoType(value) for value in comparison_values]
|
||||
scan_filters[key] = (comparison_operator, dynamo_types)
|
||||
|
||||
|
||||
filter_expression = get_filter_expression(filter_expression, expr_names, expr_values)
|
||||
|
||||
return table.scan(scan_filters, limit, exclusive_start_key, filter_expression, index_name)
|
||||
@ -1024,12 +1024,12 @@ class DynamoDBBackend(BaseBackend):
|
||||
|
||||
if not get_expected(expected).expr(item):
|
||||
raise ValueError('The conditional request failed')
|
||||
condition_op = get_filter_expression(
|
||||
condition_expression,
|
||||
expression_attribute_names,
|
||||
expression_attribute_values)
|
||||
if not condition_op.expr(current):
|
||||
raise ValueError('The conditional request failed')
|
||||
condition_op = get_filter_expression(
|
||||
condition_expression,
|
||||
expression_attribute_names,
|
||||
expression_attribute_values)
|
||||
if not condition_op.expr(item):
|
||||
raise ValueError('The conditional request failed')
|
||||
|
||||
# Update does not fail on new items, so create one
|
||||
if item is None:
|
||||
|
Loading…
Reference in New Issue
Block a user