aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libpathod/language/actions.py8
-rw-r--r--libpathod/language/base.py79
-rw-r--r--libpathod/language/http.py40
-rw-r--r--test/test_language_base.py90
-rw-r--r--test/test_language_http.py2
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"
)