Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pyparsing/results.py: 49%

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

306 statements  

1# results.py 

2 

3from __future__ import annotations 

4 

5import collections 

6from collections.abc import ( 

7 MutableMapping, 

8 Mapping, 

9 MutableSequence, 

10 Iterator, 

11 Iterable, 

12) 

13import pprint 

14from typing import Any, NamedTuple 

15 

16from .util import deprecate_argument, _is_iterable, _flatten 

17 

18 

19str_type: tuple[type, ...] = (str, bytes) 

20_generator_type = type((_ for _ in ())) 

21NULL_SLICE: slice = slice(None) 

22 

23 

24class _ParseResultsWithOffset(NamedTuple): 

25 result: ParseResults 

26 offset: int 

27 

28 

29class ParseResults: 

30 """Structured parse results, to provide multiple means of access to 

31 the parsed data: 

32 

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`) 

36 

37 Example: 

38 

39 .. testcode:: 

40 

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")) 

49 

50 # parse_string returns a ParseResults object 

51 result = date_str.parse_string("1999/12/31") 

52 

53 def test(s, fn=repr): 

54 print(f"{s} -> {fn(eval(s))}") 

55 

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) 

63 

64 prints: 

65 

66 .. testoutput:: 

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 

81 _null_values: tuple[Any, ...] = (None, [], ()) 

82 

83 _name: str 

84 _parent: ParseResults 

85 _all_names: set[str] 

86 _modal: bool 

87 _toklist: list[Any] 

88 _tokdict: dict[str, Any] 

89 

90 __slots__ = ( 

91 "_name", 

92 "_parent", 

93 "_all_names", 

94 "_modal", 

95 "_toklist", 

96 "_tokdict", 

97 ) 

98 

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`: 

103 

104 .. testcode:: 

105 

106 import pyparsing as pp 

107 ppc = pp.common 

108 

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 

115 

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()) 

121 

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 ) 

131 

132 prints: 

133 

134 .. testoutput:: 

135 :options: +NORMALIZE_WHITESPACE 

136 

137 

138 100 

139 (100, <class 'int'>) 

140 

141 [2,3,4] 

142 ([2, 3, 4], <class 'list'>) 

143 

144 [[2, 1],3,4] 

145 ([[2, 1], 3, 4], <class 'list'>) 

146 

147 [(2, 1),3,4] 

148 ([[2, 1], 3, 4], <class 'list'>) 

149 

150 (2,3,4) 

151 ([2, 3, 4], <class 'list'>) 

152 

153 ([2, 3], 4) 

154 ([[2, 3], 4], <class 'list'>) 

155 

156 (Used internally by :class:`Group` when `aslist=True`.) 

157 """ 

158 

159 def __new__(cls, contained=None): 

160 if contained is None: 

161 contained = [] 

162 

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 ) 

167 

168 return list.__new__(cls) 

169 

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 

178 if toklist is None: 

179 self._toklist = [] 

180 elif isinstance(toklist, (list, _generator_type)): 

181 self._toklist = ( 

182 [toklist[:]] 

183 if isinstance(toklist, ParseResults.List) 

184 else list(toklist) 

185 ) 

186 else: 

187 self._toklist = [toklist] 

188 self._tokdict = dict() 

189 return self 

190 

191 # Performance tuning: we construct a *lot* of these, so keep this 

192 # constructor as small and fast as possible 

193 def __init__( 

194 self, 

195 toklist=None, 

196 name=None, 

197 aslist=True, 

198 modal=True, 

199 isinstance=isinstance, 

200 **kwargs, 

201 ) -> None: 

202 asList = deprecate_argument(kwargs, "asList", True, new_name="aslist") 

203 

204 asList = asList and aslist 

205 self._tokdict: dict[str, _ParseResultsWithOffset] 

206 self._modal = modal 

207 

208 if name is None or name == "": 

209 return 

210 

211 if isinstance(name, int): 

212 name = str(name) 

213 

214 if not modal: 

215 self._all_names = {name} 

216 

217 self._name = name 

218 

219 if toklist in self._null_values: 

220 return 

221 

222 if isinstance(toklist, (str_type, type)): 

223 toklist = [toklist] 

224 

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 

232 

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 

240 

241 def __getitem__(self, i): 

242 if isinstance(i, (int, slice)): 

243 return self._toklist[i] 

244 

245 if i not in self._all_names: 

246 return self._tokdict[i][-1].result 

247 

248 return ParseResults([v.result for v in self._tokdict[i]]) 

249 

250 def __setitem__(self, k, v, isinstance=isinstance): 

251 if isinstance(v, _ParseResultsWithOffset): 

252 self._tokdict[k] = self._tokdict.get(k, list()) + [v] 

253 sub = v.result 

254 elif isinstance(k, (int, slice)): 

255 self._toklist[k] = v 

256 sub = v 

257 else: 

258 self._tokdict[k] = self._tokdict.get(k, []) + [ 

259 _ParseResultsWithOffset(v, 0) 

260 ] 

261 sub = v 

262 if isinstance(sub, ParseResults): 

263 sub._parent = self 

264 

265 def __delitem__(self, i): 

266 if not isinstance(i, (int, slice)): 

267 del self._tokdict[i] 

268 return 

269 

270 # slight optimization if del results[:] 

271 if i == NULL_SLICE: 

272 self._toklist.clear() 

273 return 

274 

275 mylen = len(self._toklist) 

276 del self._toklist[i] 

277 

278 # convert int to slice 

279 if isinstance(i, int): 

280 if i < 0: 

281 i += mylen 

282 i = slice(i, i + 1) 

283 # get removed indices 

284 removed = list(range(*i.indices(mylen))) 

285 removed.reverse() 

286 # fixup indices in token dictionary 

287 for occurrences in self._tokdict.values(): 

288 for j in removed: 

289 for k, (value, position) in enumerate(occurrences): 

290 if position > j: 

291 occurrences[k] = _ParseResultsWithOffset(value, position - 1) 

292 

293 def __contains__(self, k) -> bool: 

294 return k in self._tokdict 

295 

296 def __len__(self) -> int: 

297 return len(self._toklist) 

298 

299 def __bool__(self) -> bool: 

300 return not not (self._toklist or self._tokdict) 

301 

302 def __iter__(self) -> Iterator: 

303 return iter(self._toklist) 

304 

305 def __reversed__(self) -> Iterator: 

306 return iter(self._toklist[::-1]) 

307 

308 def keys(self): 

309 return iter(self._tokdict) 

310 

311 def values(self): 

312 return (self[k] for k in self.keys()) 

313 

314 def items(self): 

315 return ((k, self[k]) for k in self.keys()) 

316 

317 def haskeys(self) -> bool: 

318 """ 

319 Since ``keys()`` returns an iterator, this method is helpful in bypassing 

320 code that looks for the existence of any defined results names.""" 

321 return not not self._tokdict 

322 

323 def pop(self, *args, **kwargs): 

324 """ 

325 Removes and returns item at specified index (default= ``last``). 

326 Supports both ``list`` and ``dict`` semantics for ``pop()``. If 

327 passed no argument or an integer argument, it will use ``list`` 

328 semantics and pop tokens from the list of parsed tokens. If passed 

329 a non-integer argument (most likely a string), it will use ``dict`` 

330 semantics and pop the corresponding value from any defined results 

331 names. A second default return value argument is supported, just as in 

332 ``dict.pop()``. 

333 

334 Example: 

335 

336 .. doctest:: 

337 

338 >>> numlist = Word(nums)[...] 

339 >>> print(numlist.parse_string("0 123 321")) 

340 ['0', '123', '321'] 

341 

342 >>> def remove_first(tokens): 

343 ... tokens.pop(0) 

344 ... 

345 >>> numlist.add_parse_action(remove_first) 

346 [W:(0-9)]... 

347 >>> print(numlist.parse_string("0 123 321")) 

348 ['123', '321'] 

349 

350 >>> label = Word(alphas) 

351 >>> patt = label("LABEL") + Word(nums)[1, ...] 

352 >>> print(patt.parse_string("AAB 123 321").dump()) 

353 ['AAB', '123', '321'] 

354 - LABEL: 'AAB' 

355 

356 >>> # Use pop() in a parse action to remove named result 

357 >>> # (note that corresponding value is not 

358 >>> # removed from list form of results) 

359 >>> def remove_LABEL(tokens): 

360 ... tokens.pop("LABEL") 

361 ... return tokens 

362 ... 

363 >>> patt.add_parse_action(remove_LABEL) 

364 {W:(A-Za-z) {W:(0-9)}...} 

365 >>> print(patt.parse_string("AAB 123 321").dump()) 

366 ['AAB', '123', '321'] 

367 

368 """ 

369 if not args: 

370 args = [-1] 

371 for k, v in kwargs.items(): 

372 if k == "default": 

373 args = (args[0], v) 

374 else: 

375 raise TypeError(f"pop() got an unexpected keyword argument {k!r}") 

376 if isinstance(args[0], int) or len(args) == 1 or args[0] in self: 

377 index = args[0] 

378 ret = self[index] 

379 del self[index] 

380 return ret 

381 else: 

382 defaultvalue = args[1] 

383 return defaultvalue 

384 

385 def get(self, key, default_value=None): 

386 """ 

387 Returns named result matching the given key, or if there is no 

388 such name, then returns the given ``default_value`` or ``None`` if no 

389 ``default_value`` is specified. 

390 

391 Similar to ``dict.get()``. 

392 

393 Example: 

394 

395 .. doctest:: 

396 

397 >>> integer = Word(nums) 

398 >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

399 

400 >>> result = date_str.parse_string("1999/12/31") 

401 >>> result.get("year") 

402 '1999' 

403 >>> result.get("hour", "not specified") 

404 'not specified' 

405 >>> result.get("hour") 

406 

407 """ 

408 if key in self: 

409 return self[key] 

410 else: 

411 return default_value 

412 

413 def insert(self, index, ins_string): 

414 """ 

415 Inserts new element at location index in the list of parsed tokens. 

416 

417 Similar to ``list.insert()``. 

418 

419 Example: 

420 

421 .. doctest:: 

422 

423 >>> numlist = Word(nums)[...] 

424 >>> print(numlist.parse_string("0 123 321")) 

425 ['0', '123', '321'] 

426 

427 >>> # use a parse action to insert the parse location 

428 >>> # in the front of the parsed results 

429 >>> def insert_locn(locn, tokens): 

430 ... tokens.insert(0, locn) 

431 ... 

432 >>> numlist.add_parse_action(insert_locn) 

433 [W:(0-9)]... 

434 >>> print(numlist.parse_string("0 123 321")) 

435 [0, '0', '123', '321'] 

436 

437 """ 

438 self._toklist.insert(index, ins_string) 

439 # fixup indices in token dictionary 

440 for occurrences in self._tokdict.values(): 

441 for k, (value, position) in enumerate(occurrences): 

442 if position > index: 

443 occurrences[k] = _ParseResultsWithOffset(value, position + 1) 

444 

445 def append(self, item): 

446 """ 

447 Add single element to end of ``ParseResults`` list of elements. 

448 

449 Example: 

450 

451 .. doctest:: 

452 

453 >>> numlist = Word(nums)[...] 

454 >>> print(numlist.parse_string("0 123 321")) 

455 ['0', '123', '321'] 

456 

457 >>> # use a parse action to compute the sum of the parsed integers, 

458 >>> # and add it to the end 

459 >>> def append_sum(tokens): 

460 ... tokens.append(sum(map(int, tokens))) 

461 ... 

462 >>> numlist.add_parse_action(append_sum) 

463 [W:(0-9)]... 

464 >>> print(numlist.parse_string("0 123 321")) 

465 ['0', '123', '321', 444] 

466 """ 

467 self._toklist.append(item) 

468 

469 def extend(self, itemseq): 

470 """ 

471 Add sequence of elements to end of :class:`ParseResults` list of elements. 

472 

473 Example: 

474 

475 .. testcode:: 

476 

477 patt = Word(alphas)[1, ...] 

478 

479 # use a parse action to append the reverse of the matched strings, 

480 # to make a palindrome 

481 def make_palindrome(tokens): 

482 tokens.extend(reversed([t[::-1] for t in tokens])) 

483 return ''.join(tokens) 

484 

485 patt.add_parse_action(make_palindrome) 

486 print(patt.parse_string("lskdj sdlkjf lksd")) 

487 

488 prints: 

489 

490 .. testoutput:: 

491 

492 ['lskdjsdlkjflksddsklfjkldsjdksl'] 

493 """ 

494 if isinstance(itemseq, ParseResults): 

495 self.__iadd__(itemseq) 

496 else: 

497 self._toklist.extend(itemseq) 

498 

499 def clear(self): 

500 """ 

501 Clear all elements and results names. 

502 """ 

503 del self._toklist[:] 

504 self._tokdict.clear() 

505 

506 def __getattr__(self, name): 

507 try: 

508 return self[name] 

509 except KeyError: 

510 if name.startswith("__"): 

511 raise AttributeError(name) 

512 return "" 

513 

514 def __add__(self, other: ParseResults) -> ParseResults: 

515 ret = self.copy() 

516 ret += other 

517 return ret 

518 

519 def __iadd__(self, other: ParseResults) -> ParseResults: 

520 if not other: 

521 return self 

522 

523 if other._tokdict: 

524 offset = len(self._toklist) 

525 # addoffset = lambda a: offset if a < 0 else a + offset 

526 otheritems = other._tokdict.items() 

527 otherdictitems = [ 

528 # (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) 

529 ( 

530 k, 

531 _ParseResultsWithOffset( 

532 v.result, 

533 # addoffset(v[1]) 

534 (offset if v.offset < 0 else v.offset + offset), 

535 ), 

536 ) 

537 for k, vlist in otheritems 

538 for v in vlist 

539 ] 

540 for k, v in otherdictitems: 

541 self[k] = v 

542 if isinstance(v.result, ParseResults): 

543 v.result._parent = self 

544 

545 self._toklist += other._toklist 

546 self._all_names |= other._all_names 

547 return self 

548 

549 def __radd__(self, other) -> ParseResults: 

550 if isinstance(other, int) and other == 0: 

551 # useful for merging many ParseResults using sum() builtin 

552 return self.copy() 

553 else: 

554 # this may raise a TypeError - so be it 

555 return other + self 

556 

557 def __repr__(self) -> str: 

558 return f"{type(self).__name__}({self._toklist!r}, {self.as_dict()})" 

559 

560 def __str__(self) -> str: 

561 return ( 

562 "[" 

563 + ", ".join( 

564 [ 

565 str(i) if isinstance(i, ParseResults) else repr(i) 

566 for i in self._toklist 

567 ] 

568 ) 

569 + "]" 

570 ) 

571 

572 def _asStringList(self, sep=""): 

573 out = [] 

574 for item in self._toklist: 

575 if out and sep: 

576 out.append(sep) 

577 if isinstance(item, ParseResults): 

578 out += item._asStringList() 

579 else: 

580 out.append(str(item)) 

581 return out 

582 

583 def as_list(self, *, flatten: bool = False) -> list: 

584 """ 

585 Returns the parse results as a nested list of matching tokens, all converted to strings. 

586 If ``flatten`` is True, all the nesting levels in the returned list are collapsed. 

587 

588 Example: 

589 

590 .. doctest:: 

591 

592 >>> patt = Word(alphas)[1, ...] 

593 >>> result = patt.parse_string("sldkj lsdkj sldkj") 

594 >>> # even though the result prints in string-like form, 

595 >>> # it is actually a pyparsing ParseResults 

596 >>> type(result) 

597 <class 'pyparsing.results.ParseResults'> 

598 >>> print(result) 

599 ['sldkj', 'lsdkj', 'sldkj'] 

600 

601 .. doctest:: 

602 

603 >>> # Use as_list() to create an actual list 

604 >>> result_list = result.as_list() 

605 >>> type(result_list) 

606 <class 'list'> 

607 >>> print(result_list) 

608 ['sldkj', 'lsdkj', 'sldkj'] 

609 

610 .. versionchanged:: 3.2.0 

611 New ``flatten`` argument. 

612 """ 

613 

614 if flatten: 

615 return [*_flatten(self)] 

616 else: 

617 return [ 

618 res.as_list() if isinstance(res, ParseResults) else res 

619 for res in self._toklist 

620 ] 

621 

622 def as_dict(self) -> dict: 

623 """ 

624 Returns the named parse results as a nested dictionary. 

625 

626 Example: 

627 

628 .. doctest:: 

629 

630 >>> integer = pp.Word(pp.nums) 

631 >>> date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

632 

633 >>> result = date_str.parse_string('1999/12/31') 

634 >>> type(result) 

635 <class 'pyparsing.results.ParseResults'> 

636 >>> result 

637 ParseResults(['1999', '/', '12', '/', '31'], {'year': '1999', 'month': '12', 'day': '31'}) 

638 

639 >>> result_dict = result.as_dict() 

640 >>> type(result_dict) 

641 <class 'dict'> 

642 >>> result_dict 

643 {'year': '1999', 'month': '12', 'day': '31'} 

644 

645 >>> # even though a ParseResults supports dict-like access, 

646 >>> # sometime you just need to have a dict 

647 >>> import json 

648 >>> print(json.dumps(result)) 

649 Traceback (most recent call last): 

650 TypeError: Object of type ParseResults is not JSON serializable 

651 >>> print(json.dumps(result.as_dict())) 

652 {"year": "1999", "month": "12", "day": "31"} 

653 """ 

654 

655 def to_item(obj): 

656 if isinstance(obj, ParseResults): 

657 return obj.as_dict() if obj.haskeys() else [to_item(v) for v in obj] 

658 else: 

659 return obj 

660 

661 return dict((k, to_item(v)) for k, v in self.items()) 

662 

663 def copy(self) -> ParseResults: 

664 """ 

665 Returns a new shallow copy of a :class:`ParseResults` object. 

666 :class:`ParseResults` items contained within the source are 

667 shared with the copy. Use :meth:`ParseResults.deepcopy` to 

668 create a copy with its own separate content values. 

669 """ 

670 ret: ParseResults = object.__new__(ParseResults) 

671 ret._toklist = self._toklist[:] 

672 ret._tokdict = {**self._tokdict} 

673 ret._parent = self._parent 

674 ret._all_names = {*self._all_names} 

675 ret._name = self._name 

676 ret._modal = self._modal 

677 return ret 

678 

679 def deepcopy(self) -> ParseResults: 

680 """ 

681 Returns a new deep copy of a :class:`ParseResults` object. 

682 

683 .. versionadded:: 3.1.0 

684 """ 

685 ret = self.copy() 

686 # replace values with copies if they are of known mutable types 

687 for i, obj in enumerate(self._toklist): 

688 if isinstance(obj, ParseResults): 

689 ret._toklist[i] = obj.deepcopy() 

690 elif isinstance(obj, (str, bytes)): 

691 pass 

692 elif isinstance(obj, MutableMapping): 

693 ret._toklist[i] = dest = type(obj)() 

694 for k, v in obj.items(): 

695 dest[k] = v.deepcopy() if isinstance(v, ParseResults) else v 

696 elif isinstance(obj, Iterable): 

697 ret._toklist[i] = type(obj)( 

698 v.deepcopy() if isinstance(v, ParseResults) else v for v in obj # type: ignore[call-arg] 

699 ) 

700 return ret 

701 

702 def get_name(self) -> str | None: 

703 r""" 

704 Returns the results name for this token expression. 

705 

706 Useful when several different expressions might match 

707 at a particular location. 

708 

709 Example: 

710 

711 .. testcode:: 

712 

713 integer = Word(nums) 

714 ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") 

715 house_number_expr = Suppress('#') + Word(nums, alphanums) 

716 user_data = (Group(house_number_expr)("house_number") 

717 | Group(ssn_expr)("ssn") 

718 | Group(integer)("age")) 

719 user_info = user_data[1, ...] 

720 

721 result = user_info.parse_string("22 111-22-3333 #221B") 

722 for item in result: 

723 print(item.get_name(), ':', item[0]) 

724 

725 prints: 

726 

727 .. testoutput:: 

728 

729 age : 22 

730 ssn : 111-22-3333 

731 house_number : 221B 

732 

733 """ 

734 if self._name: 

735 return self._name 

736 elif self._parent: 

737 par: ParseResults = self._parent 

738 parent_tokdict_items = par._tokdict.items() 

739 return next( 

740 ( 

741 k 

742 for k, vlist in parent_tokdict_items 

743 for v, loc in vlist 

744 if v is self 

745 ), 

746 None, 

747 ) 

748 elif len(self) == 1 and len(self._tokdict) == 1: 

749 first_name, first_pr_offset = next(iter(self._tokdict.items())) 

750 if first_pr_offset[0].offset <= 0: 

751 return first_name 

752 

753 return None 

754 

755 def dump(self, indent="", full=True, include_list=True, _depth=0) -> str: 

756 """ 

757 Diagnostic method for listing out the contents of 

758 a :class:`ParseResults`. Accepts an optional ``indent`` argument so 

759 that this string can be embedded in a nested display of other data. 

760 

761 Example: 

762 

763 .. testcode:: 

764 

765 integer = Word(nums) 

766 date_str = integer("year") + '/' + integer("month") + '/' + integer("day") 

767 

768 result = date_str.parse_string('1999/12/31') 

769 print(result.dump()) 

770 

771 prints: 

772 

773 .. testoutput:: 

774 

775 ['1999', '/', '12', '/', '31'] 

776 - day: '31' 

777 - month: '12' 

778 - year: '1999' 

779 """ 

780 out = [] 

781 NL = "\n" 

782 out.append(indent + str(self.as_list()) if include_list else "") 

783 

784 if not full: 

785 return "".join(out) 

786 

787 if self.haskeys(): 

788 items = sorted((str(k), v) for k, v in self.items()) 

789 for k, v in items: 

790 if out: 

791 out.append(NL) 

792 out.append(f"{indent}{(' ' * _depth)}- {k}: ") 

793 if not isinstance(v, ParseResults): 

794 out.append(repr(v)) 

795 continue 

796 

797 if not v: 

798 out.append(str(v)) 

799 continue 

800 

801 out.append( 

802 v.dump( 

803 indent=indent, 

804 full=full, 

805 include_list=include_list, 

806 _depth=_depth + 1, 

807 ) 

808 ) 

809 if not any(isinstance(vv, ParseResults) for vv in self): 

810 return "".join(out) 

811 

812 v = self 

813 incr = " " 

814 nl = "\n" 

815 for i, vv in enumerate(v): 

816 if isinstance(vv, ParseResults): 

817 vv_dump = vv.dump( 

818 indent=indent, 

819 full=full, 

820 include_list=include_list, 

821 _depth=_depth + 1, 

822 ) 

823 out.append( 

824 f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv_dump}" 

825 ) 

826 else: 

827 out.append( 

828 f"{nl}{indent}{incr * _depth}[{i}]:{nl}{indent}{incr * (_depth + 1)}{vv}" 

829 ) 

830 

831 return "".join(out) 

832 

833 def pprint(self, *args, **kwargs): 

834 """ 

835 Pretty-printer for parsed results as a list, using the 

836 `pprint <https://docs.python.org/3/library/pprint.html>`_ module. 

837 Accepts additional positional or keyword args as defined for 

838 `pprint.pprint <https://docs.python.org/3/library/pprint.html#pprint.pprint>`_ . 

839 

840 Example: 

841 

842 .. testcode:: 

843 

844 ident = Word(alphas, alphanums) 

845 num = Word(nums) 

846 func = Forward() 

847 term = ident | num | Group('(' + func + ')') 

848 func <<= ident + Group(Optional(DelimitedList(term))) 

849 result = func.parse_string("fna a,b,(fnb c,d,200),100") 

850 result.pprint(width=40) 

851 

852 prints: 

853 

854 .. testoutput:: 

855 

856 ['fna', 

857 ['a', 

858 'b', 

859 ['(', 'fnb', ['c', 'd', '200'], ')'], 

860 '100']] 

861 """ 

862 pprint.pprint(self.as_list(), *args, **kwargs) 

863 

864 # add support for pickle protocol 

865 def __getstate__(self): 

866 return ( 

867 self._toklist, 

868 ( 

869 self._tokdict.copy(), 

870 None, 

871 self._all_names, 

872 self._name, 

873 ), 

874 ) 

875 

876 def __setstate__(self, state): 

877 self._toklist, (self._tokdict, par, inAccumNames, self._name) = state 

878 self._all_names = set(inAccumNames) 

879 self._parent = None 

880 

881 def __getnewargs__(self): 

882 return self._toklist, self._name 

883 

884 def __dir__(self): 

885 return dir(type(self)) + list(self.keys()) 

886 

887 @classmethod 

888 def from_dict(cls, other, name=None) -> ParseResults: 

889 """ 

890 Helper classmethod to construct a :class:`ParseResults` from a ``dict``, preserving the 

891 name-value relations as results names. If an optional ``name`` argument is 

892 given, a nested :class:`ParseResults` will be returned. 

893 """ 

894 ret = cls([]) 

895 for k, v in other.items(): 

896 if isinstance(v, Mapping): 

897 ret += cls.from_dict(v, name=k) 

898 else: 

899 ret += cls([v], name=k, aslist=_is_iterable(v)) 

900 if name is not None: 

901 ret = cls([ret], name=name) 

902 return ret 

903 

904 asList = as_list 

905 """ 

906 .. deprecated:: 3.0.0 

907 use :meth:`as_list` 

908 """ 

909 asDict = as_dict 

910 """ 

911 .. deprecated:: 3.0.0 

912 use :meth:`as_dict` 

913 """ 

914 getName = get_name 

915 """ 

916 .. deprecated:: 3.0.0 

917 use :meth:`get_name` 

918 """ 

919 

920 

921MutableMapping.register(ParseResults) 

922MutableSequence.register(ParseResults)