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