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