diff options
-rw-r--r-- | libpathod/language/actions.py | 8 | ||||
-rw-r--r-- | libpathod/language/base.py | 79 | ||||
-rw-r--r-- | libpathod/language/http.py | 40 | ||||
-rw-r--r-- | test/test_language_base.py | 90 | ||||
-rw-r--r-- | test/test_language_http.py | 2 |
5 files changed, 91 insertions, 128 deletions
diff --git a/libpathod/language/actions.py b/libpathod/language/actions.py index 27bbd3d2..e86394a0 100644 --- a/libpathod/language/actions.py +++ b/libpathod/language/actions.py @@ -52,7 +52,7 @@ class PauseAt(_Action): @classmethod def expr(klass): e = pp.Literal("p").suppress() - e += base.Offset + e += base.TokOffset e += pp.Literal(",").suppress() e += pp.MatchFirst( [ @@ -79,7 +79,7 @@ class DisconnectAt(_Action): @classmethod def expr(klass): e = pp.Literal("d").suppress() - e += base.Offset + e += base.TokOffset return e.setParseAction(lambda x: klass(*x)) def spec(self): @@ -100,9 +100,9 @@ class InjectAt(_Action): @classmethod def expr(klass): e = pp.Literal("i").suppress() - e += base.Offset + e += base.TokOffset e += pp.Literal(",").suppress() - e += base.Value + e += base.TokValue return e.setParseAction(lambda x: klass(*x)) def spec(self): diff --git a/libpathod/language/base.py b/libpathod/language/base.py index c473a6a8..d80eec99 100644 --- a/libpathod/language/base.py +++ b/libpathod/language/base.py @@ -40,7 +40,9 @@ v_naked_literal = pp.MatchFirst( class Token(object): """ - A specification token. Tokens are immutable. + A token in the specification language. Tokens are immutable. The token + classes have no meaning in and of themselves, and are combined into + Components and Actions to build the language. """ __metaclass__ = abc.ABCMeta @@ -72,7 +74,7 @@ class Token(object): return self.spec() -class _ValueLiteral(Token): +class _TokValueLiteral(Token): def __init__(self, val): self.val = val.decode("string_escape") @@ -83,7 +85,7 @@ class _ValueLiteral(Token): return self -class ValueLiteral(_ValueLiteral): +class TokValueLiteral(_TokValueLiteral): """ A literal with Python-style string escaping """ @@ -103,7 +105,7 @@ class ValueLiteral(_ValueLiteral): return "'" + inner + "'" -class ValueNakedLiteral(_ValueLiteral): +class TokValueNakedLiteral(_TokValueLiteral): @classmethod def expr(klass): e = v_naked_literal.copy() @@ -113,7 +115,7 @@ class ValueNakedLiteral(_ValueLiteral): return self.val.encode("string_escape") -class ValueGenerate(Token): +class TokValueGenerate(Token): def __init__(self, usize, unit, datatype): if not unit: unit = "b" @@ -127,7 +129,7 @@ class ValueGenerate(Token): def freeze(self, settings): g = self.get_generator(settings) - return ValueLiteral(g[:].encode("string_escape")) + return TokValueLiteral(g[:].encode("string_escape")) @classmethod def expr(klass): @@ -156,7 +158,7 @@ class ValueGenerate(Token): return s -class ValueFile(Token): +class TokValueFile(Token): def __init__(self, path): self.path = str(path) @@ -189,26 +191,26 @@ class ValueFile(Token): return "<'%s'"%self.path.encode("string_escape") -Value = pp.MatchFirst( +TokValue = pp.MatchFirst( [ - ValueGenerate.expr(), - ValueFile.expr(), - ValueLiteral.expr() + TokValueGenerate.expr(), + TokValueFile.expr(), + TokValueLiteral.expr() ] ) -NakedValue = pp.MatchFirst( +TokNakedValue = pp.MatchFirst( [ - ValueGenerate.expr(), - ValueFile.expr(), - ValueLiteral.expr(), - ValueNakedLiteral.expr(), + TokValueGenerate.expr(), + TokValueFile.expr(), + TokValueLiteral.expr(), + TokValueNakedLiteral.expr(), ] ) -Offset = pp.MatchFirst( +TokOffset = pp.MatchFirst( [ v_integer, pp.Literal("r"), @@ -247,9 +249,9 @@ class KeyValue(_Component): @classmethod def expr(klass): e = pp.Literal(klass.preamble).suppress() - e += Value + e += TokValue e += pp.Literal("=").suppress() - e += Value + e += TokValue return e.setParseAction(lambda x: klass(*x)) def spec(self): @@ -295,7 +297,7 @@ class OptionsOrValue(_Component): # string value literal. self.option_used = False if isinstance(value, basestring): - value = ValueLiteral(value.upper()) + value = TokValueLiteral(value.upper()) self.option_used = True self.value = value @@ -303,7 +305,7 @@ class OptionsOrValue(_Component): def expr(klass): parts = [pp.CaselessLiteral(i) for i in klass.options] m = pp.MatchFirst(parts) - spec = m | Value.copy() + spec = m | TokValue.copy() spec = spec.setParseAction(lambda x: klass(*x)) if klass.preamble: spec = pp.Literal(klass.preamble).suppress() + spec @@ -345,15 +347,18 @@ class Integer(_Component): class PreValue(_Component): """ - A value lead by self.preamble. + A value component lead by an optional preamble. """ + preamble = "" + def __init__(self, value): self.value = value @classmethod def expr(klass): - e = pp.Literal(klass.preamble).suppress() - e = e + Value + e = (TokValue | TokNakedValue) + if klass.preamble: + e = pp.Literal(klass.preamble).suppress() + e return e.setParseAction(lambda x: klass(*x)) def values(self, settings): @@ -364,29 +369,3 @@ class PreValue(_Component): def freeze(self, settings): return self.__class__(self.value.freeze(settings)) - - -class SimpleValue(_Component): - """ - A simple value - i.e. one without a preface. - """ - def __init__(self, value): - if isinstance(value, basestring): - value = ValueLiteral(value) - self.value = value - - @classmethod - def expr(klass): - e = Value | NakedValue - return e.setParseAction(lambda x: klass(*x)) - - def values(self, settings): - return [ - self.value.get_generator(settings), - ] - - def spec(self): - return "%s"%(self.value.spec()) - - def freeze(self, settings): - return self.__class__(self.value.freeze(settings)) diff --git a/libpathod/language/http.py b/libpathod/language/http.py index eb671d16..800d9f08 100644 --- a/libpathod/language/http.py +++ b/libpathod/language/http.py @@ -16,7 +16,7 @@ class Raw(base.CaselessLiteral): TOK = "r" -class Path(base.SimpleValue): +class Path(base.PreValue): pass @@ -62,18 +62,18 @@ class Header(_HeaderMixin, base.KeyValue): class ShortcutContentType(_HeaderMixin, base.PreValue): preamble = "c" - key = base.ValueLiteral("Content-Type") + key = base.TokValueLiteral("Content-Type") class ShortcutLocation(_HeaderMixin, base.PreValue): preamble = "l" - key = base.ValueLiteral("Location") + key = base.TokValueLiteral("Location") class ShortcutUserAgent(_HeaderMixin, base.OptionsOrValue): preamble = "u" options = [i[1] for i in http_uastrings.UASTRINGS] - key = base.ValueLiteral("User-Agent") + key = base.TokValueLiteral("User-Agent") def values(self, settings): if self.option_used: @@ -104,7 +104,7 @@ class PathodResponse(base.Token): @classmethod def expr(klass): e = pp.Literal("s").suppress() - e = e + base.ValueLiteral.expr() + e = e + base.TokValueLiteral.expr() return e.setParseAction(lambda x: klass(*x)) def values(self, settings): @@ -117,7 +117,7 @@ class PathodResponse(base.Token): def freeze(self, settings): f = self.parsed.freeze(settings).spec() - return PathodResponse(base.ValueLiteral(f.encode("string_escape"))) + return PathodResponse(base.TokValueLiteral(f.encode("string_escape"))) def get_header(val, headers): @@ -227,8 +227,8 @@ class Response(_HTTPMessage): if not get_header(i[0], self.headers): tokens.append( Header( - base.ValueLiteral(i[0]), - base.ValueLiteral(i[1])) + base.TokValueLiteral(i[0]), + base.TokValueLiteral(i[1])) ) if not self.raw: if not get_header("Content-Length", self.headers): @@ -240,8 +240,8 @@ class Response(_HTTPMessage): ) tokens.append( Header( - base.ValueLiteral("Content-Length"), - base.ValueLiteral(str(length)), + base.TokValueLiteral("Content-Length"), + base.TokValueLiteral(str(length)), ) ) intermediate = self.__class__(tokens) @@ -326,8 +326,8 @@ class Request(_HTTPMessage): if not get_header(i[0], self.headers): tokens.append( Header( - base.ValueLiteral(i[0]), - base.ValueLiteral(i[1]) + base.TokValueLiteral(i[0]), + base.TokValueLiteral(i[1]) ) ) if not self.raw: @@ -338,16 +338,16 @@ class Request(_HTTPMessage): ) tokens.append( Header( - base.ValueLiteral("Content-Length"), - base.ValueLiteral(str(length)), + base.TokValueLiteral("Content-Length"), + base.TokValueLiteral(str(length)), ) ) if settings.request_host: if not get_header("Host", self.headers): tokens.append( Header( - base.ValueLiteral("Host"), - base.ValueLiteral(settings.request_host) + base.TokValueLiteral("Host"), + base.TokValueLiteral(settings.request_host) ) ) intermediate = self.__class__(tokens) @@ -389,10 +389,10 @@ def make_error_response(reason, body=None): tokens = [ Code("800"), Header( - base.ValueLiteral("Content-Type"), - base.ValueLiteral("text/plain") + base.TokValueLiteral("Content-Type"), + base.TokValueLiteral("text/plain") ), - Reason(base.ValueLiteral(reason)), - Body(base.ValueLiteral("pathod error: " + (body or reason))), + Reason(base.TokValueLiteral(reason)), + Body(base.TokValueLiteral("pathod error: " + (body or reason))), ] return PathodErrorResponse(tokens) diff --git a/test/test_language_base.py b/test/test_language_base.py index 04b37b1f..56e7bbd4 100644 --- a/test/test_language_base.py +++ b/test/test_language_base.py @@ -17,43 +17,43 @@ def test_caseless_literal(): assert v.values(language.Settings()) -class TestValueNakedLiteral: +class TestTokValueNakedLiteral: def test_expr(self): - v = base.ValueNakedLiteral("foo") + v = base.TokValueNakedLiteral("foo") assert v.expr() def test_spec(self): - v = base.ValueNakedLiteral("foo") + v = base.TokValueNakedLiteral("foo") assert v.spec() == repr(v) == "foo" - v = base.ValueNakedLiteral("f\x00oo") + v = base.TokValueNakedLiteral("f\x00oo") assert v.spec() == repr(v) == r"f\x00oo" -class TestValueLiteral: +class TestTokValueLiteral: def test_espr(self): - v = base.ValueLiteral("foo") + v = base.TokValueLiteral("foo") assert v.expr() assert v.val == "foo" - v = base.ValueLiteral("foo\n") + v = base.TokValueLiteral("foo\n") assert v.expr() assert v.val == "foo\n" assert repr(v) def test_spec(self): - v = base.ValueLiteral("foo") + v = base.TokValueLiteral("foo") assert v.spec() == r"'foo'" - v = base.ValueLiteral("f\x00oo") + v = base.TokValueLiteral("f\x00oo") assert v.spec() == repr(v) == r"'f\x00oo'" - v = base.ValueLiteral("\"") + v = base.TokValueLiteral("\"") assert v.spec() == repr(v) == '\'"\'' def roundtrip(self, spec): - e = base.ValueLiteral.expr() - v = base.ValueLiteral(spec) + e = base.TokValueLiteral.expr() + v = base.TokValueLiteral(spec) v2 = e.parseString(v.spec()) nt.assert_equal(v.val, v2[0].val) nt.assert_equal(v.spec(), v2[0].spec()) @@ -68,58 +68,58 @@ class TestValueLiteral: self.roundtrip("\a") -class TestValueGenerate: +class TestTokValueGenerate: def test_basic(self): - v = base.Value.parseString("@10b")[0] + v = base.TokValue.parseString("@10b")[0] assert v.usize == 10 assert v.unit == "b" assert v.bytes() == 10 - v = base.Value.parseString("@10")[0] + v = base.TokValue.parseString("@10")[0] assert v.unit == "b" - v = base.Value.parseString("@10k")[0] + v = base.TokValue.parseString("@10k")[0] assert v.bytes() == 10240 - v = base.Value.parseString("@10g")[0] + v = base.TokValue.parseString("@10g")[0] assert v.bytes() == 1024**3 * 10 - v = base.Value.parseString("@10g,digits")[0] + v = base.TokValue.parseString("@10g,digits")[0] assert v.datatype == "digits" g = v.get_generator({}) assert g[:100] - v = base.Value.parseString("@10,digits")[0] + v = base.TokValue.parseString("@10,digits")[0] assert v.unit == "b" assert v.datatype == "digits" def test_spec(self): - v = base.ValueGenerate(1, "b", "bytes") + v = base.TokValueGenerate(1, "b", "bytes") assert v.spec() == repr(v) == "@1" - v = base.ValueGenerate(1, "k", "bytes") + v = base.TokValueGenerate(1, "k", "bytes") assert v.spec() == repr(v) == "@1k" - v = base.ValueGenerate(1, "k", "ascii") + v = base.TokValueGenerate(1, "k", "ascii") assert v.spec() == repr(v) == "@1k,ascii" - v = base.ValueGenerate(1, "b", "ascii") + v = base.TokValueGenerate(1, "b", "ascii") assert v.spec() == repr(v) == "@1,ascii" def test_freeze(self): - v = base.ValueGenerate(100, "b", "ascii") + v = base.TokValueGenerate(100, "b", "ascii") f = v.freeze(language.Settings()) assert len(f.val) == 100 -class TestValueFile: +class TestTokValueFile: def test_file_value(self): - v = base.Value.parseString("<'one two'")[0] + v = base.TokValue.parseString("<'one two'")[0] assert str(v) assert v.path == "one two" - v = base.Value.parseString("<path")[0] + v = base.TokValue.parseString("<path")[0] assert v.path == "path" def test_access_control(self): - v = base.Value.parseString("<path")[0] + v = base.TokValue.parseString("<path")[0] with tutils.tmpdir() as t: p = os.path.join(t, "path") with open(p, "wb") as f: @@ -127,7 +127,7 @@ class TestValueFile: assert v.get_generator(language.Settings(staticdir=t)) - v = base.Value.parseString("<path2")[0] + v = base.TokValue.parseString("<path2")[0] tutils.raises( exceptions.FileAccessDenied, v.get_generator, @@ -139,7 +139,7 @@ class TestValueFile: language.Settings() ) - v = base.Value.parseString("</outside")[0] + v = base.TokValue.parseString("</outside")[0] tutils.raises( "outside", v.get_generator, @@ -147,42 +147,26 @@ class TestValueFile: ) def test_spec(self): - v = base.Value.parseString("<'one two'")[0] - v2 = base.Value.parseString(v.spec())[0] + v = base.TokValue.parseString("<'one two'")[0] + v2 = base.TokValue.parseString(v.spec())[0] assert v2.path == "one two" def test_freeze(self): - v = base.Value.parseString("<'one two'")[0] + v = base.TokValue.parseString("<'one two'")[0] v2 = v.freeze({}) assert v2.path == v.path class TestMisc: def test_generators(self): - v = base.Value.parseString("'val'")[0] + v = base.TokValue.parseString("'val'")[0] g = v.get_generator({}) assert g[:] == "val" def test_value(self): - assert base.Value.parseString("'val'")[0].val == "val" - assert base.Value.parseString('"val"')[0].val == "val" - assert base.Value.parseString('"\'val\'"')[0].val == "'val'" - - def test_simplevalue(self): - e = base.SimpleValue.expr() - assert e.parseString('"/foo"')[0].value.val == "/foo" - - v = base.SimpleValue("/foo") - assert v.value.val == "/foo" - - v = e.parseString("@100")[0] - v2 = v.freeze({}) - v3 = v2.freeze({}) - assert v2.value.val == v3.value.val - assert len(v2.value.val) == 100 - - s = v.spec() - assert s == v.expr().parseString(s)[0].spec() + assert base.TokValue.parseString("'val'")[0].val == "val" + assert base.TokValue.parseString('"val"')[0].val == "val" + assert base.TokValue.parseString('"\'val\'"')[0].val == "'val'" def test_prevalue(self): class TT(base.PreValue): diff --git a/test/test_language_http.py b/test/test_language_http.py index 839c02b3..e9e91922 100644 --- a/test/test_language_http.py +++ b/test/test_language_http.py @@ -340,7 +340,7 @@ def test_pathodspec(): def test_pathodspec_freeze(): e = http.PathodResponse( - base.ValueLiteral( + base.TokValueLiteral( "200:b'foo':i10,'\\x27'".encode( "string_escape" ) |