def __init__(self, chars): super(EmptyQuotedString, self).__init__() single = Char("'") >> String(set(chars) - set("'"), "'", 0) << Char("'") double = Char('"') >> String(set(chars) - set('"'), '"', 0) << Char('"') self.add_child(single | double)
def test_many1(): a = Char("a") b = Char("b") x = Char("x") xs = Many(x, lower=1) with pytest.raises(Exception): xs("") with pytest.raises(Exception): xs("a") assert xs("x") == ["x"] assert xs("xxxxx") == ["x", "x", "x", "x", "x"] assert xs("xxxxb") == ["x", "x", "x", "x"] ab = Many(a + b, lower=1) with pytest.raises(Exception): ab("") with pytest.raises(Exception): ab("ba") assert ab("ab") == [["a", "b"]] assert ab("ababab") == [["a", "b"], ["a", "b"], ["a", "b"]] ab = Many(a | b, lower=1) assert ab("aababb") == ["a", "a", "b", "a", "b", "b"]
def __init__(self, ctx): self.ctx = ctx Complex = Forward() Comment = (WS >> OneLineComment("#")).map(lambda x: None) Name = String(string.ascii_letters + "_/") Num = Number & (WSChar | LineEnd) StartName = WS >> PosMarker(StartTagName(Letters)) << WS EndName = WS >> EndTagName(Letters, ignore_case=True) << WS Cont = Char("\\") + EOL AttrStart = Many(WSChar) AttrEnd = (Many(WSChar) + Cont) | Many(WSChar) OpAttr = (Literal("!=") | Literal("<=") | Literal(">=") | InSet("<>")) & WSChar BareAttr = String( set(string.printable) - (set(string.whitespace) | set("<>'\""))) Attr = AttrStart >> (Num | QuotedString | OpAttr | BareAttr) << AttrEnd Attrs = Many(Attr) StartTag = (WS + LT) >> (StartName + Attrs) << (GT + WS) EndTag = (WS + LT + FS) >> EndName << (GT + WS) Simple = WS >> (Lift(self.to_directive) * PosMarker(Name) * Attrs) << WS Stanza = Simple | Complex | Comment | Many(WSChar | EOL, lower=1).map(lambda x: None) Complex <= (Lift(self.to_section) * StartTag * Many(Stanza).map(skip_none)) << EndTag Doc = Many(Stanza).map(skip_none) self.Top = Doc + EOF
def test_many(): a = Char("a") b = Char("b") x = Char("x") xs = Many(x) assert xs("") == [] assert xs("a") == [] assert xs("x") == ["x"] assert xs("xxxxx") == ["x", "x", "x", "x", "x"] assert xs("xxxxb") == ["x", "x", "x", "x"] ab = Many(a + b) assert ab("") == [] assert ab("ba") == [] assert ab("ab") == [["a", "b"]] assert ab("ababab") == [["a", "b"], ["a", "b"], ["a", "b"]] ab = Many(a | b) assert ab("aababb") == ["a", "a", "b", "a", "b", "b"]
def parse_doc(f, ctx=None, line_end="\n"): def to_entry(name, rest): rest = [] if not rest else [rest] return Directive(name=name.value, attrs=rest, lineno=name.lineno, src=ctx) Sep = Char("=") Stmt = Forward() Num = Number & (WSChar | LineEnd) Comment = (WS >> OneLineComment("#").map(lambda x: None)) Bare = String(set(string.printable) - (set("#\n\r"))) Name = WS >> PosMarker(String(string.ascii_letters + "_-" + string.digits)) << WS Value = WS >> (Num | Bare) << WS Stanza = (Lift(to_entry) * Name * (Opt(Sep >> Value))) | Comment Stmt <= WS >> Stanza << WS Doc = Many(Stmt).map(skip_none) Top = Doc + EOF return Entry(children=Top(f)[0], src=ctx)
def parse_doc(self, content): try: def to_directive(x): name, rest = x rest = [rest] if rest is not None else [] return Directive(name=name.value.strip(), attrs=rest, lineno=name.lineno, src=self) def to_section(name, rest): return Section(name=name.value.strip(), children=rest, lineno=name.lineno, src=self) def apply_defaults(cfg): if "DEFAULT" not in cfg: return cfg defaults = cfg["DEFAULT"] not_defaults = cfg[~eq("DEFAULT")] for c in not_defaults: for d in defaults.grandchildren: if d.name not in c: c.children.append(d) cfg.children = list(not_defaults) return cfg def make_bytes(number, char_multiple): if char_multiple.lower() == 'k': return number * 2**10 if char_multiple.lower() == 'm': return number * 2**20 if char_multiple.lower() == 'g': return number * 2**30 content = "\n".join(content) header_chars = (set(string.printable) - set(string.whitespace) - set("[]")) | set(" ") sep_chars = set("=") key_chars = header_chars - sep_chars value_chars = set(string.printable) - set("\n\r") On = Literal("on", True, ignore_case=True) Off = Literal("off", False, ignore_case=True) Tru = Literal("true", True, ignore_case=True) Fals = Literal("false", False, ignore_case=True) Boolean = ((On | Off | Tru | Fals) & (WSChar | LineEnd)) % "Boolean" Num = Number & (WSChar | LineEnd) QuoStr = QuotedString & (WSChar | LineEnd) # Handle php.ini shorthand notation for memory limits: 1G, 8M, 50K # https://www.php.net/manual/en/faq.using.php#faq.using.shorthandbytes MemNum = (Lift(make_bytes) * Number * (Char('K') | Char('M') | Char('G'))) & (WSChar | LineEnd) LeftEnd = (WS + LeftBracket + WS) RightEnd = (WS + RightBracket + WS) Header = (LeftEnd >> PosMarker(String(header_chars)) << RightEnd) % "Header" Key = WS >> PosMarker(String(key_chars)) << WS Sep = InSet(sep_chars, "Sep") Value = WS >> (Boolean | MemNum | Num | QuoStr | HangingString(value_chars)) KVPair = WithIndent(Key + Opt(Sep >> Value)) % "KVPair" Comment = (WS >> (OneLineComment(";")).map(lambda x: None)) Line = Comment | KVPair.map(to_directive) Sect = Lift(to_section) * Header * Many(Line).map(skip_none) Doc = Many(Comment | Sect).map(skip_none) Top = Doc << WS << EOF res = Entry(children=Top(content), src=self) return apply_defaults(res) except SkipException: raise except: raise ParseException(ParseException("Could not parse content: '{0}'". format(content)))
import re import string from .. import Parser, parser, LegacyItemAccess from insights.specs import Specs from insights.parsr import (Char, EOF, HangingString, InSet, Many, OneLineComment, Opt, skip_none, String, WithIndent, WS) header_chars = (set(string.printable) - set(string.whitespace) - set("[]")) | set(" ") sep_chars = set(":=") key_chars = header_chars - sep_chars - set(" ") value_chars = set(string.printable) - set("\n\r") LeftEnd = WS >> Char("[") << WS RightEnd = WS >> Char("]") << WS Header = LeftEnd >> String(header_chars) << RightEnd Key = WS >> String(key_chars) << WS Sep = InSet(sep_chars) Value = WS >> HangingString(value_chars) KVPair = WithIndent(Key + Opt(Sep >> Value)) Comment = WS >> (OneLineComment("#") | OneLineComment(";")).map(lambda x: None) Line = Comment | KVPair.map(tuple) Sect = (Header + Many(Line).map(skip_none).map(dict)).map(tuple) Doc = Many(Comment | Sect).map(skip_none).map(dict) Top = Doc << WS << EOF def parse_yum_repos(content):
def test_or(): p = Char("a") | Char("b") assert p("a") == "a" assert p("b") == "b"
def test_and(): p = Char("a") + Char("b") assert p("ab") == ["a", "b"]
return Not(p) if op else p def oper(args): left, rest = args for op, right in rest: if op == "&": left = And(left, right) if op in ",|": left = Or(left, right) return left expr = Forward() bare = String(set(string.printable) - (set(string.whitespace) | set(")&,|"))) tag = (QuotedString | bare).map(Eq) regex_body = QuotedString | String( set(string.printable) - set(string.whitespace)) regex = Char("/") >> regex_body.map(Regex) factor_body = ((Char("(") >> expr << Char(")")) | regex | tag) factor = (WS >> Opt(Char("!")) + factor_body << WS).map(negate) term = (factor + Many(Char("&") + factor)).map(oper) expr <= (term + Many(InSet(",|") + term)).map(oper) parse = expr << EOF
def test_opt_default(): a = Opt(Char("a"), "Default") assert a("b") == "Default"
def test_opt(): a = Opt(Char("a")) assert a("a") == "a" assert a("b") is None
def test_until(): a = Char("a") b = Char("b") u = Until(a, b) res = u("aaaab") assert len(res) == 4
def test_error(): p = Char("a").map(boom) try: p("a") except Exception as ex: assert "boom" in str(ex)