Split Code and Reason into separate _Component objects.

This commit is contained in:
Aldo Cortesi 2012-10-28 17:07:16 +13:00
parent e9af434c2b
commit 7d74f75f6d
2 changed files with 52 additions and 30 deletions

View File

@ -89,7 +89,6 @@ DATATYPES = dict(
) )
#v_integer = pp.Regex(r"[+-]?\d+")\
v_integer = pp.Regex(r"\d+")\ v_integer = pp.Regex(r"\d+")\
.setName("integer")\ .setName("integer")\
.setParseAction(lambda toks: int(toks[0])) .setParseAction(lambda toks: int(toks[0]))
@ -541,24 +540,36 @@ class InjectAt(_Action):
) )
class Code: class Code(_Component):
def __init__(self, code, msg=None): def __init__(self, code):
self.code, self.msg = code, msg self.code = str(code)
if msg is None:
self.msg = ValueLiteral(http_status.RESPONSES.get(self.code, "Unknown code"))
def accept(self, settings, r): def accept(self, settings, r):
r.code = self.code r.code = self
r.msg = self.msg.get_generator(settings)
@classmethod @classmethod
def expr(klass): def expr(klass):
e = v_integer e = v_integer.copy()
e = e + pp.Optional(
Value
)
return e.setParseAction(lambda x: klass(*x)) return e.setParseAction(lambda x: klass(*x))
def values(self, settings):
return [LiteralGenerator(self.code)]
class Reason(_Component):
def __init__(self, value):
self.value = value
def accept(self, settings, r):
r.reason = self
@classmethod
def expr(klass):
e = Value.copy()
return e.setParseAction(lambda x: klass(*x))
def values(self, settings):
return [self.value.get_generator(settings)]
class Message: class Message:
@ -673,8 +684,8 @@ class Message:
# Careful not to log any VALUE specs without sanitizing them first. We truncate at 1k. # Careful not to log any VALUE specs without sanitizing them first. We truncate at 1k.
if hasattr(v, "values"): if hasattr(v, "values"):
v = [x[:TRUNCATE] for x in v.values(settings)] v = [x[:TRUNCATE] for x in v.values(settings)]
v = "".join(v) v = "".join(v).encode("string_escape")
if hasattr(v, "__len__"): elif hasattr(v, "__len__"):
v = v[:TRUNCATE] v = v[:TRUNCATE]
v = v.encode("string_escape") v = v.encode("string_escape")
ret[i] = v ret[i] = v
@ -694,14 +705,21 @@ class Response(Message):
ShortcutLocation, ShortcutLocation,
Raw Raw
) )
logattrs = ["code", "version", "body"] logattrs = ["code", "reason", "version", "body"]
def __init__(self): def __init__(self):
Message.__init__(self) Message.__init__(self)
self.code = None self.code = None
self.msg = None self.reason = None
def preamble(self, settings): def preamble(self, settings):
return [self.version, " ", str(self.code), " ", self.msg] l = [self.version, " "]
l.extend(self.code.values(settings))
l.append(" ")
if self.reason:
l.extend(self.reason.values(settings))
else:
l.append(LiteralGenerator(http_status.RESPONSES.get(int(self.code.code), "Unknown code")))
return l
@classmethod @classmethod
def expr(klass): def expr(klass):
@ -710,16 +728,14 @@ class Response(Message):
resp = pp.And( resp = pp.And(
[ [
Code.expr(), Code.expr(),
pp.Optional(Reason.expr()),
pp.ZeroOrMore(Sep + atom) pp.ZeroOrMore(Sep + atom)
] ]
) )
return resp return resp
def __str__(self): def string(self, settings):
parts = [ return "%s"%self.code
"%s %s"%(self.code, self.msg[:])
]
return "\n".join(parts)
class Request(Message): class Request(Message):
@ -796,7 +812,7 @@ class CraftedResponse(Response):
class PathodErrorResponse(Response): class PathodErrorResponse(Response):
def __init__(self, msg, body=None): def __init__(self, msg, body=None):
Response.__init__(self) Response.__init__(self)
self.code = 800 self.code = Code("800")
self.msg = LiteralGenerator(msg) self.msg = LiteralGenerator(msg)
self.body = Body(ValueLiteral("pathod error: " + (body or msg))) self.body = Body(ValueLiteral("pathod error: " + (body or msg)))
self.headers = [ self.headers = [

View File

@ -182,11 +182,12 @@ class TestMisc:
def test_code(self): def test_code(self):
e = language.Code.expr() e = language.Code.expr()
v = e.parseString("200")[0] v = e.parseString("200")[0]
assert v.code == 200 assert v.string() == "200"
def _test_reason(self):
v = e.parseString("404'msg'")[0] v = e.parseString("404'msg'")[0]
assert v.code == 404 assert v.code.string() == "404"
assert v.msg.val == "msg" assert v.reason == "msg"
r = e.parseString("200'foo'")[0] r = e.parseString("200'foo'")[0]
assert r.msg.val == "foo" assert r.msg.val == "foo"
@ -499,18 +500,23 @@ class TestResponse:
p = tutils.test_data.path("data") p = tutils.test_data.path("data")
d = dict(staticdir=p) d = dict(staticdir=p)
r = language.parse_response(d, "+response") r = language.parse_response(d, "+response")
assert r.code == 202 assert r.code.string() == "202"
def test_response(self): def test_response(self):
r = language.parse_response({}, "400'msg'") r = language.parse_response({}, "400'msg'")
assert r.code == 400 assert r.code.string() == "400"
assert r.msg == "msg" assert r.reason.string() == "msg"
r = language.parse_response({}, "400'msg':b@100b") r = language.parse_response({}, "400'msg':b@100b")
assert r.msg == "msg" assert r.reason.string() == "msg"
assert r.body.values({}) assert r.body.values({})
assert str(r) assert str(r)
r = language.parse_response({}, "200")
assert r.code.string() == "200"
assert not r.reason
assert "OK" in [i[:] for i in r.preamble({})]
def test_render(self): def test_render(self):
s = cStringIO.StringIO() s = cStringIO.StringIO()
r = language.parse_response({}, "400'msg'") r = language.parse_response({}, "400'msg'")