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

310 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 __slots__ = ["tup"] 

26 

27 def __init__(self, p1: ParseResults, p2: int) -> None: 

28 self.tup: tuple[ParseResults, int] = (p1, p2) 

29 

30 def __getitem__(self, i): 

31 return self.tup[i] 

32 

33 def __getstate__(self): 

34 return self.tup 

35 

36 def __setstate__(self, state): 

37 self.tup = state 

38 

39 

40class ParseResults: 

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

42 the parsed data: 

43 

44 - as a list (``len(results)``) 

45 - by list index (``results[0], results[1]``, etc.) 

46 - by attribute (``results.<results_name>`` - see :class:`ParserElement.set_results_name`) 

47 

48 Example: 

49 

50 .. testcode:: 

51 

52 integer = Word(nums) 

53 date_str = (integer.set_results_name("year") + '/' 

54 + integer.set_results_name("month") + '/' 

55 + integer.set_results_name("day")) 

56 # equivalent form: 

57 # date_str = (integer("year") + '/' 

58 # + integer("month") + '/' 

59 # + integer("day")) 

60 

61 # parse_string returns a ParseResults object 

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

63 

64 def test(s, fn=repr): 

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

66 

67 test("list(result)") 

68 test("result[0]") 

69 test("result['month']") 

70 test("result.day") 

71 test("'month' in result") 

72 test("'minutes' in result") 

73 test("result.dump()", str) 

74 

75 prints: 

76 

77 .. testoutput:: 

78 

79 list(result) -> ['1999', '/', '12', '/', '31'] 

80 result[0] -> '1999' 

81 result['month'] -> '12' 

82 result.day -> '31' 

83 'month' in result -> True 

84 'minutes' in result -> False 

85 result.dump() -> ['1999', '/', '12', '/', '31'] 

86 - day: '31' 

87 - month: '12' 

88 - year: '1999' 

89 

90 """ 

91 

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

93 

94 _name: str 

95 _parent: ParseResults 

96 _all_names: set[str] 

97 _modal: bool 

98 _toklist: list[Any] 

99 _tokdict: dict[str, Any] 

100 

101 __slots__ = ( 

102 "_name", 

103 "_parent", 

104 "_all_names", 

105 "_modal", 

106 "_toklist", 

107 "_tokdict", 

108 ) 

109 

110 class List(list): 

111 """ 

112 Simple wrapper class to distinguish parsed list results that should be preserved 

113 as actual Python lists, instead of being converted to :class:`ParseResults`: 

114 

115 .. testcode:: 

116 

117 import pyparsing as pp 

118 ppc = pp.common 

119 

120 LBRACK, RBRACK, LPAR, RPAR = pp.Suppress.using_each("[]()") 

121 element = pp.Forward() 

122 item = ppc.integer 

123 item_list = pp.DelimitedList(element) 

124 element_list = LBRACK + item_list + RBRACK | LPAR + item_list + RPAR 

125 element <<= item | element_list 

126 

127 # add parse action to convert from ParseResults 

128 # to actual Python collection types 

129 @element_list.add_parse_action 

130 def as_python_list(t): 

131 return pp.ParseResults.List(t.as_list()) 

132 

133 element.run_tests(''' 

134 100 

135 [2,3,4] 

136 [[2, 1],3,4] 

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

138 (2,3,4) 

139 ([2, 3], 4) 

140 ''', post_parse=lambda s, r: (r[0], type(r[0])) 

141 ) 

142 

143 prints: 

144 

145 .. testoutput:: 

146 :options: +NORMALIZE_WHITESPACE 

147 

148 

149 100 

150 (100, <class 'int'>) 

151 

152 [2,3,4] 

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

154 

155 [[2, 1],3,4] 

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

157 

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

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

160 

161 (2,3,4) 

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

163 

164 ([2, 3], 4) 

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

166 

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

168 """ 

169 

170 def __new__(cls, contained=None): 

171 if contained is None: 

172 contained = [] 

173 

174 if not isinstance(contained, list): 

175 raise TypeError( 

176 f"{cls.__name__} may only be constructed with a list, not {type(contained).__name__}" 

177 ) 

178 

179 return list.__new__(cls) 

180 

181 def __new__(cls, toklist=None, name=None, **kwargs): 

182 if isinstance(toklist, ParseResults): 

183 return toklist 

184 self = object.__new__(cls) 

185 self._name = None 

186 self._parent = None 

187 self._all_names = set() 

188 

189 if toklist is None: 

190 self._toklist = [] 

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

192 self._toklist = ( 

193 [toklist[:]] 

194 if isinstance(toklist, ParseResults.List) 

195 else list(toklist) 

196 ) 

197 else: 

198 self._toklist = [toklist] 

199 self._tokdict = dict() 

200 return self 

201 

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

203 # constructor as small and fast as possible 

204 def __init__( 

205 self, 

206 toklist=None, 

207 name=None, 

208 aslist=True, 

209 modal=True, 

210 isinstance=isinstance, 

211 **kwargs, 

212 ) -> None: 

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

214 

215 asList = asList and aslist 

216 self._tokdict: dict[str, _ParseResultsWithOffset] 

217 self._modal = modal 

218 

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

220 return 

221 

222 if isinstance(name, int): 

223 name = str(name) 

224 

225 if not modal: 

226 self._all_names = {name} 

227 

228 self._name = name 

229 

230 if toklist in self._null_values: 

231 return 

232 

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

234 toklist = [toklist] 

235 

236 if asList: 

237 if isinstance(toklist, ParseResults): 

238 self[name] = _ParseResultsWithOffset(ParseResults(toklist._toklist), 0) 

239 else: 

240 self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]), 0) 

241 self[name]._name = name 

242 return 

243 

244 try: 

245 self[name] = toklist[0] 

246 except (KeyError, TypeError, IndexError): 

247 if toklist is not self: 

248 self[name] = toklist 

249 else: 

250 self._name = name 

251 

252 def __getitem__(self, i): 

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

254 return self._toklist[i] 

255 

256 if i not in self._all_names: 

257 return self._tokdict[i][-1][0] 

258 

259 return ParseResults([v[0] for v in self._tokdict[i]]) 

260 

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

262 if isinstance(v, _ParseResultsWithOffset): 

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

264 sub = v[0] 

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

266 self._toklist[k] = v 

267 sub = v 

268 else: 

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

270 _ParseResultsWithOffset(v, 0) 

271 ] 

272 sub = v 

273 if isinstance(sub, ParseResults): 

274 sub._parent = self 

275 

276 def __delitem__(self, i): 

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

278 del self._tokdict[i] 

279 return 

280 

281 # slight optimization if del results[:] 

282 if i == NULL_SLICE: 

283 self._toklist.clear() 

284 return 

285 

286 mylen = len(self._toklist) 

287 del self._toklist[i] 

288 

289 # convert int to slice 

290 if isinstance(i, int): 

291 if i < 0: 

292 i += mylen 

293 i = slice(i, i + 1) 

294 # get removed indices 

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

296 removed.reverse() 

297 # fixup indices in token dictionary 

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

299 for j in removed: 

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

301 occurrences[k] = _ParseResultsWithOffset( 

302 value, position - (position > j) 

303 ) 

304 

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

306 return k in self._tokdict 

307 

308 def __len__(self) -> int: 

309 return len(self._toklist) 

310 

311 def __bool__(self) -> bool: 

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

313 

314 def __iter__(self) -> Iterator: 

315 return iter(self._toklist) 

316 

317 def __reversed__(self) -> Iterator: 

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

319 

320 def keys(self): 

321 return iter(self._tokdict) 

322 

323 def values(self): 

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

325 

326 def items(self): 

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

328 

329 def haskeys(self) -> bool: 

330 """ 

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

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

333 return not not self._tokdict 

334 

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

336 """ 

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

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

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

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

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

342 semantics and pop the corresponding value from any defined results 

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

344 ``dict.pop()``. 

345 

346 Example: 

347 

348 .. doctest:: 

349 

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

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

352 ['0', '123', '321'] 

353 

354 >>> def remove_first(tokens): 

355 ... tokens.pop(0) 

356 ... 

357 >>> numlist.add_parse_action(remove_first) 

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

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

360 ['123', '321'] 

361 

362 >>> label = Word(alphas) 

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

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

365 ['AAB', '123', '321'] 

366 - LABEL: 'AAB' 

367 

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

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

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

371 >>> def remove_LABEL(tokens): 

372 ... tokens.pop("LABEL") 

373 ... return tokens 

374 ... 

375 >>> patt.add_parse_action(remove_LABEL) 

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

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

378 ['AAB', '123', '321'] 

379 

380 """ 

381 if not args: 

382 args = [-1] 

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

384 if k == "default": 

385 args = (args[0], v) 

386 else: 

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

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

389 index = args[0] 

390 ret = self[index] 

391 del self[index] 

392 return ret 

393 else: 

394 defaultvalue = args[1] 

395 return defaultvalue 

396 

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

398 """ 

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

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

401 ``default_value`` is specified. 

402 

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

404 

405 Example: 

406 

407 .. doctest:: 

408 

409 >>> integer = Word(nums) 

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

411 

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

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

414 '1999' 

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

416 'not specified' 

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

418 

419 """ 

420 if key in self: 

421 return self[key] 

422 else: 

423 return default_value 

424 

425 def insert(self, index, ins_string): 

426 """ 

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

428 

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

430 

431 Example: 

432 

433 .. doctest:: 

434 

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

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

437 ['0', '123', '321'] 

438 

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

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

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

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

443 ... 

444 >>> numlist.add_parse_action(insert_locn) 

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

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

447 [0, '0', '123', '321'] 

448 

449 """ 

450 self._toklist.insert(index, ins_string) 

451 # fixup indices in token dictionary 

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

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

454 occurrences[k] = _ParseResultsWithOffset( 

455 value, position + (position > index) 

456 ) 

457 

458 def append(self, item): 

459 """ 

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

461 

462 Example: 

463 

464 .. doctest:: 

465 

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

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

468 ['0', '123', '321'] 

469 

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

471 >>> # and add it to the end 

472 >>> def append_sum(tokens): 

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

474 ... 

475 >>> numlist.add_parse_action(append_sum) 

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

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

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

479 """ 

480 self._toklist.append(item) 

481 

482 def extend(self, itemseq): 

483 """ 

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

485 

486 Example: 

487 

488 .. testcode:: 

489 

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

491 

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

493 # to make a palindrome 

494 def make_palindrome(tokens): 

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

496 return ''.join(tokens) 

497 

498 patt.add_parse_action(make_palindrome) 

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

500 

501 prints: 

502 

503 .. testoutput:: 

504 

505 ['lskdjsdlkjflksddsklfjkldsjdksl'] 

506 """ 

507 if isinstance(itemseq, ParseResults): 

508 self.__iadd__(itemseq) 

509 else: 

510 self._toklist.extend(itemseq) 

511 

512 def clear(self): 

513 """ 

514 Clear all elements and results names. 

515 """ 

516 del self._toklist[:] 

517 self._tokdict.clear() 

518 

519 def __getattr__(self, name): 

520 try: 

521 return self[name] 

522 except KeyError: 

523 if name.startswith("__"): 

524 raise AttributeError(name) 

525 return "" 

526 

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

528 ret = self.copy() 

529 ret += other 

530 return ret 

531 

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

533 if not other: 

534 return self 

535 

536 if other._tokdict: 

537 offset = len(self._toklist) 

538 addoffset = lambda a: offset if a < 0 else a + offset 

539 otheritems = other._tokdict.items() 

540 otherdictitems = [ 

541 (k, _ParseResultsWithOffset(v[0], addoffset(v[1]))) 

542 for k, vlist in otheritems 

543 for v in vlist 

544 ] 

545 for k, v in otherdictitems: 

546 self[k] = v 

547 if isinstance(v[0], ParseResults): 

548 v[0]._parent = self 

549 

550 self._toklist += other._toklist 

551 self._all_names |= other._all_names 

552 return self 

553 

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

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

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

557 return self.copy() 

558 else: 

559 # this may raise a TypeError - so be it 

560 return other + self 

561 

562 def __repr__(self) -> str: 

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

564 

565 def __str__(self) -> str: 

566 return ( 

567 "[" 

568 + ", ".join( 

569 [ 

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

571 for i in self._toklist 

572 ] 

573 ) 

574 + "]" 

575 ) 

576 

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

578 out = [] 

579 for item in self._toklist: 

580 if out and sep: 

581 out.append(sep) 

582 if isinstance(item, ParseResults): 

583 out += item._asStringList() 

584 else: 

585 out.append(str(item)) 

586 return out 

587 

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

589 """ 

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

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

592 

593 Example: 

594 

595 .. doctest:: 

596 

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

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

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

600 >>> # it is actually a pyparsing ParseResults 

601 >>> type(result) 

602 <class 'pyparsing.results.ParseResults'> 

603 >>> print(result) 

604 ['sldkj', 'lsdkj', 'sldkj'] 

605 

606 .. doctest:: 

607 

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

609 >>> result_list = result.as_list() 

610 >>> type(result_list) 

611 <class 'list'> 

612 >>> print(result_list) 

613 ['sldkj', 'lsdkj', 'sldkj'] 

614 

615 .. versionchanged:: 3.2.0 

616 New ``flatten`` argument. 

617 """ 

618 

619 if flatten: 

620 return [*_flatten(self)] 

621 else: 

622 return [ 

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

624 for res in self._toklist 

625 ] 

626 

627 def as_dict(self) -> dict: 

628 """ 

629 Returns the named parse results as a nested dictionary. 

630 

631 Example: 

632 

633 .. doctest:: 

634 

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

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

637 

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

639 >>> type(result) 

640 <class 'pyparsing.results.ParseResults'> 

641 >>> result 

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

643 

644 >>> result_dict = result.as_dict() 

645 >>> type(result_dict) 

646 <class 'dict'> 

647 >>> result_dict 

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

649 

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

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

652 >>> import json 

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

654 Traceback (most recent call last): 

655 TypeError: Object of type ParseResults is not JSON serializable 

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

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

658 """ 

659 

660 def to_item(obj): 

661 if isinstance(obj, ParseResults): 

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

663 else: 

664 return obj 

665 

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

667 

668 def copy(self) -> ParseResults: 

669 """ 

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

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

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

673 create a copy with its own separate content values. 

674 """ 

675 ret: ParseResults = object.__new__(ParseResults) 

676 ret._toklist = self._toklist[:] 

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

678 ret._parent = self._parent 

679 ret._all_names = {*self._all_names} 

680 ret._name = self._name 

681 ret._modal = self._modal 

682 return ret 

683 

684 def deepcopy(self) -> ParseResults: 

685 """ 

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

687 

688 .. versionadded:: 3.1.0 

689 """ 

690 ret = self.copy() 

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

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

693 if isinstance(obj, ParseResults): 

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

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

696 pass 

697 elif isinstance(obj, MutableMapping): 

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

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

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

701 elif isinstance(obj, Iterable): 

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

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

704 ) 

705 return ret 

706 

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

708 r""" 

709 Returns the results name for this token expression. 

710 

711 Useful when several different expressions might match 

712 at a particular location. 

713 

714 Example: 

715 

716 .. testcode:: 

717 

718 integer = Word(nums) 

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

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

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

722 | Group(ssn_expr)("ssn") 

723 | Group(integer)("age")) 

724 user_info = user_data[1, ...] 

725 

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

727 for item in result: 

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

729 

730 prints: 

731 

732 .. testoutput:: 

733 

734 age : 22 

735 ssn : 111-22-3333 

736 house_number : 221B 

737 

738 """ 

739 if self._name: 

740 return self._name 

741 elif self._parent: 

742 par: ParseResults = self._parent 

743 parent_tokdict_items = par._tokdict.items() 

744 return next( 

745 ( 

746 k 

747 for k, vlist in parent_tokdict_items 

748 for v, loc in vlist 

749 if v is self 

750 ), 

751 None, 

752 ) 

753 elif ( 

754 len(self) == 1 

755 and len(self._tokdict) == 1 

756 and next(iter(self._tokdict.values()))[0][1] in (0, -1) 

757 ): 

758 return next(iter(self._tokdict.keys())) 

759 else: 

760 return None 

761 

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

763 """ 

764 Diagnostic method for listing out the contents of 

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

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

767 

768 Example: 

769 

770 .. testcode:: 

771 

772 integer = Word(nums) 

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

774 

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

776 print(result.dump()) 

777 

778 prints: 

779 

780 .. testoutput:: 

781 

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

783 - day: '31' 

784 - month: '12' 

785 - year: '1999' 

786 """ 

787 out = [] 

788 NL = "\n" 

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

790 

791 if not full: 

792 return "".join(out) 

793 

794 if self.haskeys(): 

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

796 for k, v in items: 

797 if out: 

798 out.append(NL) 

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

800 if not isinstance(v, ParseResults): 

801 out.append(repr(v)) 

802 continue 

803 

804 if not v: 

805 out.append(str(v)) 

806 continue 

807 

808 out.append( 

809 v.dump( 

810 indent=indent, 

811 full=full, 

812 include_list=include_list, 

813 _depth=_depth + 1, 

814 ) 

815 ) 

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

817 return "".join(out) 

818 

819 v = self 

820 incr = " " 

821 nl = "\n" 

822 for i, vv in enumerate(v): 

823 if isinstance(vv, ParseResults): 

824 vv_dump = vv.dump( 

825 indent=indent, 

826 full=full, 

827 include_list=include_list, 

828 _depth=_depth + 1, 

829 ) 

830 out.append( 

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

832 ) 

833 else: 

834 out.append( 

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

836 ) 

837 

838 return "".join(out) 

839 

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

841 """ 

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

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

844 Accepts additional positional or keyword args as defined for 

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

846 

847 Example: 

848 

849 .. testcode:: 

850 

851 ident = Word(alphas, alphanums) 

852 num = Word(nums) 

853 func = Forward() 

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

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

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

857 result.pprint(width=40) 

858 

859 prints: 

860 

861 .. testoutput:: 

862 

863 ['fna', 

864 ['a', 

865 'b', 

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

867 '100']] 

868 """ 

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

870 

871 # add support for pickle protocol 

872 def __getstate__(self): 

873 return ( 

874 self._toklist, 

875 ( 

876 self._tokdict.copy(), 

877 None, 

878 self._all_names, 

879 self._name, 

880 ), 

881 ) 

882 

883 def __setstate__(self, state): 

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

885 self._all_names = set(inAccumNames) 

886 self._parent = None 

887 

888 def __getnewargs__(self): 

889 return self._toklist, self._name 

890 

891 def __dir__(self): 

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

893 

894 @classmethod 

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

896 """ 

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

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

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

900 """ 

901 ret = cls([]) 

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

903 if isinstance(v, Mapping): 

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

905 else: 

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

907 if name is not None: 

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

909 return ret 

910 

911 asList = as_list 

912 """ 

913 .. deprecated:: 3.0.0 

914 use :meth:`as_list` 

915 """ 

916 asDict = as_dict 

917 """ 

918 .. deprecated:: 3.0.0 

919 use :meth:`as_dict` 

920 """ 

921 getName = get_name 

922 """ 

923 .. deprecated:: 3.0.0 

924 use :meth:`get_name` 

925 """ 

926 

927 

928MutableMapping.register(ParseResults) 

929MutableSequence.register(ParseResults)