diff --git a/jmespath/visitor.py b/jmespath/visitor.py index 15fb1774..d9fbba0b 100644 --- a/jmespath/visitor.py +++ b/jmespath/visitor.py @@ -35,12 +35,18 @@ def _is_special_number_case(x, y): return isinstance(x, bool) -def _is_comparable(x): +def _is_comparable(x, y): + # Ordering operators are only valid when both operands + # belong to the same comparable category, i.e. both are + # numbers or both are strings. Mixing categories (e.g. a + # number and a string) is not comparable and yields null. + # # The spec doesn't officially support string types yet, # but enough people are relying on this behavior that # it's been added back. This should eventually become # part of the official spec. - return _is_actual_number(x) or isinstance(x, string_type) + return ((_is_actual_number(x) and _is_actual_number(y)) or + (isinstance(x, string_type) and isinstance(y, string_type))) def _is_actual_number(x): @@ -151,9 +157,7 @@ def visit_comparator(self, node, value): # will yield a None value. left = self.visit(node['children'][0], value) right = self.visit(node['children'][1], value) - num_types = (int, float) - if not (_is_comparable(left) and - _is_comparable(right)): + if not _is_comparable(left, right): return None return comparator_func(left, right) diff --git a/tests/compliance/boolean.json b/tests/compliance/boolean.json index dd7ee588..891494c4 100644 --- a/tests/compliance/boolean.json +++ b/tests/compliance/boolean.json @@ -220,7 +220,8 @@ "two": 2, "three": 3, "emptylist": [], - "boolvalue": false + "boolvalue": false, + "stringvalue": "2" }, "cases": [ { @@ -267,6 +268,26 @@ "expression": "one < boolvalue", "result": null }, + { + "expression": "one < stringvalue", + "result": null + }, + { + "expression": "one <= stringvalue", + "result": null + }, + { + "expression": "one > stringvalue", + "result": null + }, + { + "expression": "one >= stringvalue", + "result": null + }, + { + "expression": "stringvalue < one", + "result": null + }, { "expression": "one < two && three > one", "result": true