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

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

309 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 

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: 

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 

41class 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 

927MutableMapping.register(ParseResults) 

928MutableSequence.register(ParseResults)