From a779aac9db96b05acb2c4e1b62417bbf37f160f8 Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 28 Apr 2012 17:12:39 +1200 Subject: [PATCH] Make specification language more terse, and more regular. --- libpathod/rparse.py | 27 ++++++++---- notes | 103 ++++++++++++++------------------------------ test/test_rparse.py | 57 ++++++++++++------------ 3 files changed, 79 insertions(+), 108 deletions(-) diff --git a/libpathod/rparse.py b/libpathod/rparse.py index 5c6d02570..18d05a69a 100644 --- a/libpathod/rparse.py +++ b/libpathod/rparse.py @@ -15,6 +15,9 @@ class ParseException(Exception): def marked(self): return "%s\n%s"%(self.s, " "*(self.col-1) + "^") + def __str__(self): + return self.msg + class ServerError(Exception): pass @@ -41,16 +44,17 @@ v_integer = pp.Regex(r"[+-]?\d+")\ .setName("integer")\ .setParseAction(lambda toks: int(toks[0])) -v_string = pp.MatchFirst( + +v_literal = pp.MatchFirst( [ pp.QuotedString("\"", escChar="\\", unquoteResults=True), pp.QuotedString("'", escChar="\\", unquoteResults=True), ] ) -v_literal = pp.MatchFirst( +v_naked_literal = pp.MatchFirst( [ - v_string, + v_literal, pp.Word("".join(i for i in pp.printables if i not in ",:")) ] ) @@ -121,6 +125,13 @@ class ValueLiteral: return self.val +class ValueNakedLiteral(ValueLiteral): + @classmethod + def expr(klass): + e = v_naked_literal.copy() + return e.setParseAction(lambda x: klass(*x)) + + class ValueGenerate: UNITS = dict( b = 1024**0, @@ -163,7 +174,7 @@ class ValueFile: @classmethod def expr(klass): e = pp.Literal("<").suppress() - e = e + v_literal + e = e + v_naked_literal return e.setParseAction(lambda x: klass(*x)) def get_generator(self, settings): @@ -197,7 +208,7 @@ class Body: @classmethod def expr(klass): - e = pp.Literal("b:").suppress() + e = pp.Literal("b").suppress() e = e + Value return e.setParseAction(lambda x: klass(*x)) @@ -208,7 +219,7 @@ class _Pause: @classmethod def expr(klass): - e = pp.Literal("p%s:"%klass.sub).suppress() + e = pp.Literal("p%s"%klass.sub).suppress() e = e + pp.MatchFirst( [ v_integer, @@ -273,7 +284,7 @@ class Header: @classmethod def expr(klass): - e = pp.Literal("h:").suppress() + e = pp.Literal("h").suppress() e += Value e += pp.Literal(":").suppress() e += Value @@ -294,7 +305,7 @@ class Code: def expr(klass): e = v_integer e = e + pp.Optional( - pp.Literal(":").suppress() + Value + Value ) return e.setParseAction(lambda x: klass(*x)) diff --git a/notes b/notes index 0513cb425..bd315ebe0 100644 --- a/notes +++ b/notes @@ -1,92 +1,53 @@ +Response: + + code[msg],[comma-separated features] + + +Features: + + hVALUE:VALUE Set header + bVALUE Set body + db Disconnect before sending data + dr Disconnect randomly + pbTIME Pause before sending data for NUM seconds or forever + paTIME Pause after sending all data for NUM seconds or forever + prTIME Pause randomly for NUM seconds or forever + + cVALUE Set Content-Type header + lVALUE Set Location header + + +Time Specifiers: + + 5 - 5 seconds + 5s - 5 seconds + 5m - 5 minutes + 5h - 5 hours + + Value Specifiers: !500k - 500k of random data !500k:utf8 - 500k of utf8. Other specifiers: utf8,alphanum,alpha,printable "foo" - literal - foo - literal destination - code>destination - - 301:VALUE>VALUE - 301>http://foo.bar - - - Content-type: - - t:content-type + <"path" - load from path under data directory Examples: - 200,b:500k - - 404,p:5s,b:1k:printable - - 200,t:text/json,p:5s,b:1k - - 200,b:1k,xr - + 200,b500k + 404,pb5,b1k:printable + 200,t"text/json",pr5,b1k + 200,b1k,xr Sequences: 200 * 2 | !forever - 200 | 404 | 200,b:500g - Anchors: Passed on command-line? diff --git a/test/test_rparse.py b/test/test_rparse.py index 8e9da6f05..440803c98 100644 --- a/test/test_rparse.py +++ b/test/test_rparse.py @@ -17,7 +17,7 @@ class DummyRequest(StringIO.StringIO): class uMisc(libpry.AutoTree): def test_generators(self): - v = rparse.Value.parseString("val")[0] + v = rparse.Value.parseString("'val'")[0] g = v.get_generator({}) assert g[:] == "val" @@ -94,26 +94,25 @@ class uMisc(libpry.AutoTree): assert v.datatype == "digits" def test_value(self): - assert rparse.Value.parseString("val")[0].val == "val" assert rparse.Value.parseString("'val'")[0].val == "val" assert rparse.Value.parseString('"val"')[0].val == "val" assert rparse.Value.parseString('"\'val\'"')[0].val == "'val'" def test_body(self): e = rparse.Body.expr() - v = e.parseString("b:foo")[0] + v = e.parseString("b'foo'")[0] assert v.value.val == "foo" - v = e.parseString("b:!100")[0] + v = e.parseString("b!100")[0] assert str(v.value) == "!100b:bytes" - v = e.parseString("b:!100g:digits", parseAll=True)[0] + v = e.parseString("b!100g:digits", parseAll=True)[0] assert v.value.datatype == "digits" assert str(v.value) == "!100g:digits" def test_header(self): e = rparse.Header.expr() - v = e.parseString("h:foo:bar")[0] + v = e.parseString("h'foo':'bar'")[0] assert v.key.val == "foo" assert v.value.val == "bar" @@ -122,17 +121,17 @@ class uMisc(libpry.AutoTree): v = e.parseString("200")[0] assert v.code == 200 - v = e.parseString("404:msg")[0] + v = e.parseString("404'msg'")[0] assert v.code == 404 assert v.msg.val == "msg" - r = e.parseString("200:'foo'")[0] + r = e.parseString("200'foo'")[0] assert r.msg.val == "foo" - r = e.parseString("200:'\"foo\"'")[0] + r = e.parseString("200'\"foo\"'")[0] assert r.msg.val == "\"foo\"" - r = e.parseString('200:"foo"')[0] + r = e.parseString('200"foo"')[0] assert r.msg.val == "foo" r = e.parseString('404')[0] @@ -168,20 +167,20 @@ class uDisconnects(libpry.AutoTree): class uPauses(libpry.AutoTree): def test_before(self): e = rparse.PauseBefore.expr() - v = e.parseString("pb:10")[0] + v = e.parseString("pb10")[0] assert v.value == 10 - v = e.parseString("pb:forever")[0] + v = e.parseString("pbforever")[0] assert v.value == "forever" def test_after(self): e = rparse.PauseAfter.expr() - v = e.parseString("pa:10")[0] + v = e.parseString("pa10")[0] assert v.value == 10 def test_random(self): e = rparse.PauseRandom.expr() - v = e.parseString("pr:10")[0] + v = e.parseString("pr10")[0] assert v.value == 10 @@ -191,41 +190,41 @@ class uparse(libpry.AutoTree): try: rparse.parse({}, "400:msg,b:") except rparse.ParseException, v: - print v.marked() + assert v.marked() def test_parse_header(self): - r = rparse.parse({}, "400,h:foo:bar") + r = rparse.parse({}, '400,h"foo":"bar"') assert r.get_header("foo") == "bar" def test_parse_pause_before(self): - r = rparse.parse({}, "400,pb:10") + r = rparse.parse({}, "400,pb10") assert (0, 10) in r.pauses def test_parse_pause_after(self): - r = rparse.parse({}, "400,pa:10") + r = rparse.parse({}, "400,pa10") assert (sys.maxint, 10) in r.pauses def test_parse_pause_random(self): - r = rparse.parse({}, "400,pr:10") + r = rparse.parse({}, "400,pr10") assert ("random", 10) in r.pauses class uResponse(libpry.AutoTree): def dummy_response(self): - return rparse.parse({}, "400:msg") + return rparse.parse({}, "400'msg'") def test_response(self): - r = rparse.parse({}, "400:msg") + r = rparse.parse({}, "400'msg'") assert r.code == 400 assert r.msg == "msg" - r = rparse.parse({}, "400:msg,b:!100b") + r = rparse.parse({}, "400'msg',b!100b") assert r.msg == "msg" assert r.body[:] assert str(r) def test_ready_randoms(self): - r = rparse.parse({}, "400:msg") + r = rparse.parse({}, "400'msg'") x = [(0, 5)] assert r.ready_randoms(100, x) == x @@ -246,7 +245,7 @@ class uResponse(libpry.AutoTree): def test_write_values(self): tst = "foo"*1025 - r = rparse.parse({}, "400:msg") + r = rparse.parse({}, "400'msg'") s = DummyRequest() r.write_values(s, [tst], [], None) @@ -254,7 +253,7 @@ class uResponse(libpry.AutoTree): def test_write_values_pauses(self): tst = "".join(str(i) for i in range(10)) - r = rparse.parse({}, "400:msg") + r = rparse.parse({}, "400'msg'") for i in range(2, 10): s = DummyRequest() @@ -274,7 +273,7 @@ class uResponse(libpry.AutoTree): def test_render(self): s = DummyRequest() - r = rparse.parse({}, "400:msg") + r = rparse.parse({}, "400'msg'") r.render(s) def test_length(self): @@ -282,9 +281,9 @@ class uResponse(libpry.AutoTree): s = DummyRequest() x.render(s) assert x.length() == len(s.getvalue()) - testlen(rparse.parse({}, "400:msg")) - testlen(rparse.parse({}, "400:msg,h:foo:bar")) - testlen(rparse.parse({}, "400:msg,h:foo:bar,b:!100b")) + testlen(rparse.parse({}, "400'msg'")) + testlen(rparse.parse({}, "400'msg',h'foo':'bar'")) + testlen(rparse.parse({}, "400'msg',h'foo':'bar',b!100b")) tests = [