Skip to content

Fix TypeError when ordering-comparing a number against a string (#169)#364

Open
apoorvdarshan wants to merge 1 commit into
jmespath:developfrom
apoorvdarshan:fix/issue-169-ordering-comparator-mixed-types
Open

Fix TypeError when ordering-comparing a number against a string (#169)#364
apoorvdarshan wants to merge 1 commit into
jmespath:developfrom
apoorvdarshan:fix/issue-169-ordering-comparator-mixed-types

Conversation

@apoorvdarshan

Copy link
Copy Markdown

Fixes #169

Root cause

Ordering operators (<, <=, >, >=) are only valid when both operands belong to the same comparable category (both numbers, or both strings). In TreeInterpreter.visit_comparator, the guard applied _is_comparable to each operand independently:

if not (_is_comparable(left) and _is_comparable(right)):
    return None
return comparator_func(left, right)

Since _is_comparable(x) returned True for either a number or a string, a number/string pair (e.g. 1 and "2") passed the guard and was then handed straight to operator.lt, which raises TypeError in Python 3.

Reproduction

import jmespath

data = [{"id": 1}, {"id": 2}]
jmespath.compile("[?id < '2']").search(data)

Actual output on develop (also reported on 0.9.3 / 1.0.1):

TypeError: '<' not supported between instances of 'int' and 'str'

Per the spec, an ordering comparison between incomparable types evaluates to null, so the filter should simply exclude the item. Corrected output:

[]

Same-category comparisons are unaffected: [?id < `2`] still returns [{"id": 1}], and [?name < 'm'] still works for strings.

Fix

_is_comparable now takes both operands and requires them to be in the same category before an ordering comparison is attempted:

def _is_comparable(x, y):
    return ((_is_actual_number(x) and _is_actual_number(y)) or
            (isinstance(x, string_type) and isinstance(y, string_type)))

The call site becomes _is_comparable(left, right). When the operands are not in the same category, visit_comparator returns None, matching the behavior already used for other incomparable types (list, null, bool). The change is confined to visit_comparator and its private helper; the now-unused local num_types = (int, float) on the adjacent line was removed. _is_comparable is a private, module-internal helper with no other callers.

Tests

Added regression cases to tests/compliance/boolean.json alongside the existing incomparable-ordering cases (emptylist < one, one < boolvalue, ...), covering a number vs. string in both directions for every ordering operator:

one < stringvalue    -> null
one <= stringvalue   -> null
one > stringvalue    -> null
one >= stringvalue   -> null
stringvalue < one    -> null

These fail on the unmodified code (with the TypeError above) and pass after the fix. The full test suite passes (996 passed, 1 skipped).

Disclosure: prepared with AI assistance; reviewed and verified locally.

Ordering operators (`<`, `<=`, `>`, `>=`) are only valid when both
operands are in the same comparable category. `_is_comparable` was
applied to each operand independently, so a number and a string both
passed the guard and were then compared directly, raising
`TypeError: '<' not supported between instances of 'int' and 'str'`
instead of yielding null.

Require both operands to be numbers or both to be strings before
comparing; otherwise return None, matching the spec and the behavior
already used for other incomparable types.

Fixes jmespath#169
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

'<' filter works incorrect in some cases

1 participant