Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update CTS and fix #67

Merged
merged 1 commit into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
**Fixes**

- Fixed handling of JSONPath literals in filter expressions. We now raise a `JSONPathSyntaxError` if a filter expression literal is not part of a comparison, membership or function expression. See [jsonpath-compliance-test-suite#81](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite/pull/81).
- Fixed parsing of number literals including an exponent. Upper case 'e's are now allowed.
- Fixed handling of trailing commas in bracketed selection lists. We now raise a `JSONPathSyntaxError` in such cases.

**Compliance**

- Skipped tests for invalid escape sequences. The JSONPath spec is more strict than Python's JSON decoder when it comes to parsing `\u` escape sequences in string literals. We are adopting a policy of least surprise. The assertion is that most people will expect the JSONPath parser to behave the same as Python's JSON parser. See [jsonpath-compliance-test-suite #87](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite/pull/87).
- Skipped tests for invalid integer and float literals. Same as above. We are deliberately choosing to match Python's int and float parsing behavior. See [jsonpath-compliance-test-suite #89](https://github.com/jsonpath-standard/jsonpath-compliance-test-suite/pull/89).
- Skipped tests for incorrect casing `true`, `false` and `null` literals.

**Features**

Expand Down
2 changes: 1 addition & 1 deletion docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ And this is a list of areas where we deviate from [RFC 9535](https://datatracker
- We don't require property names to be quoted inside a bracketed selection, unless the name contains reserved characters.
- We don't require the recursive descent segment to have a selector. `$..` is equivalent to `$..*`.
- We support explicit comparisons to `undefined` as well as implicit existence tests.
- Float literals without a fractional digit are OK. `1.` is equivalent to `1.0`.
- Float literals without a fractional digit are OK or leading digit. `1.` is equivalent to `1.0`.
- We treat literals (such as `true` and `false`) as valid "basic" expressions. For example, `$[?true || false]`, without an existence test or comparison either side of logical _or_, does not raise a syntax error.
- By default, `and` is equivalent to `&&` and `or` is equivalent to `||`.
- `none` and `nil` are aliases for `null`.
Expand Down
5 changes: 3 additions & 2 deletions jsonpath/lex.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""JSONPath tokenization."""

from __future__ import annotations

import re
Expand Down Expand Up @@ -138,8 +139,8 @@ def compile_rules(self) -> Pattern[str]:
(TOKEN_LIST_SLICE, self.slice_list_pattern),
(TOKEN_FUNCTION, self.function_pattern),
(TOKEN_DOT_PROPERTY, self.dot_property_pattern),
(TOKEN_FLOAT, r"-?\d+\.\d*(?:e[+-]?\d+)?"),
(TOKEN_INT, r"-?\d+(?P<G_EXP>e[+\-]?\d+)?\b"),
(TOKEN_FLOAT, r"-?\d+\.\d*(?:[eE][+-]?\d+)?"),
(TOKEN_INT, r"-?\d+(?P<G_EXP>[eE][+\-]?\d+)?\b"),
(TOKEN_DDOT, r"\.\."),
(TOKEN_AND, self.logical_and_pattern),
(TOKEN_OR, self.logical_or_pattern),
Expand Down
6 changes: 6 additions & 0 deletions jsonpath/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@ def parse_selector_list(self, stream: TokenStream) -> ListSelector: # noqa: PLR
stream.expect_peek(TOKEN_COMMA)
stream.next_token()

if stream.peek.kind == TOKEN_RBRACKET:
raise JSONPathSyntaxError(
"unexpected trailing comma",
token=stream.peek,
)

stream.next_token()

if not list_items:
Expand Down
27 changes: 26 additions & 1 deletion tests/test_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import json
import operator
from dataclasses import dataclass
from dataclasses import field
from typing import Any
from typing import List
from typing import Mapping
Expand All @@ -28,6 +29,7 @@ class Case:
result: Any = None
results: Optional[List[Any]] = None
invalid_selector: Optional[bool] = None
tags: List[str] = field(default_factory=list)


SKIP = {
Expand All @@ -43,12 +45,35 @@ class Case:
"functions, match, filter, match function, unicode char class negated, uppercase": "\\P not supported", # noqa: E501
"functions, search, filter, search function, unicode char class, uppercase": "\\p not supported", # noqa: E501
"functions, search, filter, search function, unicode char class negated, uppercase": "\\P not supported", # noqa: E501
"filter, equals number, decimal fraction, no fractional digit": "TODO",
"filter, equals number, decimal fraction, no fractional digit": "expected behavior policy", # noqa: E501
"filter, equals number, decimal fraction, no int digit": "expected behavior policy",
"filter, equals number, invalid no int digit": "expected behavior policy",
"filter, equals number, invalid 00": "expected behavior policy",
"filter, equals number, invalid leading 0": "expected behavior policy",
"filter, equals number, invalid no fractional digit": "expected behavior policy",
"filter, equals number, invalid no fractional digit e": "expected behavior policy",
"slice selector, start, leading 0": "expected behavior policy",
"slice selector, start, -0": "expected behavior policy",
"slice selector, start, leading -0": "expected behavior policy",
"slice selector, end, leading 0": "expected behavior policy",
"slice selector, end, minus space": "expected behavior policy",
"slice selector, end, -0": "expected behavior policy",
"slice selector, end, leading -0": "expected behavior policy",
"slice selector, step, leading 0": "expected behavior policy",
"slice selector, step, minus space": "expected behavior policy",
"slice selector, step, -0": "expected behavior policy",
"slice selector, step, leading -0": "expected behavior policy",
"filter, true, incorrectly capitalized": "flexible literal policy",
"filter, false, incorrectly capitalized": "flexible literal policy",
"filter, null, incorrectly capitalized": "flexible literal policy",
"name selector, double quotes, single high surrogate": "expected behavior policy",
"name selector, double quotes, single low surrogate": "expected behavior policy",
"name selector, double quotes, high high surrogate": "expected behavior policy",
"name selector, double quotes, low low surrogate": "expected behavior policy",
"name selector, double quotes, surrogate non-surrogate": "expected behavior policy",
"name selector, double quotes, non-surrogate surrogate": "expected behavior policy",
"name selector, double quotes, surrogate supplementary": "expected behavior policy",
"name selector, double quotes, supplementary surrogate": "expected behavior policy",
"whitespace, selectors, space between dot and name": "flexible whitespace policy", # noqa: E501
"whitespace, selectors, newline between dot and name": "flexible whitespace policy", # noqa: E501
"whitespace, selectors, tab between dot and name": "flexible whitespace policy", # noqa: E501
Expand Down
Loading