jsonata-python 0.5.2__py3-none-any.whl → 0.6.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/cli/__main__.py CHANGED
@@ -34,7 +34,7 @@ def get_options(argv: Optional[list[str]] = None) -> argparse.ArgumentParser:
34
34
  """
35
35
  parser = argparse.ArgumentParser(prog="jsonata.cli", description="Pure Python JSONata CLI")
36
36
  parser.add_argument(
37
- "-v", "--version", action='version', version='%(prog)s 0.5.2')
37
+ "-v", "--version", action='version', version='%(prog)s 0.6.0')
38
38
 
39
39
  parser.add_argument(
40
40
  "-e", "--expression", metavar="<file>",
@@ -54,7 +54,7 @@ def get_options(argv: Optional[list[str]] = None) -> argparse.ArgumentParser:
54
54
  )
55
55
  parser.add_argument(
56
56
  "-o", "--output", metavar="<arg>",
57
- help="JSON output file (- for stdin)"
57
+ help="JSON output file (default=stdout)"
58
58
  )
59
59
  parser.add_argument(
60
60
  "-oc", "--ocharset", default="utf-8", metavar="<arg>",
@@ -78,7 +78,7 @@ def get_options(argv: Optional[list[str]] = None) -> argparse.ArgumentParser:
78
78
  )
79
79
  parser.add_argument(
80
80
  "-it", "--interactive", default=False, action="store_true",
81
- help="Interactive REPL"
81
+ help="Interactive REPL (requires input file)"
82
82
  )
83
83
 
84
84
  # The expression
@@ -160,8 +160,9 @@ def main(argv: Optional[list[str]] = None) -> int:
160
160
  options = parser.parse_args(argv)
161
161
 
162
162
  if options.expression is None and options.expr is None:
163
- parser.print_help()
164
- return 1
163
+ if not options.interactive:
164
+ parser.print_help()
165
+ return 1
165
166
 
166
167
  icharset = options.icharset
167
168
  ocharset = options.icharset
@@ -187,6 +188,9 @@ def main(argv: Optional[list[str]] = None) -> int:
187
188
  bindings = json.loads(bindings_str)
188
189
 
189
190
  if options.input == '-' or options.input is None:
191
+ if options.interactive:
192
+ parser.print_help()
193
+ return 1
190
194
  input = sys.stdin.read()
191
195
  else:
192
196
  with open(options.input, 'r', encoding=icharset) as fd:
jsonata/functions.py CHANGED
@@ -441,6 +441,13 @@ class Functions:
441
441
  if char is None or not char:
442
442
  char = " "
443
443
 
444
+ # match JS: truncate width to integer
445
+ if width is not None:
446
+ try:
447
+ width = int(width)
448
+ except Exception:
449
+ width = 0
450
+
444
451
  if width < 0:
445
452
  result = Functions.left_pad(string, -width, char)
446
453
  else:
@@ -722,7 +729,7 @@ class Functions:
722
729
  r = None
723
730
  for i in range(0, 10):
724
731
  try:
725
- r = re.sub(pattern, replacement, s, 1)
732
+ r = re.sub(pattern, replacement, s, count=1)
726
733
  break
727
734
  except Exception as e:
728
735
  msg = str(e)
jsonata/parser.py CHANGED
@@ -529,6 +529,12 @@ class Parser:
529
529
  # if/then/else ternary operator ?:
530
530
  self.register(Parser.InfixTernaryOperator(self, tokenizer.Tokenizer.operators["?"]))
531
531
 
532
+ # coalescing operator ??
533
+ self.register(Parser.InfixCoalesce(self, tokenizer.Tokenizer.operators["??"]))
534
+
535
+ # elvis/default operator ?:
536
+ self.register(Parser.InfixDefault(self, tokenizer.Tokenizer.operators["?:"]))
537
+
532
538
  # object transformer
533
539
  self.register(Parser.PrefixObjectTransformer(self))
534
540
 
@@ -854,6 +860,43 @@ class Parser:
854
860
  self._else = self._outer_instance.expression(0)
855
861
  return self
856
862
 
863
+ class InfixCoalesce(Infix):
864
+ _outer_instance: 'Parser'
865
+
866
+ def __init__(self, outer_instance, get):
867
+ super().__init__(outer_instance, "??", get)
868
+ self._outer_instance = outer_instance
869
+
870
+ def led(self, left):
871
+ self.type = "condition"
872
+ # condition becomes function exists(left)
873
+ cond = Parser.Symbol(self._outer_instance)
874
+ cond.type = "function"
875
+ cond.value = "("
876
+ proc = Parser.Symbol(self._outer_instance)
877
+ proc.type = "variable"
878
+ proc.value = "exists"
879
+ cond.procedure = proc
880
+ cond.arguments = [left]
881
+ self.condition = cond
882
+ self.then = left
883
+ self._else = self._outer_instance.expression(0)
884
+ return self
885
+
886
+ class InfixDefault(Infix):
887
+ _outer_instance: 'Parser'
888
+
889
+ def __init__(self, outer_instance, get):
890
+ super().__init__(outer_instance, "?:", get)
891
+ self._outer_instance = outer_instance
892
+
893
+ def led(self, left):
894
+ self.type = "condition"
895
+ self.condition = left
896
+ self.then = left
897
+ self._else = self._outer_instance.expression(0)
898
+ return self
899
+
857
900
  class PrefixObjectTransformer(Prefix):
858
901
  _outer_instance: 'Parser'
859
902
 
jsonata/tokenizer.py CHANGED
@@ -65,6 +65,8 @@ class Tokenizer:
65
65
  '<=': 40,
66
66
  '>=': 40,
67
67
  '~>': 40,
68
+ '?:': 40,
69
+ '??': 40,
68
70
  'and': 30,
69
71
  'or': 25,
70
72
  'in': 40,
@@ -216,6 +218,14 @@ class Tokenizer:
216
218
  # ~> chain function
217
219
  self.position += 2
218
220
  return self.create("operator", "~>")
221
+ if current_char == '?' and have_more and self.path[self.position + 1] == ':':
222
+ # ?: default / elvis operator
223
+ self.position += 2
224
+ return self.create("operator", "?:")
225
+ if current_char == '?' and have_more and self.path[self.position + 1] == '?':
226
+ # ?? coalescing operator
227
+ self.position += 2
228
+ return self.create("operator", "??")
219
229
  # test for single char operators
220
230
  if Tokenizer.operators.get(str(current_char)) is not None:
221
231
  self.position += 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jsonata-python
3
- Version: 0.5.2
3
+ Version: 0.6.0
4
4
  Summary: Pure Python implementation of JSONata
5
5
  Project-URL: Homepage, https://github.com/rayokota/jsonata-python
6
6
  Project-URL: Bug Reports, https://github.com/rayokota/jsonata-python/issues
@@ -278,7 +278,7 @@ options:
278
278
  -f {auto,json,string}, --format {auto,json,string}
279
279
  Input format (default=auto)
280
280
  -o <arg>, --output <arg>
281
- JSON output file (- for stdin)
281
+ JSON output file (default=stdout)
282
282
  -oc <arg>, --ocharset <arg>
283
283
  Output character set (default=utf-8)
284
284
  -time Print performance timers to stderr
@@ -287,7 +287,7 @@ options:
287
287
  JSONata variable bindings
288
288
  -bf <file>, --bindings-file <file>
289
289
  JSONata variable bindings file
290
- -it, --interactive Interactive REPL
290
+ -it, --interactive Interactive REPL (requires input file)
291
291
  ```
292
292
 
293
293
  ### Examples
@@ -317,6 +317,11 @@ helloworld.json
317
317
  "frederic.smith@very-serious.com"
318
318
  ]
319
319
  }
320
+
321
+ % python3 -m jsonata.cli -i helloworld.json -it
322
+ Enter an expression to have it evaluated.
323
+ JSONata> (a & b)
324
+ hello world
320
325
  ```
321
326
 
322
327
  ## Running Tests
@@ -1,17 +1,17 @@
1
1
  jsonata/__init__.py,sha256=4r8USHj4SoBy_TD8dLxt9HJIgpLfXApFrZBipi4rgr0,388
2
2
  jsonata/constants.py,sha256=WtdH_l_s5KD-SiOJ4GR2az7WpVgKB2HguXUnyfy4tvs,3017
3
3
  jsonata/datetimeutils.py,sha256=IzU6y-vwyhwobHyw9rsImBye-RfWDV7K8Vk0Xs-yiG0,48567
4
- jsonata/functions.py,sha256=giAtWZ92cOlnBcH7Zkapnib-LPSPyBFHrz-9AMdkhqQ,75500
4
+ jsonata/functions.py,sha256=2vip5OJt8VMprF1vOnvr3iCQQlLGbfOItQ3MwDXzCTM,75691
5
5
  jsonata/jexception.py,sha256=6Jz7WMsIiNlQ7-1Hq8RKiE2HxcHq2PDekw0qsSe3lqo,12885
6
6
  jsonata/jsonata.py,sha256=jZIxVrNcZI3aBvE0PURZ4-cxpaK9JiJVH5Q_cllCXS0,84247
7
- jsonata/parser.py,sha256=U8nNxvsDIy0wVTfNCs2DNN7RjNVm0SqfociD9cRcsWM,53877
7
+ jsonata/parser.py,sha256=dzZ6PeM5l3scTHq4DzCXt4FSRO49yzYEk7XqspCcHNU,55359
8
8
  jsonata/signature.py,sha256=j7eNKUuGx_9vCt5Qv8BPM7iV5vH26U0Kx8zrkDcctME,20194
9
9
  jsonata/timebox.py,sha256=bnevNR_ONvKUiIZCJZEWsRiR0gCWTGOwn5RCY7dKqYc,2861
10
- jsonata/tokenizer.py,sha256=X-JsARtkBIN6bO8_TElpw3SCageQMtfBWlexuhG2Sds,11982
10
+ jsonata/tokenizer.py,sha256=6noGxO1L_n2V-Uva5oV044Xx0p08Gm7-XXSfLEG4rR0,12429
11
11
  jsonata/utils.py,sha256=U13I49Ie3hEn3PKGR4361TPengDAkbyHmwipDFZJlXo,5192
12
12
  jsonata/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- jsonata/cli/__main__.py,sha256=MMJkVvYUzbWMG5_I142RINTmQntgL17LQKNs1iv1pn4,6971
14
- jsonata_python-0.5.2.dist-info/METADATA,sha256=Oozc2sFoZzLB2IKV33eI9omuQJtsqln4UmjgtnzvxGU,17297
15
- jsonata_python-0.5.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- jsonata_python-0.5.2.dist-info/licenses/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
17
- jsonata_python-0.5.2.dist-info/RECORD,,
13
+ jsonata/cli/__main__.py,sha256=xfwJE5nkt6tYH__Zk1PQ_R0idkmQq1XcAKRFt3-bTEo,7125
14
+ jsonata_python-0.6.0.dist-info/METADATA,sha256=m_Srw48y9PCRzQYzqZz6TJM7mU73pWddDhw9FXEGLOo,17442
15
+ jsonata_python-0.6.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ jsonata_python-0.6.0.dist-info/licenses/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325
17
+ jsonata_python-0.6.0.dist-info/RECORD,,