From fffee660e57e1f8be19ae6ffa979c48cfc6cef9e Mon Sep 17 00:00:00 2001 From: Aldo Cortesi Date: Sat, 2 May 2015 21:42:09 +1200 Subject: [PATCH] language: create and use Integer and PreValue generics --- libpathod/language/base.py | 53 +++++++++----------------------- libpathod/language/http.py | 40 ++++++++++++++++-------- libpathod/language/websockets.py | 10 +++++- test/test_language_base.py | 41 ++++++++---------------- 4 files changed, 65 insertions(+), 79 deletions(-) diff --git a/libpathod/language/base.py b/libpathod/language/base.py index f6530d75f..4e1900a79 100644 --- a/libpathod/language/base.py +++ b/libpathod/language/base.py @@ -11,6 +11,9 @@ from . import generators, exceptions TRUNCATE = 1024 +Sep = pp.Optional(pp.Literal(":")).suppress() + + v_integer = pp.Word(pp.nums)\ .setName("integer")\ .setParseAction(lambda toks: int(toks[0])) @@ -318,28 +321,6 @@ class ShortcutUserAgent(_Header): return ShortcutUserAgent(self.value.freeze(settings)) -class Body(_Component): - def __init__(self, value): - self.value = value - - @classmethod - def expr(klass): - e = pp.Literal("b").suppress() - e = e + Value - return e.setParseAction(lambda x: klass(*x)) - - def values(self, settings): - return [ - self.value.get_generator(settings), - ] - - def spec(self): - return "b%s"%(self.value.spec()) - - def freeze(self, settings): - return Body(self.value.freeze(settings)) - - class PathodSpec(_Token): def __init__(self, value): self.value = value @@ -457,9 +438,9 @@ class OptionsOrValue(_Component): return self.__class__(self.value.freeze(settings)) -class Code(_Component): - def __init__(self, code): - self.code = str(code) +class Integer(_Component): + def __init__(self, value): + self.value = str(value) @classmethod def expr(klass): @@ -467,22 +448,25 @@ class Code(_Component): return e.setParseAction(lambda x: klass(*x)) def values(self, settings): - return [generators.LiteralGenerator(self.code)] + return [generators.LiteralGenerator(self.value)] def spec(self): - return "%s"%(self.code) + return "%s"%(self.value) def freeze(self, settings): return self -class Reason(_Component): +class PreValue(_Component): + """ + A value lead by self.preamble. + """ def __init__(self, value): self.value = value @classmethod def expr(klass): - e = pp.Literal("m").suppress() + e = pp.Literal(klass.preamble).suppress() e = e + Value return e.setParseAction(lambda x: klass(*x)) @@ -490,10 +474,10 @@ class Reason(_Component): return [self.value.get_generator(settings)] def spec(self): - return "m%s"%(self.value.spec()) + return "%s%s"%(self.preamble, self.value.spec()) def freeze(self, settings): - return Reason(self.value.freeze(settings)) + return self.__class__(self.value.freeze(settings)) class _Action(_Token): @@ -633,10 +617,6 @@ class _Message(object): def actions(self): return self.toks(_Action) - @property - def body(self): - return self.tok(Body) - @property def headers(self): return self.toks(_Header) @@ -695,6 +675,3 @@ class _Message(object): def __repr__(self): return self.spec() - - -Sep = pp.Optional(pp.Literal(":")).suppress() diff --git a/libpathod/language/http.py b/libpathod/language/http.py index 7966b914c..30a5fd9f3 100644 --- a/libpathod/language/http.py +++ b/libpathod/language/http.py @@ -20,6 +20,18 @@ class Path(base.SimpleValue): pass +class Code(base.Integer): + pass + + +class Reason(base.PreValue): + preamble = "m" + + +class Body(base.PreValue): + preamble = "b" + + class Method(base.OptionsOrValue): options = [ "get", @@ -47,10 +59,14 @@ def get_header(val, headers): class _HTTPMessage(base._Message): version = "HTTP/1.1" + @property def raw(self): return bool(self.tok(Raw)) + @property + def body(self): + return self.tok(Body) @abc.abstractmethod def preamble(self, settings): # pragma: no cover @@ -69,7 +85,7 @@ class _HTTPMessage(base._Message): class Response(_HTTPMessage): comps = ( - base.Body, + Body, base.Header, base.PauseAt, base.DisconnectAt, @@ -77,7 +93,7 @@ class Response(_HTTPMessage): base.ShortcutContentType, base.ShortcutLocation, Raw, - base.Reason + Reason ) logattrs = ["code", "reason", "version", "body"] @@ -87,16 +103,16 @@ class Response(_HTTPMessage): @property def code(self): - return self.tok(base.Code) + return self.tok(Code) @property def reason(self): - return self.tok(base.Reason) + return self.tok(Reason) def preamble(self, settings): l = [self.version, " "] l.extend(self.code.values(settings)) - code = int(self.code.code) + code = int(self.code.value) l.append(" ") if self.reason: l.extend(self.reason.values(settings)) @@ -121,7 +137,7 @@ class Response(_HTTPMessage): if not self.code: tokens.insert( 1, - base.Code(101) + Code(101) ) hdrs = netlib.websockets.server_handshake_headers( settings.websocket_key @@ -159,9 +175,9 @@ class Response(_HTTPMessage): pp.MatchFirst( [ WS.expr() + pp.Optional( - base.Sep + base.Code.expr() + base.Sep + Code.expr() ), - base.Code.expr(), + Code.expr(), ] ), pp.ZeroOrMore(base.Sep + atom) @@ -176,7 +192,7 @@ class Response(_HTTPMessage): class Request(_HTTPMessage): comps = ( - base.Body, + Body, base.Header, base.PauseAt, base.DisconnectAt, @@ -285,12 +301,12 @@ class PathodErrorResponse(Response): def make_error_response(reason, body=None): tokens = [ - base.Code("800"), + Code("800"), base.Header( base.ValueLiteral("Content-Type"), base.ValueLiteral("text/plain") ), - base.Reason(base.ValueLiteral(reason)), - base.Body(base.ValueLiteral("pathod error: " + (body or reason))), + Reason(base.ValueLiteral(reason)), + Body(base.ValueLiteral("pathod error: " + (body or reason))), ] return PathodErrorResponse(tokens) diff --git a/libpathod/language/websockets.py b/libpathod/language/websockets.py index 7ec4a2b1c..b666b2fe8 100644 --- a/libpathod/language/websockets.py +++ b/libpathod/language/websockets.py @@ -17,15 +17,23 @@ class WF(base.CaselessLiteral): TOK = "wf" +class Body(base.PreValue): + preamble = "b" + + class WebsocketFrame(base._Message): comps = ( - base.Body, + Body, base.PauseAt, base.DisconnectAt, base.InjectAt ) logattrs = ["body"] + @property + def body(self): + return self.tok(Body) + @classmethod def expr(klass): parts = [i.expr() for i in klass.comps] diff --git a/test/test_language_base.py b/test/test_language_base.py index 10f11d420..e44580214 100644 --- a/test/test_language_base.py +++ b/test/test_language_base.py @@ -183,24 +183,6 @@ class TestMisc: s = v.spec() assert s == v.expr().parseString(s)[0].spec() - def test_body(self): - e = base.Body.expr() - v = e.parseString("b'foo'")[0] - assert v.value.val == "foo" - - v = e.parseString("b@100")[0] - assert str(v.value) == "@100" - v2 = v.freeze({}) - v3 = v2.freeze({}) - assert v2.value.val == v3.value.val - - v = e.parseString("b@100g,digits", parseAll=True)[0] - assert v.value.datatype == "digits" - assert str(v.value) == "@100g,digits" - - s = v.spec() - assert s == e.parseString(s)[0].spec() - def test_pathodspec(self): e = base.PathodSpec.expr() v = e.parseString("s'200'")[0] @@ -227,16 +209,10 @@ class TestMisc: assert e.freeze({}) assert e.values({}) - def test_code(self): - e = base.Code.expr() - v = e.parseString("200")[0] - assert v.string() == "200" - assert v.spec() == "200" - - assert v.freeze({}).code == v.code - - def test_reason(self): - e = base.Reason.expr() + def test_value(self): + class TT(base.PreValue): + preamble = "m" + e = TT.expr() v = e.parseString("m'msg'")[0] assert v.value.val == "msg" @@ -472,3 +448,12 @@ def test_options_or_value(): v2 = v.freeze({}) v3 = v2.freeze({}) assert v2.value.val == v3.value.val + + +def test_integer(): + e = base.Integer.expr() + v = e.parseString("200")[0] + assert v.string() == "200" + assert v.spec() == "200" + + assert v.freeze({}).value == v.value