jsonata-python 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- jsonata/__init__.py +10 -0
- jsonata/cli/__init__.py +0 -0
- jsonata/cli/__main__.py +242 -0
- jsonata/constants.py +68 -0
- jsonata/datetimeutils.py +1144 -0
- jsonata/functions.py +2179 -0
- jsonata/jexception.py +232 -0
- jsonata/jsonata.py +2045 -0
- jsonata/parser.py +1397 -0
- jsonata/signature.py +441 -0
- jsonata/timebox.py +89 -0
- jsonata/tokenizer.py +306 -0
- jsonata/utils.py +150 -0
- jsonata_python-0.1.0.dist-info/METADATA +338 -0
- jsonata_python-0.1.0.dist-info/RECORD +17 -0
- jsonata_python-0.1.0.dist-info/WHEEL +4 -0
- jsonata_python-0.1.0.dist-info/licenses/LICENSE +202 -0
jsonata/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from jsonata.constants import Constants
|
|
2
|
+
from jsonata.datetimeutils import DateTimeUtils
|
|
3
|
+
from jsonata.functions import Functions
|
|
4
|
+
from jsonata.jexception import JException
|
|
5
|
+
from jsonata.jsonata import Jsonata
|
|
6
|
+
from jsonata.parser import Parser
|
|
7
|
+
from jsonata.signature import Signature
|
|
8
|
+
from jsonata.timebox import Timebox
|
|
9
|
+
from jsonata.tokenizer import Tokenizer
|
|
10
|
+
from jsonata.utils import Utils
|
jsonata/cli/__init__.py
ADDED
|
File without changes
|
jsonata/cli/__main__.py
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright Robert Yokota
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
# Derived from the following code:
|
|
17
|
+
#
|
|
18
|
+
# Project name: jsonata-cli
|
|
19
|
+
# Copyright Dashjoin GmbH. https://dashjoin.com
|
|
20
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import cmd
|
|
25
|
+
import json
|
|
26
|
+
import sys
|
|
27
|
+
from typing import Any, Optional
|
|
28
|
+
|
|
29
|
+
from jsonata import functions, jexception, jsonata, timebox
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_options(argv: Optional[list[str]] = None) -> argparse.ArgumentParser:
|
|
33
|
+
"""Parses command-line arguments.
|
|
34
|
+
"""
|
|
35
|
+
parser = argparse.ArgumentParser(prog="jsonata.cli", description="Pure Python JSONata CLI")
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"-v", "--version", action='version', version='%(prog)s 0.1.0')
|
|
38
|
+
|
|
39
|
+
parser.add_argument(
|
|
40
|
+
"-e", "--expression", metavar="<file>",
|
|
41
|
+
help="JSON expression to evaluate."
|
|
42
|
+
)
|
|
43
|
+
parser.add_argument(
|
|
44
|
+
"-i", "--input", metavar="<arg>",
|
|
45
|
+
help="JSON input file (- for stdin)"
|
|
46
|
+
)
|
|
47
|
+
parser.add_argument(
|
|
48
|
+
"-ic", "--icharset", default="utf-8", metavar="<arg>",
|
|
49
|
+
help="Input character set (default=utf-8)"
|
|
50
|
+
)
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"-f", "--format", choices=['auto', 'json', 'string'], default="auto",
|
|
53
|
+
help="Input format (default=auto)"
|
|
54
|
+
)
|
|
55
|
+
parser.add_argument(
|
|
56
|
+
"-o", "--output", metavar="<arg>",
|
|
57
|
+
help="JSON output file (- for stdin)"
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"-oc", "--ocharset", default="utf-8", metavar="<arg>",
|
|
61
|
+
help="Output character set (default=utf-8)"
|
|
62
|
+
)
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"-time", default=False, action="store_true",
|
|
65
|
+
help="Print performance timers to stderr"
|
|
66
|
+
)
|
|
67
|
+
parser.add_argument(
|
|
68
|
+
"-c", "--compact", default=False, action="store_true",
|
|
69
|
+
help="Compact JSON output (don't prettify)"
|
|
70
|
+
)
|
|
71
|
+
parser.add_argument(
|
|
72
|
+
"-b", "--bindings", metavar="<json-string>",
|
|
73
|
+
help="JSONata variable bindings"
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"-bf", "--bindings-file", dest="bindings_file", metavar="<file>",
|
|
77
|
+
help="JSONata variable bindings file"
|
|
78
|
+
)
|
|
79
|
+
parser.add_argument(
|
|
80
|
+
"-it", "--interactive", default=False, action="store_true",
|
|
81
|
+
help="Interactive REPL"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# The expression
|
|
85
|
+
parser.add_argument(
|
|
86
|
+
"expr", nargs='?')
|
|
87
|
+
|
|
88
|
+
return parser
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class JsonataREPL(cmd.Cmd):
|
|
92
|
+
prompt = "JSONata> "
|
|
93
|
+
intro = "Enter an expression to have it evaluated."
|
|
94
|
+
|
|
95
|
+
def __init__(self, doc, bindings):
|
|
96
|
+
super().__init__()
|
|
97
|
+
self.doc = doc
|
|
98
|
+
self.bindings = bindings
|
|
99
|
+
|
|
100
|
+
def jsonata_eval(self, text: str) -> Optional[Any]:
|
|
101
|
+
try:
|
|
102
|
+
j = jsonata.Jsonata.jsonata(text)
|
|
103
|
+
frame = j.create_frame()
|
|
104
|
+
for k, v in self.bindings.items():
|
|
105
|
+
frame.bind(k, v)
|
|
106
|
+
return j.evaluate(self.doc, frame)
|
|
107
|
+
except jexception.JException as ex:
|
|
108
|
+
print("JSONata error: " + str(ex) + "\n")
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
def preloop(self) -> None:
|
|
112
|
+
pass
|
|
113
|
+
|
|
114
|
+
def do_set(self, args: str) -> bool:
|
|
115
|
+
"""Set variable expression
|
|
116
|
+
|
|
117
|
+
Evaluates the expression, saves the result as the given variable in the current activation.
|
|
118
|
+
"""
|
|
119
|
+
name, space, args = args.partition(' ')
|
|
120
|
+
value = json.loads(args)
|
|
121
|
+
print(value)
|
|
122
|
+
self.bindings[name] = value
|
|
123
|
+
return False
|
|
124
|
+
|
|
125
|
+
def do_show(self, args: str) -> bool:
|
|
126
|
+
"""Shows all variables in the current activation."""
|
|
127
|
+
print(self.bindings)
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
def do_quit(self, args: str) -> bool:
|
|
131
|
+
"""Quits from the REPL."""
|
|
132
|
+
return True
|
|
133
|
+
|
|
134
|
+
do_exit = do_quit
|
|
135
|
+
|
|
136
|
+
def default(self, args: str) -> bool:
|
|
137
|
+
"""Evaluate an expression."""
|
|
138
|
+
try:
|
|
139
|
+
value = self.jsonata_eval(args)
|
|
140
|
+
print(value)
|
|
141
|
+
except Exception as ex:
|
|
142
|
+
pass
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def read_input(inp: str, format: str) -> str:
|
|
147
|
+
if format == "auto":
|
|
148
|
+
try:
|
|
149
|
+
return json.loads(inp)
|
|
150
|
+
except json.JSONDecodeError:
|
|
151
|
+
return inp
|
|
152
|
+
elif format == "json":
|
|
153
|
+
return json.loads(inp)
|
|
154
|
+
elif format == "string":
|
|
155
|
+
return inp
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def main(argv: Optional[list[str]] = None) -> int:
|
|
159
|
+
parser = get_options(argv)
|
|
160
|
+
options = parser.parse_args(argv)
|
|
161
|
+
|
|
162
|
+
if options.expression is None and options.expr is None:
|
|
163
|
+
parser.print_help()
|
|
164
|
+
return 1
|
|
165
|
+
|
|
166
|
+
icharset = options.icharset
|
|
167
|
+
ocharset = options.icharset
|
|
168
|
+
|
|
169
|
+
expr_file = options.expression
|
|
170
|
+
if expr_file is None:
|
|
171
|
+
expr = options.expr
|
|
172
|
+
else:
|
|
173
|
+
with open(expr_file, 'r', encoding=icharset) as fd:
|
|
174
|
+
expr = fd.read()
|
|
175
|
+
|
|
176
|
+
prettify = not options.compact
|
|
177
|
+
|
|
178
|
+
bindings_file = options.bindings_file
|
|
179
|
+
if bindings_file is None:
|
|
180
|
+
bindings_str = options.bindings
|
|
181
|
+
else:
|
|
182
|
+
with open(bindings_file, 'r', encoding=icharset) as fd:
|
|
183
|
+
bindings_str = fd.read()
|
|
184
|
+
if bindings_str is None:
|
|
185
|
+
bindings = {}
|
|
186
|
+
else:
|
|
187
|
+
bindings = json.loads(bindings_str)
|
|
188
|
+
|
|
189
|
+
if options.input == '-' or options.input is None:
|
|
190
|
+
input = sys.stdin.read()
|
|
191
|
+
else:
|
|
192
|
+
with open(options.input, 'r', encoding=icharset) as fd:
|
|
193
|
+
input = fd.read()
|
|
194
|
+
|
|
195
|
+
t0 = timebox.Timebox.current_milli_time()
|
|
196
|
+
|
|
197
|
+
format = options.format
|
|
198
|
+
doc = read_input(input, format)
|
|
199
|
+
|
|
200
|
+
t1 = timebox.Timebox.current_milli_time()
|
|
201
|
+
|
|
202
|
+
if options.interactive:
|
|
203
|
+
repl = JsonataREPL(doc, bindings)
|
|
204
|
+
repl.cmdloop()
|
|
205
|
+
return 0
|
|
206
|
+
|
|
207
|
+
try:
|
|
208
|
+
j = jsonata.Jsonata.jsonata(expr)
|
|
209
|
+
frame = j.create_frame()
|
|
210
|
+
for k, v in bindings.items():
|
|
211
|
+
frame.bind(k, v)
|
|
212
|
+
|
|
213
|
+
t2 = timebox.Timebox.current_milli_time()
|
|
214
|
+
|
|
215
|
+
result = j.evaluate(doc, frame)
|
|
216
|
+
|
|
217
|
+
t3 = timebox.Timebox.current_milli_time()
|
|
218
|
+
|
|
219
|
+
s = functions.Functions.string(result, prettify)
|
|
220
|
+
|
|
221
|
+
output = options.output
|
|
222
|
+
if output is None:
|
|
223
|
+
print(s)
|
|
224
|
+
else:
|
|
225
|
+
with open(output, 'w', encoding=ocharset) as fd:
|
|
226
|
+
fd.write(s)
|
|
227
|
+
|
|
228
|
+
t4 = timebox.Timebox.current_milli_time()
|
|
229
|
+
|
|
230
|
+
if options.time:
|
|
231
|
+
sys.stderr.write("Performance(millis): total=" + str(t4-t0) + " t(in)=" + str(t1-t0) +
|
|
232
|
+
" t(parse)=" + str(t2-t1) + " t(eval)="+str(t3-t2) + " t(out)=" + str(t4-t3) + "\n")
|
|
233
|
+
except jexception.JException as ex:
|
|
234
|
+
sys.stderr.write("JSONata error: " + str(ex) + "\n")
|
|
235
|
+
return 1
|
|
236
|
+
|
|
237
|
+
return 0
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
if __name__ == "__main__":
|
|
241
|
+
ret = main(sys.argv[1:])
|
|
242
|
+
sys.exit(ret)
|
jsonata/constants.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright Robert Yokota
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
# Derived from the following code:
|
|
17
|
+
#
|
|
18
|
+
# Project name: jsonata-java
|
|
19
|
+
# Copyright Dashjoin GmbH. https://dashjoin.com
|
|
20
|
+
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
21
|
+
#
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# Constants required by DateTimeUtils
|
|
25
|
+
#
|
|
26
|
+
class Constants:
|
|
27
|
+
ERR_MSG_SEQUENCE_UNSUPPORTED = "Formatting or parsing an integer as a sequence starting with %s is not supported by this implementation"
|
|
28
|
+
ERR_MSG_DIFF_DECIMAL_GROUP = "In a decimal digit pattern, all digits must be from the same decimal group"
|
|
29
|
+
ERR_MSG_NO_CLOSING_BRACKET = "No matching closing bracket ']' in date/time picture string"
|
|
30
|
+
ERR_MSG_UNKNOWN_COMPONENT_SPECIFIER = "Unknown component specifier %s in date/time picture string"
|
|
31
|
+
ERR_MSG_INVALID_NAME_MODIFIER = "The 'name' modifier can only be applied to months and days in the date/time picture string, not %s"
|
|
32
|
+
ERR_MSG_TIMEZONE_FORMAT = "The timezone integer format specifier cannot have more than four digits"
|
|
33
|
+
ERR_MSG_MISSING_FORMAT = "The date/time picture string is missing specifiers required to parse the timestamp"
|
|
34
|
+
ERR_MSG_INVALID_OPTIONS_SINGLE_CHAR = "Argument 3 of function %s is invalid. The value of the %s property must be a single character"
|
|
35
|
+
ERR_MSG_INVALID_OPTIONS_STRING = "Argument 3 of function %s is invalid. The value of the %s property must be a string"
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Collection of decimal format strings that defined by xsl:decimal-format.
|
|
39
|
+
#
|
|
40
|
+
# <pre>
|
|
41
|
+
# <!ELEMENT xsl:decimal-format EMPTY>
|
|
42
|
+
# <!ATTLIST xsl:decimal-format
|
|
43
|
+
# name %qname; #IMPLIED
|
|
44
|
+
# decimal-separator %char; "."
|
|
45
|
+
# grouping-separator %char; ","
|
|
46
|
+
# infinity CDATA "Infinity"
|
|
47
|
+
# minus-sign %char; "-"
|
|
48
|
+
# NaN CDATA "NaN"
|
|
49
|
+
# percent %char; "%"
|
|
50
|
+
# per-mille %char; "‰"
|
|
51
|
+
# zero-digit %char; "0"
|
|
52
|
+
# digit %char; "#"
|
|
53
|
+
# pattern-separator %char; ";">
|
|
54
|
+
# </pre>
|
|
55
|
+
#
|
|
56
|
+
# http://www.w3.org/TR/xslt#format-number} to explain format-number in XSLT
|
|
57
|
+
# Specification xsl.usage advanced
|
|
58
|
+
#
|
|
59
|
+
SYMBOL_DECIMAL_SEPARATOR = "decimal-separator"
|
|
60
|
+
SYMBOL_GROUPING_SEPARATOR = "grouping-separator"
|
|
61
|
+
SYMBOL_INFINITY = "infinity"
|
|
62
|
+
SYMBOL_MINUS_SIGN = "minus-sign"
|
|
63
|
+
SYMBOL_NAN = "NaN"
|
|
64
|
+
SYMBOL_PERCENT = "percent"
|
|
65
|
+
SYMBOL_PER_MILLE = "per-mille"
|
|
66
|
+
SYMBOL_ZERO_DIGIT = "zero-digit"
|
|
67
|
+
SYMBOL_DIGIT = "digit"
|
|
68
|
+
SYMBOL_PATTERN_SEPARATOR = "pattern-separator"
|