@ai-ecoverse/py-pyparsing 3.3.3-1

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.
Files changed (43) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +3 -0
  3. package/lib/python3.14/site-packages/pyparsing/__init__.py +413 -0
  4. package/lib/python3.14/site-packages/pyparsing/__pycache__/__init__.cpython-314.pyc +0 -0
  5. package/lib/python3.14/site-packages/pyparsing/__pycache__/actions.cpython-314.pyc +0 -0
  6. package/lib/python3.14/site-packages/pyparsing/__pycache__/common.cpython-314.pyc +0 -0
  7. package/lib/python3.14/site-packages/pyparsing/__pycache__/core.cpython-314.pyc +0 -0
  8. package/lib/python3.14/site-packages/pyparsing/__pycache__/exceptions.cpython-314.pyc +0 -0
  9. package/lib/python3.14/site-packages/pyparsing/__pycache__/helpers.cpython-314.pyc +0 -0
  10. package/lib/python3.14/site-packages/pyparsing/__pycache__/results.cpython-314.pyc +0 -0
  11. package/lib/python3.14/site-packages/pyparsing/__pycache__/testing.cpython-314.pyc +0 -0
  12. package/lib/python3.14/site-packages/pyparsing/__pycache__/unicode.cpython-314.pyc +0 -0
  13. package/lib/python3.14/site-packages/pyparsing/__pycache__/util.cpython-314.pyc +0 -0
  14. package/lib/python3.14/site-packages/pyparsing/__pycache__/warnings.cpython-314.pyc +0 -0
  15. package/lib/python3.14/site-packages/pyparsing/actions.py +264 -0
  16. package/lib/python3.14/site-packages/pyparsing/ai/__init__.py +0 -0
  17. package/lib/python3.14/site-packages/pyparsing/ai/__pycache__/__init__.cpython-314.pyc +0 -0
  18. package/lib/python3.14/site-packages/pyparsing/ai/best_practices.md +75 -0
  19. package/lib/python3.14/site-packages/pyparsing/ai/show_best_practices/__init__.py +0 -0
  20. package/lib/python3.14/site-packages/pyparsing/ai/show_best_practices/__main__.py +2 -0
  21. package/lib/python3.14/site-packages/pyparsing/ai/show_best_practices/__pycache__/__init__.cpython-314.pyc +0 -0
  22. package/lib/python3.14/site-packages/pyparsing/ai/show_best_practices/__pycache__/__main__.cpython-314.pyc +0 -0
  23. package/lib/python3.14/site-packages/pyparsing/common.py +570 -0
  24. package/lib/python3.14/site-packages/pyparsing/core.py +6972 -0
  25. package/lib/python3.14/site-packages/pyparsing/diagram/__init__.py +761 -0
  26. package/lib/python3.14/site-packages/pyparsing/diagram/__pycache__/__init__.cpython-314.pyc +0 -0
  27. package/lib/python3.14/site-packages/pyparsing/exceptions.py +353 -0
  28. package/lib/python3.14/site-packages/pyparsing/helpers.py +1769 -0
  29. package/lib/python3.14/site-packages/pyparsing/py.typed +0 -0
  30. package/lib/python3.14/site-packages/pyparsing/results.py +928 -0
  31. package/lib/python3.14/site-packages/pyparsing/testing.py +398 -0
  32. package/lib/python3.14/site-packages/pyparsing/tools/__init__.py +0 -0
  33. package/lib/python3.14/site-packages/pyparsing/tools/__pycache__/__init__.cpython-314.pyc +0 -0
  34. package/lib/python3.14/site-packages/pyparsing/tools/__pycache__/cvt_pyparsing_pep8_names.cpython-314.pyc +0 -0
  35. package/lib/python3.14/site-packages/pyparsing/tools/cvt_pyparsing_pep8_names.py +142 -0
  36. package/lib/python3.14/site-packages/pyparsing/unicode.py +356 -0
  37. package/lib/python3.14/site-packages/pyparsing/util.py +514 -0
  38. package/lib/python3.14/site-packages/pyparsing/warnings.py +10 -0
  39. package/lib/python3.14/site-packages/pyparsing-3.3.3.dist-info/METADATA +147 -0
  40. package/lib/python3.14/site-packages/pyparsing-3.3.3.dist-info/RECORD +23 -0
  41. package/lib/python3.14/site-packages/pyparsing-3.3.3.dist-info/WHEEL +4 -0
  42. package/lib/python3.14/site-packages/pyparsing-3.3.3.dist-info/licenses/LICENSE +20 -0
  43. package/package.json +27 -0
@@ -0,0 +1,928 @@
1
+ # results.py
2
+
3
+ from __future__ import annotations
4
+
5
+ import collections
6
+ from collections.abc import (
7
+ MutableMapping,
8
+ Mapping,
9
+ MutableSequence,
10
+ Iterator,
11
+ Iterable,
12
+ )
13
+ import pprint
14
+ from typing import Any
15
+
16
+ from .util import deprecate_argument, _is_iterable, _flatten
17
+
18
+
19
+ str_type: tuple[type, ...] = (str, bytes)
20
+ _generator_type = type((_ for _ in ()))
21
+ NULL_SLICE: slice = slice(None)
22
+
23
+
24
+ class _ParseResultsWithOffset:
25
+ tup: tuple[ParseResults, int]
26
+ __slots__ = ["tup"]
27
+
28
+ def __init__(self, p1: ParseResults, p2: int) -> None:
29
+ self.tup: tuple[ParseResults, int] = (p1, p2)
30
+
31
+ def __getitem__(self, i):
32
+ return self.tup[i]
33
+
34
+ def __getstate__(self):
35
+ return self.tup
36
+
37
+ def __setstate__(self, *args):
38
+ self.tup = args[0]
39
+
40
+
41
+ class ParseResults:
42
+ """Structured parse results, to provide multiple means of access to
43
+ the parsed data:
44
+
45
+ - as a list (``len(results)``)
46
+ - by list index (``results[0], results[1]``, etc.)
47
+ - by attribute (``results.<results_name>`` - see :class:`ParserElement.set_results_name`)
48
+
49
+ Example:
50
+
51
+ .. testcode::
52
+
53
+ integer = Word(nums)
54
+ date_str = (integer.set_results_name("year") + '/'
55
+ + integer.set_results_name("month") + '/'
56
+ + integer.set_results_name("day"))
57
+ # equivalent form:
58
+ # date_str = (integer("year") + '/'
59
+ # + integer("month") + '/'
60
+ # + integer("day"))
61
+
62
+ # parse_string returns a ParseResults object
63
+ result = date_str.parse_string("1999/12/31")
64
+
65
+ def test(s, fn=repr):
66
+ print(f"{s} -> {fn(eval(s))}")
67
+
68
+ test("list(result)")
69
+ test("result[0]")
70
+ test("result['month']")
71
+ test("result.day")
72
+ test("'month' in result")
73
+ test("'minutes' in result")
74
+ test("result.dump()", str)
75
+
76
+ prints:
77
+
78
+ .. testoutput::
79
+
80
+ list(result) -> ['1999', '/', '12', '/', '31']
81
+ result[0] -> '1999'
82
+ result['month'] -> '12'
83
+ result.day -> '31'
84
+ 'month' in result -> True
85
+ 'minutes' in result -> False
86
+ result.dump() -> ['1999', '/', '12', '/', '31']
87
+ - day: '31'
88
+ - month: '12'
89
+ - year: '1999'
90
+
91
+ """
92
+
93
+ _null_values: tuple[Any, ...] = (None, [], ())
94
+
95
+ _name: str
96
+ _parent: ParseResults
97
+ _all_names: set[str]
98
+ _modal: bool
99
+ _toklist: list[Any]
100
+ _tokdict: dict[str, Any]
101
+
102
+ __slots__ = (
103
+ "_name",
104
+ "_parent",
105
+ "_all_names",
106
+ "_modal",
107
+ "_toklist",
108
+ "_tokdict",
109
+ )
110
+
111
+ class List(list):
112
+ """
113
+ Simple wrapper class to distinguish parsed list results that should be preserved
114
+ as actual Python lists, instead of being converted to :class:`ParseResults`:
115
+
116
+ .. testcode::
117
+
118
+ import pyparsing as pp
119
+ ppc = pp.common
120
+
121
+ LBRACK, RBRACK, LPAR, RPAR = pp.Suppress.using_each("[]()")
122
+ element = pp.Forward()
123
+ item = ppc.integer
124
+ item_list = pp.DelimitedList(element)
125
+ element_list = LBRACK + item_list + RBRACK | LPAR + item_list + RPAR
126
+ element <<= item | element_list
127
+
128
+ # add parse action to convert from ParseResults
129
+ # to actual Python collection types
130
+ @element_list.add_parse_action
131
+ def as_python_list(t):
132
+ return pp.ParseResults.List(t.as_list())
133
+
134
+ element.run_tests('''
135
+ 100
136
+ [2,3,4]
137
+ [[2, 1],3,4]
138
+ [(2, 1),3,4]
139
+ (2,3,4)
140
+ ([2, 3], 4)
141
+ ''', post_parse=lambda s, r: (r[0], type(r[0]))
142
+ )
143
+
144
+ prints:
145
+
146
+ .. testoutput::
147
+ :options: +NORMALIZE_WHITESPACE
148
+
149
+
150
+ 100
151
+ (100, <class 'int'>)
152
+
153
+ [2,3,4]
154
+ ([2, 3, 4], <class 'list'>)
155
+
156
+ [[2, 1],3,4]
157
+ ([[2, 1], 3, 4], <class 'list'>)
158
+
159
+ [(2, 1),3,4]
160
+ ([[2, 1], 3, 4], <class 'list'>)
161
+
162
+ (2,3,4)
163
+ ([2, 3, 4], <class 'list'>)
164
+
165
+ ([2, 3], 4)
166
+ ([[2, 3], 4], <class 'list'>)
167
+
168
+ (Used internally by :class:`Group` when `aslist=True`.)
169
+ """
170
+
171
+ def __new__(cls, contained=None):
172
+ if contained is None:
173
+ contained = []
174
+
175
+ if not isinstance(contained, list):
176
+ raise TypeError(
177
+ f"{cls.__name__} may only be constructed with a list, not {type(contained).__name__}"
178
+ )
179
+
180
+ return list.__new__(cls)
181
+
182
+ def __new__(cls, toklist=None, name=None, **kwargs):
183
+ if isinstance(toklist, ParseResults):
184
+ return toklist
185
+ self = object.__new__(cls)
186
+ self._name = None
187
+ self._parent = None
188
+ self._all_names = set()
189
+
190
+ if toklist is None:
191
+ self._toklist = []
192
+ elif isinstance(toklist, (list, _generator_type)):
193
+ self._toklist = (
194
+ [toklist[:]]
195
+ if isinstance(toklist, ParseResults.List)
196
+ else list(toklist)
197
+ )
198
+ else:
199
+ self._toklist = [toklist]
200
+ self._tokdict = dict()
201
+ return self
202
+
203
+ # Performance tuning: we construct a *lot* of these, so keep this
204
+ # constructor as small and fast as possible
205
+ def __init__(
206
+ self,
207
+ toklist=None,
208
+ name=None,
209
+ aslist=True,
210
+ modal=True,
211
+ isinstance=isinstance,
212
+ **kwargs,
213
+ ) -> None:
214
+ asList = deprecate_argument(kwargs, "asList", True, new_name="aslist")
215
+
216
+ asList = asList and aslist
217
+ self._tokdict: dict[str, _ParseResultsWithOffset]
218
+ self._modal = modal
219
+
220
+ if name is None or name == "":
221
+ return
222
+
223
+ if isinstance(name, int):
224
+ name = str(name)
225
+
226
+ if not modal:
227
+ self._all_names = {name}
228
+
229
+ self._name = name
230
+
231
+ if toklist in self._null_values:
232
+ return
233
+
234
+ if isinstance(toklist, (str_type, type)):
235
+ toklist = [toklist]
236
+
237
+ if asList:
238
+ if isinstance(toklist, ParseResults):
239
+ self[name] = _ParseResultsWithOffset(ParseResults(toklist._toklist), 0)
240
+ else:
241
+ self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]), 0)
242
+ self[name]._name = name
243
+ return
244
+
245
+ try:
246
+ self[name] = toklist[0]
247
+ except (KeyError, TypeError, IndexError):
248
+ if toklist is not self:
249
+ self[name] = toklist
250
+ else:
251
+ self._name = name
252
+
253
+ def __getitem__(self, i):
254
+ if isinstance(i, (int, slice)):
255
+ return self._toklist[i]
256
+
257
+ if i not in self._all_names:
258
+ return self._tokdict[i][-1][0]
259
+
260
+ return ParseResults([v[0] for v in self._tokdict[i]])
261
+
262
+ def __setitem__(self, k, v, isinstance=isinstance):
263
+ if isinstance(v, _ParseResultsWithOffset):
264
+ self._tokdict[k] = self._tokdict.get(k, list()) + [v]
265
+ sub = v[0]
266
+ elif isinstance(k, (int, slice)):
267
+ self._toklist[k] = v
268
+ sub = v
269
+ else:
270
+ self._tokdict[k] = self._tokdict.get(k, []) + [
271
+ _ParseResultsWithOffset(v, 0)
272
+ ]
273
+ sub = v
274
+ if isinstance(sub, ParseResults):
275
+ sub._parent = self
276
+
277
+ def __delitem__(self, i):
278
+ if not isinstance(i, (int, slice)):
279
+ del self._tokdict[i]
280
+ return
281
+
282
+ # slight optimization if del results[:]
283
+ if i == NULL_SLICE:
284
+ self._toklist.clear()
285
+ return
286
+
287
+ mylen = len(self._toklist)
288
+ del self._toklist[i]
289
+
290
+ # convert int to slice
291
+ if isinstance(i, int):
292
+ if i < 0:
293
+ i += mylen
294
+ i = slice(i, i + 1)
295
+ # get removed indices
296
+ removed = list(range(*i.indices(mylen)))
297
+ removed.reverse()
298
+ # fixup indices in token dictionary
299
+ for occurrences in self._tokdict.values():
300
+ for j in removed:
301
+ for k, (value, position) in enumerate(occurrences):
302
+ occurrences[k] = _ParseResultsWithOffset(
303
+ value, position - (position > j)
304
+ )
305
+
306
+ def __contains__(self, k) -> bool:
307
+ return k in self._tokdict
308
+
309
+ def __len__(self) -> int:
310
+ return len(self._toklist)
311
+
312
+ def __bool__(self) -> bool:
313
+ return not not (self._toklist or self._tokdict)
314
+
315
+ def __iter__(self) -> Iterator:
316
+ return iter(self._toklist)
317
+
318
+ def __reversed__(self) -> Iterator:
319
+ return iter(self._toklist[::-1])
320
+
321
+ def keys(self):
322
+ return iter(self._tokdict)
323
+
324
+ def values(self):
325
+ return (self[k] for k in self.keys())
326
+
327
+ def items(self):
328
+ return ((k, self[k]) for k in self.keys())
329
+
330
+ def haskeys(self) -> bool:
331
+ """
332
+ Since ``keys()`` returns an iterator, this method is helpful in bypassing
333
+ code that looks for the existence of any defined results names."""
334
+ return not not self._tokdict
335
+
336
+ def pop(self, *args, **kwargs):
337
+ """
338
+ Removes and returns item at specified index (default= ``last``).
339
+ Supports both ``list`` and ``dict`` semantics for ``pop()``. If
340
+ passed no argument or an integer argument, it will use ``list``
341
+ semantics and pop tokens from the list of parsed tokens. If passed
342
+ a non-integer argument (most likely a string), it will use ``dict``
343
+ semantics and pop the corresponding value from any defined results
344
+ names. A second default return value argument is supported, just as in
345
+ ``dict.pop()``.
346
+
347
+ Example:
348
+
349
+ .. doctest::
350
+
351
+ >>> numlist = Word(nums)[...]
352
+ >>> print(numlist.parse_string("0 123 321"))
353
+ ['0', '123', '321']
354
+
355
+ >>> def remove_first(tokens):
356
+ ... tokens.pop(0)
357
+ ...
358
+ >>> numlist.add_parse_action(remove_first)
359
+ [W:(0-9)]...
360
+ >>> print(numlist.parse_string("0 123 321"))
361
+ ['123', '321']
362
+
363
+ >>> label = Word(alphas)
364
+ >>> patt = label("LABEL") + Word(nums)[1, ...]
365
+ >>> print(patt.parse_string("AAB 123 321").dump())
366
+ ['AAB', '123', '321']
367
+ - LABEL: 'AAB'
368
+
369
+ >>> # Use pop() in a parse action to remove named result
370
+ >>> # (note that corresponding value is not
371
+ >>> # removed from list form of results)
372
+ >>> def remove_LABEL(tokens):
373
+ ... tokens.pop("LABEL")
374
+ ... return tokens
375
+ ...
376
+ >>> patt.add_parse_action(remove_LABEL)
377
+ {W:(A-Za-z) {W:(0-9)}...}
378
+ >>> print(patt.parse_string("AAB 123 321").dump())
379
+ ['AAB', '123', '321']
380
+
381
+ """
382
+ if not args:
383
+ args = [-1]
384
+ for k, v in kwargs.items():
385
+ if k == "default":
386
+ args = (args[0], v)
387
+ else:
388
+ raise TypeError(f"pop() got an unexpected keyword argument {k!r}")
389
+ if isinstance(args[0], int) or len(args) == 1 or args[0] in self:
390
+ index = args[0]
391
+ ret = self[index]
392
+ del self[index]
393
+ return ret
394
+ else:
395
+ defaultvalue = args[1]
396
+ return defaultvalue
397
+
398
+ def get(self, key, default_value=None):
399
+ """
400
+ Returns named result matching the given key, or if there is no
401
+ such name, then returns the given ``default_value`` or ``None`` if no
402
+ ``default_value`` is specified.
403
+
404
+ Similar to ``dict.get()``.
405
+
406
+ Example:
407
+
408
+ .. doctest::
409
+
410
+ >>> integer = Word(nums)
411
+ >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
412
+
413
+ >>> result = date_str.parse_string("1999/12/31")
414
+ >>> result.get("year")
415
+ '1999'
416
+ >>> result.get("hour", "not specified")
417
+ 'not specified'
418
+ >>> result.get("hour")
419
+
420
+ """
421
+ if key in self:
422
+ return self[key]
423
+ else:
424
+ return default_value
425
+
426
+ def insert(self, index, ins_string):
427
+ """
428
+ Inserts new element at location index in the list of parsed tokens.
429
+
430
+ Similar to ``list.insert()``.
431
+
432
+ Example:
433
+
434
+ .. doctest::
435
+
436
+ >>> numlist = Word(nums)[...]
437
+ >>> print(numlist.parse_string("0 123 321"))
438
+ ['0', '123', '321']
439
+
440
+ >>> # use a parse action to insert the parse location
441
+ >>> # in the front of the parsed results
442
+ >>> def insert_locn(locn, tokens):
443
+ ... tokens.insert(0, locn)
444
+ ...
445
+ >>> numlist.add_parse_action(insert_locn)
446
+ [W:(0-9)]...
447
+ >>> print(numlist.parse_string("0 123 321"))
448
+ [0, '0', '123', '321']
449
+
450
+ """
451
+ self._toklist.insert(index, ins_string)
452
+ # fixup indices in token dictionary
453
+ for occurrences in self._tokdict.values():
454
+ for k, (value, position) in enumerate(occurrences):
455
+ occurrences[k] = _ParseResultsWithOffset(
456
+ value, position + (position > index)
457
+ )
458
+
459
+ def append(self, item):
460
+ """
461
+ Add single element to end of ``ParseResults`` list of elements.
462
+
463
+ Example:
464
+
465
+ .. doctest::
466
+
467
+ >>> numlist = Word(nums)[...]
468
+ >>> print(numlist.parse_string("0 123 321"))
469
+ ['0', '123', '321']
470
+
471
+ >>> # use a parse action to compute the sum of the parsed integers,
472
+ >>> # and add it to the end
473
+ >>> def append_sum(tokens):
474
+ ... tokens.append(sum(map(int, tokens)))
475
+ ...
476
+ >>> numlist.add_parse_action(append_sum)
477
+ [W:(0-9)]...
478
+ >>> print(numlist.parse_string("0 123 321"))
479
+ ['0', '123', '321', 444]
480
+ """
481
+ self._toklist.append(item)
482
+
483
+ def extend(self, itemseq):
484
+ """
485
+ Add sequence of elements to end of :class:`ParseResults` list of elements.
486
+
487
+ Example:
488
+
489
+ .. testcode::
490
+
491
+ patt = Word(alphas)[1, ...]
492
+
493
+ # use a parse action to append the reverse of the matched strings,
494
+ # to make a palindrome
495
+ def make_palindrome(tokens):
496
+ tokens.extend(reversed([t[::-1] for t in tokens]))
497
+ return ''.join(tokens)
498
+
499
+ patt.add_parse_action(make_palindrome)
500
+ print(patt.parse_string("lskdj sdlkjf lksd"))
501
+
502
+ prints:
503
+
504
+ .. testoutput::
505
+
506
+ ['lskdjsdlkjflksddsklfjkldsjdksl']
507
+ """
508
+ if isinstance(itemseq, ParseResults):
509
+ self.__iadd__(itemseq)
510
+ else:
511
+ self._toklist.extend(itemseq)
512
+
513
+ def clear(self):
514
+ """
515
+ Clear all elements and results names.
516
+ """
517
+ del self._toklist[:]
518
+ self._tokdict.clear()
519
+
520
+ def __getattr__(self, name):
521
+ try:
522
+ return self[name]
523
+ except KeyError:
524
+ if name.startswith("__"):
525
+ raise AttributeError(name)
526
+ return ""
527
+
528
+ def __add__(self, other: ParseResults) -> ParseResults:
529
+ ret = self.copy()
530
+ ret += other
531
+ return ret
532
+
533
+ def __iadd__(self, other: ParseResults) -> ParseResults:
534
+ if not other:
535
+ return self
536
+
537
+ if other._tokdict:
538
+ offset = len(self._toklist)
539
+ addoffset = lambda a: offset if a < 0 else a + offset
540
+ otheritems = other._tokdict.items()
541
+ otherdictitems = [
542
+ (k, _ParseResultsWithOffset(v[0], addoffset(v[1])))
543
+ for k, vlist in otheritems
544
+ for v in vlist
545
+ ]
546
+ for k, v in otherdictitems:
547
+ self[k] = v
548
+ if isinstance(v[0], ParseResults):
549
+ v[0]._parent = self
550
+
551
+ self._toklist += other._toklist
552
+ self._all_names |= other._all_names
553
+ return self
554
+
555
+ def __radd__(self, other) -> ParseResults:
556
+ if isinstance(other, int) and other == 0:
557
+ # useful for merging many ParseResults using sum() builtin
558
+ return self.copy()
559
+ else:
560
+ # this may raise a TypeError - so be it
561
+ return other + self
562
+
563
+ def __repr__(self) -> str:
564
+ return f"{type(self).__name__}({self._toklist!r}, {self.as_dict()})"
565
+
566
+ def __str__(self) -> str:
567
+ return (
568
+ "["
569
+ + ", ".join(
570
+ [
571
+ str(i) if isinstance(i, ParseResults) else repr(i)
572
+ for i in self._toklist
573
+ ]
574
+ )
575
+ + "]"
576
+ )
577
+
578
+ def _asStringList(self, sep=""):
579
+ out = []
580
+ for item in self._toklist:
581
+ if out and sep:
582
+ out.append(sep)
583
+ if isinstance(item, ParseResults):
584
+ out += item._asStringList()
585
+ else:
586
+ out.append(str(item))
587
+ return out
588
+
589
+ def as_list(self, *, flatten: bool = False) -> list:
590
+ """
591
+ Returns the parse results as a nested list of matching tokens, all converted to strings.
592
+ If ``flatten`` is True, all the nesting levels in the returned list are collapsed.
593
+
594
+ Example:
595
+
596
+ .. doctest::
597
+
598
+ >>> patt = Word(alphas)[1, ...]
599
+ >>> result = patt.parse_string("sldkj lsdkj sldkj")
600
+ >>> # even though the result prints in string-like form,
601
+ >>> # it is actually a pyparsing ParseResults
602
+ >>> type(result)
603
+ <class 'pyparsing.results.ParseResults'>
604
+ >>> print(result)
605
+ ['sldkj', 'lsdkj', 'sldkj']
606
+
607
+ .. doctest::
608
+
609
+ >>> # Use as_list() to create an actual list
610
+ >>> result_list = result.as_list()
611
+ >>> type(result_list)
612
+ <class 'list'>
613
+ >>> print(result_list)
614
+ ['sldkj', 'lsdkj', 'sldkj']
615
+
616
+ .. versionchanged:: 3.2.0
617
+ New ``flatten`` argument.
618
+ """
619
+
620
+ if flatten:
621
+ return [*_flatten(self)]
622
+ else:
623
+ return [
624
+ res.as_list() if isinstance(res, ParseResults) else res
625
+ for res in self._toklist
626
+ ]
627
+
628
+ def as_dict(self) -> dict:
629
+ """
630
+ Returns the named parse results as a nested dictionary.
631
+
632
+ Example:
633
+
634
+ .. doctest::
635
+
636
+ >>> integer = pp.Word(pp.nums)
637
+ >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
638
+
639
+ >>> result = date_str.parse_string('1999/12/31')
640
+ >>> type(result)
641
+ <class 'pyparsing.results.ParseResults'>
642
+ >>> result
643
+ ParseResults(['1999', '/', '12', '/', '31'], {'year': '1999', 'month': '12', 'day': '31'})
644
+
645
+ >>> result_dict = result.as_dict()
646
+ >>> type(result_dict)
647
+ <class 'dict'>
648
+ >>> result_dict
649
+ {'year': '1999', 'month': '12', 'day': '31'}
650
+
651
+ >>> # even though a ParseResults supports dict-like access,
652
+ >>> # sometime you just need to have a dict
653
+ >>> import json
654
+ >>> print(json.dumps(result))
655
+ Traceback (most recent call last):
656
+ TypeError: Object of type ParseResults is not JSON serializable
657
+ >>> print(json.dumps(result.as_dict()))
658
+ {"year": "1999", "month": "12", "day": "31"}
659
+ """
660
+
661
+ def to_item(obj):
662
+ if isinstance(obj, ParseResults):
663
+ return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj]
664
+ else:
665
+ return obj
666
+
667
+ return dict((k, to_item(v)) for k, v in self.items())
668
+
669
+ def copy(self) -> ParseResults:
670
+ """
671
+ Returns a new shallow copy of a :class:`ParseResults` object.
672
+ :class:`ParseResults` items contained within the source are
673
+ shared with the copy. Use :meth:`ParseResults.deepcopy` to
674
+ create a copy with its own separate content values.
675
+ """
676
+ ret = ParseResults(self._toklist)
677
+ ret._tokdict = self._tokdict.copy()
678
+ ret._parent = self._parent
679
+ ret._all_names |= self._all_names
680
+ ret._name = self._name
681
+ return ret
682
+
683
+ def deepcopy(self) -> ParseResults:
684
+ """
685
+ Returns a new deep copy of a :class:`ParseResults` object.
686
+
687
+ .. versionadded:: 3.1.0
688
+ """
689
+ ret = self.copy()
690
+ # replace values with copies if they are of known mutable types
691
+ for i, obj in enumerate(self._toklist):
692
+ if isinstance(obj, ParseResults):
693
+ ret._toklist[i] = obj.deepcopy()
694
+ elif isinstance(obj, (str, bytes)):
695
+ pass
696
+ elif isinstance(obj, MutableMapping):
697
+ ret._toklist[i] = dest = type(obj)()
698
+ for k, v in obj.items():
699
+ dest[k] = v.deepcopy() if isinstance(v, ParseResults) else v
700
+ elif isinstance(obj, Iterable):
701
+ ret._toklist[i] = type(obj)(
702
+ v.deepcopy() if isinstance(v, ParseResults) else v for v in obj # type: ignore[call-arg]
703
+ )
704
+ return ret
705
+
706
+ def get_name(self) -> str | None:
707
+ r"""
708
+ Returns the results name for this token expression.
709
+
710
+ Useful when several different expressions might match
711
+ at a particular location.
712
+
713
+ Example:
714
+
715
+ .. testcode::
716
+
717
+ integer = Word(nums)
718
+ ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d")
719
+ house_number_expr = Suppress('#') + Word(nums, alphanums)
720
+ user_data = (Group(house_number_expr)("house_number")
721
+ | Group(ssn_expr)("ssn")
722
+ | Group(integer)("age"))
723
+ user_info = user_data[1, ...]
724
+
725
+ result = user_info.parse_string("22 111-22-3333 #221B")
726
+ for item in result:
727
+ print(item.get_name(), ':', item[0])
728
+
729
+ prints:
730
+
731
+ .. testoutput::
732
+
733
+ age : 22
734
+ ssn : 111-22-3333
735
+ house_number : 221B
736
+
737
+ """
738
+ if self._name:
739
+ return self._name
740
+ elif self._parent:
741
+ par: ParseResults = self._parent
742
+ parent_tokdict_items = par._tokdict.items()
743
+ return next(
744
+ (
745
+ k
746
+ for k, vlist in parent_tokdict_items
747
+ for v, loc in vlist
748
+ if v is self
749
+ ),
750
+ None,
751
+ )
752
+ elif (
753
+ len(self) == 1
754
+ and len(self._tokdict) == 1
755
+ and next(iter(self._tokdict.values()))[0][1] in (0, -1)
756
+ ):
757
+ return next(iter(self._tokdict.keys()))
758
+ else:
759
+ return None
760
+
761
+ def dump(self, indent="", full=True, include_list=True, _depth=0) -> str:
762
+ """
763
+ Diagnostic method for listing out the contents of
764
+ a :class:`ParseResults`. Accepts an optional ``indent`` argument so
765
+ that this string can be embedded in a nested display of other data.
766
+
767
+ Example:
768
+
769
+ .. testcode::
770
+
771
+ integer = Word(nums)
772
+ date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
773
+
774
+ result = date_str.parse_string('1999/12/31')
775
+ print(result.dump())
776
+
777
+ prints:
778
+
779
+ .. testoutput::
780
+
781
+ ['1999', '/', '12', '/', '31']
782
+ - day: '31'
783
+ - month: '12'
784
+ - year: '1999'
785
+ """
786
+ out = []
787
+ NL = "\n"
788
+ out.append(indent + str(self.as_list()) if include_list else "")
789
+
790
+ if not full:
791
+ return "".join(out)
792
+
793
+ if self.haskeys():
794
+ items = sorted((str(k), v) for k, v in self.items())
795
+ for k, v in items:
796
+ if out:
797
+ out.append(NL)
798
+ out.append(f"{indent}{(' ' * _depth)}- {k}: ")
799
+ if not isinstance(v, ParseResults):
800
+ out.append(repr(v))
801
+ continue
802
+
803
+ if not v:
804
+ out.append(str(v))
805
+ continue
806
+
807
+ out.append(
808
+ v.dump(
809
+ indent=indent,
810
+ full=full,
811
+ include_list=include_list,
812
+ _depth=_depth + 1,
813
+ )
814
+ )
815
+ if not any(isinstance(vv, ParseResults) for vv in self):
816
+ return "".join(out)
817
+
818
+ v = self
819
+ incr = " "
820
+ nl = "\n"
821
+ for i, vv in enumerate(v):
822
+ if isinstance(vv, ParseResults):
823
+ vv_dump = vv.dump(
824
+ indent=indent,
825
+ full=full,
826
+ include_list=include_list,
827
+ _depth=_depth + 1,
828
+ )
829
+ out.append(
830
+ f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv_dump}"
831
+ )
832
+ else:
833
+ out.append(
834
+ f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv}"
835
+ )
836
+
837
+ return "".join(out)
838
+
839
+ def pprint(self, *args, **kwargs):
840
+ """
841
+ Pretty-printer for parsed results as a list, using the
842
+ `pprint <https://docs.python.org/3/library/pprint.html>`_ module.
843
+ Accepts additional positional or keyword args as defined for
844
+ `pprint.pprint <https://docs.python.org/3/library/pprint.html#pprint.pprint>`_ .
845
+
846
+ Example:
847
+
848
+ .. testcode::
849
+
850
+ ident = Word(alphas, alphanums)
851
+ num = Word(nums)
852
+ func = Forward()
853
+ term = ident | num | Group('(' + func + ')')
854
+ func <<= ident + Group(Optional(DelimitedList(term)))
855
+ result = func.parse_string("fna a,b,(fnb c,d,200),100")
856
+ result.pprint(width=40)
857
+
858
+ prints:
859
+
860
+ .. testoutput::
861
+
862
+ ['fna',
863
+ ['a',
864
+ 'b',
865
+ ['(', 'fnb', ['c', 'd', '200'], ')'],
866
+ '100']]
867
+ """
868
+ pprint.pprint(self.as_list(), *args, **kwargs)
869
+
870
+ # add support for pickle protocol
871
+ def __getstate__(self):
872
+ return (
873
+ self._toklist,
874
+ (
875
+ self._tokdict.copy(),
876
+ None,
877
+ self._all_names,
878
+ self._name,
879
+ ),
880
+ )
881
+
882
+ def __setstate__(self, state):
883
+ self._toklist, (self._tokdict, par, inAccumNames, self._name) = state
884
+ self._all_names = set(inAccumNames)
885
+ self._parent = None
886
+
887
+ def __getnewargs__(self):
888
+ return self._toklist, self._name
889
+
890
+ def __dir__(self):
891
+ return dir(type(self)) + list(self.keys())
892
+
893
+ @classmethod
894
+ def from_dict(cls, other, name=None) -> ParseResults:
895
+ """
896
+ Helper classmethod to construct a :class:`ParseResults` from a ``dict``, preserving the
897
+ name-value relations as results names. If an optional ``name`` argument is
898
+ given, a nested :class:`ParseResults` will be returned.
899
+ """
900
+ ret = cls([])
901
+ for k, v in other.items():
902
+ if isinstance(v, Mapping):
903
+ ret += cls.from_dict(v, name=k)
904
+ else:
905
+ ret += cls([v], name=k, aslist=_is_iterable(v))
906
+ if name is not None:
907
+ ret = cls([ret], name=name)
908
+ return ret
909
+
910
+ asList = as_list
911
+ """
912
+ .. deprecated:: 3.0.0
913
+ use :meth:`as_list`
914
+ """
915
+ asDict = as_dict
916
+ """
917
+ .. deprecated:: 3.0.0
918
+ use :meth:`as_dict`
919
+ """
920
+ getName = get_name
921
+ """
922
+ .. deprecated:: 3.0.0
923
+ use :meth:`get_name`
924
+ """
925
+
926
+
927
+ MutableMapping.register(ParseResults)
928
+ MutableSequence.register(ParseResults)