provide fallback parser if YAML not installed

parseTestRecord.py:
- recover from ImportError when YAML not defined
- use monkeyYaml as backup

monkeyYaml.py:
- parser for subset of YAML used in test262 frontmatter

test_monkeyYaml.py:
- unit tests
This commit is contained in:
Sam Mikes 2014-08-28 12:47:58 +01:00
parent 9bd668692e
commit 4f9cec2fa8
3 changed files with 210 additions and 3 deletions

View File

@ -0,0 +1,110 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
# This code provides a fallback parser that can handle the subset of
# YAML used in test262 frontmatter
import re
mYamlKV = re.compile(r"(.*?):(.*)")
mYamlIntDigits = re.compile(r"^[-0-9]*$")
mYamlFloatDigits = re.compile(r"^[-.0-9eE]*$")
mYamlListPattern = re.compile(r"^\[(.*)\]$")
mYamlMultilineList = re.compile(r"^ *- (.*)$")
def load(str):
dict = None
lines = str.split("\n")
while lines:
line = lines.pop(0)
if myIsAllSpaces(line):
continue
result = mYamlKV.match(line)
if result:
if not dict:
dict = {}
key = result.group(1).strip()
value = result.group(2).strip()
(lines, value) = myReadValue(lines, value)
dict[key] = value
else:
raise Exception("monkeyYaml is confused at " + line)
return dict
def myReadValue(lines, value):
if value == ">":
(lines, value) = myMultiline(lines, value)
value = value + "\n"
return (lines, value)
if lines and not value and myMaybeList(lines[0]):
return myMultilineList(lines, value)
else:
return lines, myReadOneLine(value)
def myMaybeList(value):
return mYamlMultilineList.match(value)
def myMultilineList(lines, value):
# assume no explcit indentor (otherwise have to parse value)
value = []
indent = None
while lines:
line = lines.pop(0)
leading = myLeadingSpaces(line)
if myIsAllSpaces(line):
pass
elif leading < indent:
lines.insert(0, line)
break;
else:
indent = indent or leading
value += [myReadOneLine(myRemoveListHeader(indent, line))]
return (lines, value)
def myRemoveListHeader(indent, line):
line = line[indent:]
return mYamlMultilineList.match(line).group(1)
def myReadOneLine(value):
if mYamlListPattern.match(value):
return myFlowList(value)
elif mYamlIntDigits.match(value):
try:
value = int(value)
except ValueError:
pass
elif mYamlFloatDigits.match(value):
try:
value = float(value)
except ValueError:
pass
return value
def myFlowList(value):
result = mYamlListPattern.match(value)
values = result.group(1).split(",")
return [myReadOneLine(v.strip()) for v in values]
def myMultiline(lines, value):
# assume no explcit indentor (otherwise have to parse value)
value = []
indent = 1
while lines:
line = lines.pop(0)
if myIsAllSpaces(line):
value += ["\n"]
elif myLeadingSpaces(line) < indent:
lines.insert(0, line)
break;
else:
value += [line[(indent):]]
value = " ".join(value)
return (lines, value)
def myIsAllSpaces(line):
return len(line.strip()) == 0
def myLeadingSpaces(line):
return len(line) - len(line.lstrip(' '))

View File

@ -17,8 +17,6 @@ import sys
import tempfile
import time
import yaml
# from TestCasePackagerConfig import *
headerPatternStr = r"(?:(?:\s*\/\/.*)?\s*\n)*"
@ -39,6 +37,8 @@ atattrs = re.compile(r"\s*\n\s*\*\s*@")
yamlPattern = re.compile(r"---((?:\s|\S)*)---")
newlinePattern = re.compile(r"\n")
yamlLoad = None
def stripStars(text):
return stars.sub('\n', text).strip()
@ -76,7 +76,8 @@ def oldAttrParser(testRecord, body, name):
def yamlAttrParser(testRecord, attrs, name):
match = yamlPattern.match(attrs)
body = match.group(1)
parsed = yaml.load(body)
importYamlLoad()
parsed = yamlLoad(body)
if (parsed is None):
print "Failed to parse yaml in name %s"%(name)
@ -106,3 +107,14 @@ def parseTestRecord(src, name):
oldAttrParser(testRecord, attrs, name)
return testRecord
def importYamlLoad():
global yamlLoad
if yamlLoad:
return
try:
import yaml
yamlLoad = yaml.load
except ImportError:
import monkeyYaml
yamlLoad = monkeyYaml.load

View File

@ -0,0 +1,85 @@
#!/usr/bin/env python
# Copyright 2014 by Sam Mikes. All rights reserved.
# This code is governed by the BSD license found in the LICENSE file.
import unittest
import os
import yaml
# add parent dir to search path
import sys
sys.path.insert(0, "..")
import monkeyYaml
class TestMonkeyYAMLParsing(unittest.TestCase):
def test_empty(self):
self.assertEqual(monkeyYaml.load(""), yaml.load(""))
def test_newline(self):
self.assertEqual(monkeyYaml.load("\n"), yaml.load("\n"))
def test_oneline(self):
y = "foo: bar"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_twolines(self):
y = "foo: bar\nbaz_bletch : blith:er"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_multiLine(self):
y = "foo: >\n bar\nbaz: 3"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_es5id(self):
y = "es5id: 15.2.3.6-4-102"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_Multiline_1(self):
lines = [" foo"]
value = ">"
y = "\n".join([value] + lines)
(lines, value) = monkeyYaml.myMultiline(lines, value)
self.assertEqual(lines, [])
self.assertEqual(value, yaml.load(y))
def test_Multiline_1(self):
lines = [" foo", " bar"]
value = ">"
y = "\n".join([value] + lines)
(lines, value) = monkeyYaml.myMultiline(lines, value)
self.assertEqual(lines, [])
self.assertEqual(value, yaml.load(y))
def test_myLeading(self):
self.assertEqual(2, monkeyYaml.myLeadingSpaces(" foo"))
self.assertEqual(2, monkeyYaml.myLeadingSpaces(" "))
self.assertEqual(0, monkeyYaml.myLeadingSpaces("\t "))
def test_includes_flow(self):
y = "includes: [a.js,b.js, c_with_wings.js]\n"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_myFlowList_1(self):
y = "[a.js,b.js, c_with_wings.js, 3, 4.12]"
self.assertEqual(monkeyYaml.myFlowList(y), ['a.js', 'b.js', 'c_with_wings.js', 3, 4.12])
def test_multiline_list_1(self):
y = "foo:\n - bar\n - baz"
self.assertEqual(monkeyYaml.load(y), yaml.load(y))
def test_mulineline_list2(self):
self.assertEqual(monkeyYaml.myRemoveListHeader(2, " - foo"), "foo")
def test_mulineline_list3(self):
(lines, value) = monkeyYaml.myMultilineList([" - foo", " - bar", "baz: bletch"], "")
self.assertEqual(lines, ["baz: bletch"])
self.assertEqual(value, ["foo", "bar"])
if __name__ == '__main__':
unittest.main()