Whole file
sean2077/jsonpath-python
The author described this change as “fix: resolve issue #15 where filters with bracket notation returned empty results”. It counts as a record because the check below fails on the code as it stood at 6caa9d4e0 and passes on 100bf6fda, with nothing else changed between the two runs.
Projectsean2077/jsonpath-python
Fix saved2025-11-23
Sharing licenceMIT · LICENSE
Change size+14 −9
What the code was meant to do, written into the code itself as a save note
fix: resolve issue #15 where filters with bracket notation returned empty results
The change
| 53 | 53 | # operators | |
| 54 | 54 | REP_SLICE_CONTENT = re.compile(r"^(-?\d*)?:(-?\d*)?(:-?\d*)?$") | |
| 55 | 55 | REP_SELECT_CONTENT = re.compile(r"^([\w.']+)(, ?[\w.']+)+$") | |
| 56 | - | REP_FILTER_CONTENT = re.compile(r"@\.(.*?)(?=<=|>=|==|!=|>|<| in| not| is)|len\(@\.(.*?)\)") | |
| 56 | + | REP_FILTER_CONTENT = re.compile(r"@([.\[].*?)(?=<=|>=|==|!=|>|<| in| not| is)|len\(@([.\[].*?)\)") | |
| 57 | 57 | ||
| 58 | 58 | # annotations | |
| 59 | 59 | f: list | |
| ⋯ | |||
| 94 | 94 | # pick up special patterns | |
| 95 | 95 | expr = JSONPath.REP_GET_QUOTE.sub(self._get_quote, expr) | |
| 96 | 96 | expr = JSONPath.REP_GET_BACKQUOTE.sub(self._get_backquote, expr) | |
| 97 | + | expr = JSONPath.REP_GET_PAREN.sub(self._get_paren, expr) | |
| 97 | 98 | expr = JSONPath.REP_GET_BRACKET.sub(self._get_bracket, expr) | |
| 98 | 99 | expr = re.sub(r"\.(\.#B)", r"\1", expr) | |
| 99 | - | expr = JSONPath.REP_GET_PAREN.sub(self._get_paren, expr) | |
| 100 | 100 | # split | |
| 101 | 101 | expr = JSONPath.REP_DOUBLEDOT.sub(f"{JSONPath.SEP}..{JSONPath.SEP}", expr) | |
| 102 | 102 | expr = JSONPath.REP_DOT.sub(JSONPath.SEP, expr) | |
| 103 | 103 | # put back | |
| 104 | - | expr = JSONPath.REP_PUT_PAREN.sub(self._put_paren, expr) | |
| 105 | 104 | expr = JSONPath.REP_PUT_BRACKET.sub(self._put_bracket, expr) | |
| 105 | + | expr = JSONPath.REP_PUT_PAREN.sub(self._put_paren, expr) | |
| 106 | 106 | expr = JSONPath.REP_PUT_BACKQUOTE.sub(self._put_backquote, expr) | |
| 107 | 107 | expr = JSONPath.REP_PUT_QUOTE.sub(self._put_quote, expr) | |
| 108 | 108 | if expr.startswith("$;"): | |
| ⋯ | |||
| 147 | 147 | @staticmethod | |
| 148 | 148 | def _gen_obj(m): | |
| 149 | 149 | content = m.group(1) or m.group(2) # group 2 is for len() | |
| 150 | - | ret = "__obj" | |
| 151 | - | for e in content.split("."): | |
| 152 | - | if len(e) >= 2 and ((e[0] == "'" and e[-1] == "'") or (e[0] == '"' and e[-1] == '"')): | |
| 153 | - | e = e[1:-1] | |
| 154 | - | ret += f'["{e}"]' | |
| 155 | - | return ret | |
| 156 | 150 | ||
| 151 | + | def repl(m): | |
| 152 | + | g = m.group(1) | |
| 153 | + | if g[0] in ("'", '"'): | |
| 154 | + | return f"[{g}]" | |
| 155 | + | return f"['{g}']" | |
| 156 | + | ||
| 157 | + | content = re.sub(r"\.(\w+|'[^']*'|\"[^\"]*\")", repl, content) | |
| 158 | + | return "__obj" + content | |
| 159 | + | ||
| 157 | 160 | @staticmethod | |
| 158 | 161 | def _traverse(f, obj, i: int, path: str, *args): | |
| 159 | 162 | if isinstance(obj, list): | |
| ⋯ | |||
| 275 | 278 | if step.startswith("?(") and step.endswith(")"): | |
| 276 | 279 | step = step[2:-1] | |
| 277 | 280 | step = JSONPath.REP_FILTER_CONTENT.sub(self._gen_obj, step) | |
| 281 | + | if isinstance(obj, dict): | |
| 282 | + | self._filter(obj, i + 1, path, step) | |
| 278 | 283 | self._traverse(self._filter, obj, i + 1, path, step) | |
| 279 | 284 | return | |
| 280 | 285 | ||
The check that tells the two apart
fail→pass·tests/test_issues.py::test_issue_15_bracket_notation_in_filter
Check file tests/test_issues.py, taken without changes from the fix and copied onto the older code, so the exact same check runs against both versions.
Origin and history
The code before it6caa9d4e0e9a95363edc6024b41d5b8ea5e785c0
Broken version dated2025-11-23
Modulejsonpath.jsonpath
Units changedJSONPath
Fingerprint84cf1610334e7f71
Checked2026-08-18 by goldset/0.1
Every field above is generated by our program. None of it is written by hand.