]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/pip/_vendor/pyparsing/results.py
2 from collections
.abc
import (
11 from typing
import Tuple
, Any
, Dict
, Set
, List
13 str_type
: Tuple
[type, ...] = (str, bytes)
14 _generator_type
= type((_
for _
in ()))
17 class _ParseResultsWithOffset
:
18 tup
: Tuple
["ParseResults", int]
21 def __init__(self
, p1
: "ParseResults", p2
: int):
22 self
.tup
: Tuple
[ParseResults
, int] = (p1
, p2
)
24 def __getitem__(self
, i
):
27 def __getstate__(self
):
30 def __setstate__(self
, *args
):
35 """Structured parse results, to provide multiple means of access to
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`)
45 date_str = (integer.set_results_name("year") + '/'
46 + integer.set_results_name("month") + '/'
47 + integer.set_results_name("day"))
49 # date_str = (integer("year") + '/'
50 # + integer("month") + '/'
53 # parse_string returns a ParseResults object
54 result = date_str.parse_string("1999/12/31")
57 print(f"{s} -> {fn(eval(s))}")
60 test("result['month']")
62 test("'month' in result")
63 test("'minutes' in result")
64 test("result.dump()", str)
68 list(result) -> ['1999', '/', '12', '/', '31']
70 result['month'] -> '12'
72 'month' in result -> True
73 'minutes' in result -> False
74 result.dump() -> ['1999', '/', '12', '/', '31']
80 _null_values
: Tuple
[Any
, ...] = (None, [], ())
83 _parent
: "ParseResults"
87 _tokdict
: Dict
[str, Any
]
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`::
103 LBRACK, RBRACK = map(pp.Suppress, "[]")
104 element = pp.Forward()
106 element_list = LBRACK + pp.DelimitedList(element) + RBRACK
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)
113 element <<= item | element_list
115 element.run_tests('''
121 ''', post_parse=lambda s, r: (r[0], type(r[0])))
129 ([2, 3, 4], <class 'list'>)
132 ([[2, 1], 3, 4], <class 'list'>)
134 (Used internally by :class:`Group` when `aslist=True`.)
137 def __new__(cls
, contained
=None):
138 if contained
is None:
141 if not isinstance(contained
, list):
143 f
"{cls.__name__} may only be constructed with a list, not {type(contained).__name__}"
146 return list.__new
__(cls
)
148 def __new__(cls
, toklist
=None, name
=None, **kwargs
):
149 if isinstance(toklist
, ParseResults
):
151 self
= object.__new
__(cls
)
154 self
._all
_names
= set()
158 elif isinstance(toklist
, (list, _generator_type
)):
161 if isinstance(toklist
, ParseResults
.List
)
165 self
._toklist
= [toklist
]
166 self
._tokdict
= dict()
169 # Performance tuning: we construct a *lot* of these, so keep this
170 # constructor as small and fast as possible
172 self
, toklist
=None, name
=None, asList
=True, modal
=True, isinstance=isinstance
174 self
._tokdict
: Dict
[str, _ParseResultsWithOffset
]
176 if name
is not None and name
!= "":
177 if isinstance(name
, int):
180 self
._all
_names
= {name}
182 if toklist
not in self
._null
_values
:
183 if isinstance(toklist
, (str_type
, type)):
186 if isinstance(toklist
, ParseResults
):
187 self
[name
] = _ParseResultsWithOffset(
188 ParseResults(toklist
._toklist
), 0
191 self
[name
] = _ParseResultsWithOffset(
192 ParseResults(toklist
[0]), 0
194 self
[name
]._name
= name
197 self
[name
] = toklist
[0]
198 except (KeyError, TypeError, IndexError):
199 if toklist
is not self
:
204 def __getitem__(self
, i
):
205 if isinstance(i
, (int, slice)):
206 return self
._toklist
[i
]
208 if i
not in self
._all
_names
:
209 return self
._tokdict
[i
][-1][0]
211 return ParseResults([v
[0] for v
in self
._tokdict
[i
]])
213 def __setitem__(self
, k
, v
, isinstance=isinstance):
214 if isinstance(v
, _ParseResultsWithOffset
):
215 self
._tokdict
[k
] = self
._tokdict
.get(k
, list()) + [v
]
217 elif isinstance(k
, (int, slice)):
221 self
._tokdict
[k
] = self
._tokdict
.get(k
, list()) + [
222 _ParseResultsWithOffset(v
, 0)
225 if isinstance(sub
, ParseResults
):
228 def __delitem__(self
, i
):
229 if isinstance(i
, (int, slice)):
230 mylen
= len(self
._toklist
)
233 # convert int to slice
234 if isinstance(i
, int):
238 # get removed indices
239 removed
= list(range(*i
.indices(mylen
)))
241 # fixup indices in token dictionary
242 for name
, occurrences
in self
._tokdict
.items():
244 for k
, (value
, position
) in enumerate(occurrences
):
245 occurrences
[k
] = _ParseResultsWithOffset(
246 value
, position
- (position
> j
)
251 def __contains__(self
, k
) -> bool:
252 return k
in self
._tokdict
254 def __len__(self
) -> int:
255 return len(self
._toklist
)
257 def __bool__(self
) -> bool:
258 return not not (self
._toklist
or self
._tokdict
)
260 def __iter__(self
) -> Iterator
:
261 return iter(self
._toklist
)
263 def __reversed__(self
) -> Iterator
:
264 return iter(self
._toklist
[::-1])
267 return iter(self
._tokdict
)
270 return (self
[k
] for k
in self
.keys())
273 return ((k
, self
[k
]) for k
in self
.keys())
275 def haskeys(self
) -> bool:
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
281 def pop(self
, *args
, **kwargs
):
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
294 numlist = Word(nums)[...]
295 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321']
297 def remove_first(tokens):
299 numlist.add_parse_action(remove_first)
300 print(numlist.parse_string("0 123 321")) # -> ['123', '321']
303 patt = label("LABEL") + Word(nums)[1, ...]
304 print(patt.parse_string("AAB 123 321").dump())
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):
311 patt.add_parse_action(remove_LABEL)
312 print(patt.parse_string("AAB 123 321").dump())
316 ['AAB', '123', '321']
319 ['AAB', '123', '321']
323 for k
, v
in kwargs
.items():
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
:
334 defaultvalue
= args
[1]
337 def get(self
, key
, default_value
=None):
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.
343 Similar to ``dict.get()``.
348 date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
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
360 def insert(self
, index
, ins_string
):
362 Inserts new element at location index in the list of parsed tokens.
364 Similar to ``list.insert()``.
368 numlist = Word(nums)[...]
369 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321']
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']
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
)
385 def append(self
, item
):
387 Add single element to end of ``ParseResults`` list of elements.
391 numlist = Word(nums)[...]
392 print(numlist.parse_string("0 123 321")) # -> ['0', '123', '321']
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]
400 self
._toklist
.append(item
)
402 def extend(self
, itemseq
):
404 Add sequence of elements to end of ``ParseResults`` list of elements.
408 patt = Word(alphas)[1, ...]
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'
417 if isinstance(itemseq
, ParseResults
):
418 self
.__iadd
__(itemseq
)
420 self
._toklist
.extend(itemseq
)
424 Clear all elements and results names.
427 self
._tokdict
.clear()
429 def __getattr__(self
, name
):
433 if name
.startswith("__"):
434 raise AttributeError(name
)
437 def __add__(self
, other
: "ParseResults") -> "ParseResults":
442 def __iadd__(self
, other
: "ParseResults") -> "ParseResults":
447 offset
= len(self
._toklist
)
448 addoffset
= lambda a
: offset
if a
< 0 else a
+ offset
449 otheritems
= other
._tokdict
.items()
451 (k
, _ParseResultsWithOffset(v
[0], addoffset(v
[1])))
452 for k
, vlist
in otheritems
455 for k
, v
in otherdictitems
:
457 if isinstance(v
[0], ParseResults
):
460 self
._toklist
+= other
._toklist
461 self
._all
_names |
= other
._all
_names
464 def __radd__(self
, other
) -> "ParseResults":
465 if isinstance(other
, int) and other
== 0:
466 # useful for merging many ParseResults using sum() builtin
469 # this may raise a TypeError - so be it
472 def __repr__(self
) -> str:
473 return f
"{type(self).__name__}({self._toklist!r}, {self.as_dict()})"
475 def __str__(self
) -> str:
480 str(i
) if isinstance(i
, ParseResults
) else repr(i
)
481 for i
in self
._toklist
487 def _asStringList(self
, sep
=""):
489 for item
in self
._toklist
:
492 if isinstance(item
, ParseResults
):
493 out
+= item
._asStringList
()
495 out
.append(str(item
))
498 def as_list(self
) -> list:
500 Returns the parse results as a nested list of matching tokens, all converted to strings.
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']
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']
514 res
.as_list() if isinstance(res
, ParseResults
) else res
515 for res
in self
._toklist
518 def as_dict(self
) -> dict:
520 Returns the named parse results as a nested dictionary.
525 date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
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)]})
530 result_dict = result.as_dict()
531 print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'}
533 # even though a ParseResults supports dict-like access, sometime you just need to have a dict
535 print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable
536 print(json.dumps(result.as_dict())) # -> {"month": "31", "day": "1999", "year": "12"}
540 if isinstance(obj
, ParseResults
):
541 return obj
.as_dict() if obj
.haskeys() else [to_item(v
) for v
in obj
]
545 return dict((k
, to_item(v
)) for k
, v
in self
.items())
547 def copy(self
) -> "ParseResults":
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
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
561 def deepcopy(self
) -> "ParseResults":
563 Returns a new deep copy of a :class:`ParseResults` object.
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)):
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
584 Returns the results name for this token expression. Useful when several
585 different expressions might match at a particular location.
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, ...]
597 result = user_info.parse_string("22 111-22-3333 #221B")
599 print(item.get_name(), ':', item[0])
610 par
: "ParseResults" = self
._parent
611 parent_tokdict_items
= par
._tokdict
.items()
615 for k
, vlist
in parent_tokdict_items
623 and len(self
._tokdict
) == 1
624 and next(iter(self
._tokdict
.values()))[0][1] in (0, -1)
626 return next(iter(self
._tokdict
.keys()))
630 def dump(self
, indent
="", full
=True, include_list
=True, _depth
=0) -> str:
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.
639 date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
641 result = date_str.parse_string('1999/12/31')
646 ['1999', '/', '12', '/', '31']
653 out
.append(indent
+ str(self
.as_list()) if include_list
else "")
657 items
= sorted((str(k
), v
) for k
, v
in self
.items())
661 out
.append(f
"{indent}{(' ' * _depth)}- {k}: ")
662 if isinstance(v
, ParseResults
):
668 include_list
=include_list
,
676 if any(isinstance(vv
, ParseResults
) for vv
in self
):
678 for i
, vv
in enumerate(v
):
679 if isinstance(vv
, ParseResults
):
681 "\n{}{}[{}]:\n{}{}{}".format(
686 (" " * (_depth
+ 1)),
690 include_list
=include_list
,
697 "\n%s%s[%d]:\n%s%s%s"
703 (" " * (_depth
+ 1)),
710 def pprint(self
, *args
, **kwargs
):
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>`_ .
719 ident = Word(alphas, alphanums)
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)
732 ['(', 'fnb', ['c', 'd', '200'], ')'],
735 pprint
.pprint(self
.as_list(), *args
, **kwargs
)
737 # add support for pickle protocol
738 def __getstate__(self
):
742 self
._tokdict
.copy(),
749 def __setstate__(self
, state
):
750 self
._toklist
, (self
._tokdict
, par
, inAccumNames
, self
._name
) = state
751 self
._all
_names
= set(inAccumNames
)
754 def __getnewargs__(self
):
755 return self
._toklist
, self
._name
758 return dir(type(self
)) + list(self
.keys())
761 def from_dict(cls
, other
, name
=None) -> "ParseResults":
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.
768 def is_iterable(obj
):
773 # str's are iterable, but in pyparsing, we don't want to iterate over them
775 return not isinstance(obj
, str_type
)
778 for k
, v
in other
.items():
779 if isinstance(v
, Mapping
):
780 ret
+= cls
.from_dict(v
, name
=k
)
782 ret
+= cls([v
], name
=k
, asList
=is_iterable(v
))
784 ret
= cls([ret
], name
=name
)
788 """Deprecated - use :class:`as_list`"""
790 """Deprecated - use :class:`as_dict`"""
792 """Deprecated - use :class:`get_name`"""
795 MutableMapping
.register(ParseResults
)
796 MutableSequence
.register(ParseResults
)