Skip to content

Commit 29d53e8

Browse files
markborkumdmlb2000
authored andcommitted
Implement callable subscripts (#14)
* Implement callable subscripts Implements `length()` function for JSON arrays, and `entries()`, `keys()` and `values()` functions for JSON objects. * Resolve autopep8 and pylint warnings * Resolve pylint warnings * Resolve flake8 E501 warning * Call length() on JSON string * Resolve pylint warnings * Resolve pylint warnings * Fix pre-commit and update pylint Signed-off-by: David Brown <dmlb2000@gmail.com> * Resolve pylint warnings * Resolve pylint warnings * Implement subscript(number[,number]) callable subscript * 100% coverage * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Resolve pylint warnings * Rename callable subscript classes * Implement Array.entries, Array.keys and Array.values methods * Update README.md * Remove unnecessary diffs * Rename __match__ to __call__ * Move callable subscript names into class properties * Construct dictionary of callable subscripts * Resolve pylint warnings * Update README.md * Update typing for callable subscripts * track provenance of callable subscript arguments * Resolve pylint warnings * Rename "number" to "int" * Document callables in README * Transform list into table * Add link to pull request
1 parent 77312b6 commit 29d53e8

File tree

9 files changed

+1134
-306
lines changed

9 files changed

+1134
-306
lines changed

README.md

Lines changed: 122 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This repository contains an implementation of [JSONPath](http://goessner.net/art
77

88
### `Path` class
99

10-
The `jsonpath2.Path.Path` class represents a JSONPath.
10+
The `jsonpath2.path.Path` class represents a JSONPath.
1111

1212
```python
1313
>>> s = '{"hello":"Hello, world!"}'
@@ -24,7 +24,7 @@ The `jsonpath2.Path.Path` class represents a JSONPath.
2424
['$["hello"]']
2525
```
2626

27-
This class is constructed with respect to the given instance of the `jsonpath2.Path.RootNode` class (viz., the `root_node` property).
27+
This class is constructed with respect to the given instance of the `jsonpath2.nodes.root.RootNode` class (viz., the `root_node` property).
2828

2929
#### `parse_str(strdata)` class method
3030

@@ -37,7 +37,7 @@ Parse the contents of the given file and return a new instance of this class.
3737
#### `match(root_value)` instance method
3838

3939
Match the given JSON data structure against this instance.
40-
For each match, yield an instance of the `jsonpath2.Node.MatchData` class.
40+
For each match, yield an instance of the `jsonpath2.node.MatchData` class.
4141

4242
#### `__eq__(other)` instance method
4343

@@ -53,7 +53,7 @@ The root node of the abstract syntax tree for this instance.
5353

5454
### `Node` abstract class
5555

56-
The `jsonpath2.Node.Node` class represents the abstract syntax tree for a JSONPath.
56+
The `jsonpath2.node.Node` class represents the abstract syntax tree for a JSONPath.
5757

5858
#### `__eq__(other)` instance method
5959

@@ -66,15 +66,15 @@ Yields the lexer tokens for the string representation of this instance.
6666
#### `match(root_value, current_value)` instance method
6767

6868
Match the given root and current JSON data structures against this instance.
69-
For each match, yield an instance of the `jsonpath2.Node.MatchData` class.
69+
For each match, yield an instance of the `jsonpath2.node.MatchData` class.
7070

7171
#### `tojsonpath()` instance method
7272

7373
Returns the string representation of this instance.
7474

7575
### `MatchData` class
7676

77-
The `jsonpath2.Node.MatchData` class represents the JSON value and context for a JSONPath match.
77+
The `jsonpath2.node.MatchData` class represents the JSON value and context for a JSONPath match.
7878

7979
This class is constructed with respect to a root JSON value, a current JSON value, and an abstract syntax tree node.
8080

@@ -111,10 +111,125 @@ The abstract syntax tree node.
111111
| JSONPath Filter Expression | Description |
112112
| - | - |
113113
| `$` or `@` | nested JSONPath (returns `true` if any match exists; otherwise, returns `false`) |
114-
| `=`, `!=`, `>`, `>=`, `<`, `<=` | binary operator, where left-hand operand is a nested JSONPath and right-right operand is a JSON value (returns `true` if any match exists; otherwise, returns `false`) |
114+
| `=`, `!=`, `>`, `>=`, `<`, `<=` | binary operator, where left- and right-hand operands are nested JSONPaths or JSON values (returns `true` if any match exists; otherwise, returns `false`) |
115115
| `and`, `or`, `not` | Boolean operator, where operands are JSONPath filter expressions |
116116
| `(` ... `)` | parentheses |
117117

118+
## Functions
119+
120+
> See [#14](https://github.com/pacifica/python-jsonpath2/pull/14) for more information.
121+
122+
The syntax for a function call is the name of the function followed by the arguments in parentheses, i.e., `name(arg1, arg2, ..., argN)`, where the arguments are either JSONPaths or JSON values.
123+
124+
```python
125+
>>> s = '{"hello":"Hello, world!"}'
126+
'{"hello":"Hello, world!"}'
127+
>>> import json
128+
>>> d = json.loads(s)
129+
{'hello':'Hello, world!'}
130+
>>> from jsonpath2.path import Path
131+
>>> p = Path.parse_str('$["hello"][length()]')
132+
<jsonpath2.path.Path object>
133+
>>> list(map(lambda match_data: match_data.current_value, p.match(d)))
134+
[13]
135+
>>> list(map(lambda match_data: match_data.node.tojsonpath(), p.match(d)))
136+
['$["hello"][length()]']
137+
```
138+
139+
| JavaScript Function | Signature |
140+
| - | - |
141+
| [`Array.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length) | `length(): int` |
142+
| [`Array.prototype.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/entries) | `entries(): List[Tuple[int, Any]]` |
143+
| [`Array.prototype.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) | `keys(): List[int]` |
144+
| [`Array.prototype.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/values) | `values(): List[Any]` |
145+
| [`Object.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) | `entries(): List[Tuple[str, Any]]` |
146+
| [`Object.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) | `keys(): List[str]` |
147+
| [`Object.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values) | `values(): List[Any]` |
148+
| [`string.length`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length) | `length(): int` |
149+
| [`String.prototype.charAt()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charAt) | `charAt(index: int): str` |
150+
| [`String.prototype.substring()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/substring) | `substring(indexStart: int, indexEnd: Optional[int]): str` |
151+
152+
<!-- | `Array.prototype.concat()` | |
153+
| `Array.prototype.fill()` | |
154+
| `Array.prototype.flat()` | |
155+
| `Array.prototype.includes()` | |
156+
| `Array.prototype.indexOf()` | |
157+
| `Array.prototype.join()` | |
158+
| `Array.prototype.lastIndexOf()` | |
159+
| `Array.prototype.slice()` | |
160+
| `Array.prototype.sort()` | |
161+
| `Array.prototype.splice()` | |
162+
| `JSON.parse()` | |
163+
| `JSON.stringify()` | |
164+
| `Math.abs()` | |
165+
| `Math.acos()` | |
166+
| `Math.acosh()` | |
167+
| `Math.asin()` | |
168+
| `Math.asinh()` | |
169+
| `Math.atan()` | |
170+
| `Math.atan2()` | |
171+
| `Math.atanh()` | |
172+
| `Math.cbrt()` | |
173+
| `Math.ceil()` | |
174+
| `Math.clz32()` | |
175+
| `Math.cos()` | |
176+
| `Math.cosh()` | |
177+
| `Math.exp()` | |
178+
| `Math.expm1()` | |
179+
| `Math.floor()` | |
180+
| `Math.fround()` | |
181+
| `Math.hypot()` | |
182+
| `Math.imul()` | |
183+
| `Math.log()` | |
184+
| `Math.log10()` | |
185+
| `Math.log1p()` | |
186+
| `Math.log2()` | |
187+
| `Math.max()` | |
188+
| `Math.min()` | |
189+
| `Math.pow()` | |
190+
| `Math.random()` | |
191+
| `Math.round()` | |
192+
| `Math.sign()` | |
193+
| `Math.sin()` | |
194+
| `Math.sinh()` | |
195+
| `Math.sqrt()` | |
196+
| `Math.tan()` | |
197+
| `Math.tanh()` | |
198+
| `Math.trunc()` | |
199+
| `Number.isFinite()` | |
200+
| `Number.isInteger()` | |
201+
| `Number.isNaN()` | |
202+
| `Number.isSafeInteger()` | |
203+
| `Number.parseFloat()` | |
204+
| `Number.parseInt()` | |
205+
| `String.prototype.codeCharAt()` | |
206+
| `String.prototype.codePointAt()` | |
207+
| `String.prototype.concat()` | |
208+
| `String.prototype.endsWith()` | |
209+
| `String.prototype.includes()` | |
210+
| `String.prototype.indexOf()` | |
211+
| `String.prototype.lastIndexOf()` | |
212+
| `String.prototype.localeCompare()` | |
213+
| `String.prototype.match()` | |
214+
| `String.prototype.normalize()` | |
215+
| `String.prototype.padEnd()` | |
216+
| `String.prototype.padStart()` | |
217+
| `String.prototype.repeat()` | |
218+
| `String.prototype.replace()` | |
219+
| `String.prototype.search()` | |
220+
| `String.prototype.slice()` | |
221+
| `String.prototype.split()` | |
222+
| `String.prototype.startsWith()` | |
223+
| `String.prototype.toLocaleLowerCase()` | |
224+
| `String.prototype.toLocaleUpperCase()` | |
225+
| `String.prototype.toLowerCase()` | |
226+
| `String.prototype.toUpperCase()` | |
227+
| `String.prototype.trim()` | |
228+
| `String.prototype.trimEnd()` | |
229+
| `String.prototype.trimStart()` | | -->
230+
231+
In the above table, the type aliases (`Any`, `List`, `Optional` and `Tuple`) are defined by the [`typing`](https://docs.python.org/3/library/typing.html) module from the Python Standard Library.
232+
118233
## Grammar and parser
119234

120235
The [ANTLR v4](https://github.com/antlr/antlr4) grammar for JSONPath is available at `jsonpath2/parser/JSONPath.g4`.

jsonpath2/parser/JSONPath.g4

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,12 @@ subscriptables
5454
: BRACKET_LEFT subscriptable ( COMMA subscriptable )* BRACKET_RIGHT
5555
;
5656

57+
subscriptableArguments
58+
: PAREN_LEFT ( jsonpath__ ( COMMA jsonpath__ )* )? PAREN_RIGHT
59+
;
60+
5761
subscriptableBareword
58-
: ID
62+
: ID subscriptableArguments?
5963
| WILDCARD_SUBSCRIPT
6064
;
6165

@@ -66,6 +70,7 @@ subscriptable
6670
| WILDCARD_SUBSCRIPT
6771
| QUESTION PAREN_LEFT expression PAREN_RIGHT
6872
| jsonpath_
73+
| ID subscriptableArguments
6974
;
7075

7176
sliceable

0 commit comments

Comments
 (0)