python API is working

This commit is contained in:
Joao Paulo Magalhaes
2019-03-18 20:17:35 +00:00
parent 9cd460301b
commit d1dd12839a
2 changed files with 271 additions and 89 deletions

View File

@@ -1,73 +1,215 @@
import ryml
print(type(b"fdx").__name__)
print(type(bytes("fdx", "utf8")).__name__)
ryml.fdx_(bytearray("haha", "utf8"))
#ryml.fdxw_(bytearray("haha", "utf8"))
ryml.fdx_(bytes("hehe", "utf8"))
#ryml.fdxw_(bytes("hehe", "utf8"))
ryml.fdx_(b"hihi")
#ryml.fdxw_(b"hihi")
ryml.fdx_(memoryview(b"hoho"))
import unittest
#ryml.fdxw_("hoho")
class SimpleHardcoded:
yaml = "{HELLO: a, foo: b, bar: c, baz: d, seq: [0, 1, 2, 3]}"
def check(self, ut, t):
# some convenient shorthands
eq = ut.assertEqual
fs = ut.assertFalse
tr = ut.assertTrue
#
eq(t.size(), 10)
tr(t.is_root(0))
eq(t.num_children(0), 5)
eq(t.find_child(0, b"HELLO"), 1)
eq(t.find_child(0, b"foo"), 2)
eq(t.find_child(0, b"bar"), 3)
eq(t.find_child(0, b"baz"), 4)
eq(t.find_child(0, b"seq"), 5)
eq(t.parent(0), ryml.NONE)
eq(t.parent(1), 0)
eq(t.parent(2), 0)
eq(t.parent(3), 0)
eq(t.parent(4), 0)
eq(t.parent(5), 0)
fs(t.is_root(1))
fs(t.is_root(2))
fs(t.is_root(3))
fs(t.is_root(4))
fs(t.is_root(5))
fs(t.has_child(0, b"foozzie"))
fs(t.has_child(0, b"bark"))
fs(t.has_child(0, b"bart"))
fs(t.has_child(0, b"bazk"))
eq(t.next_sibling(0), ryml.NONE)
eq(t.prev_sibling(0), ryml.NONE)
eq(t.prev_sibling(1), ryml.NONE)
eq(t.next_sibling(5), ryml.NONE)
tr(t.has_child(0, b"HELLO"))
tr(t.has_child(0, b"foo"))
tr(t.has_child(0, b"bar"))
tr(t.has_child(0, b"baz"))
eq(t.key(1), b"HELLO")
eq(t.key(2), b"foo")
eq(t.key(3), b"bar")
eq(t.key(4), b"baz")
eq(t.val(1), b"a")
eq(t.val(2), b"b")
eq(t.val(3), b"c")
eq(t.val(4), b"d")
tr(t.has_sibling(1, b"bar"))
tr(t.has_sibling(1, b"baz"))
tr(t.has_sibling(2, b"foo"))
tr(t.has_sibling(2, b"baz"))
tr(t.has_sibling(3, b"foo"))
tr(t.has_sibling(3, b"bar"))
for i in (1, 2, 3, 4, 5):
eq(t.find_sibling(i, b"HELLO"), 1)
eq(t.find_sibling(i, b"foo"), 2)
eq(t.find_sibling(i, b"bar"), 3)
eq(t.find_sibling(i, b"baz"), 4)
eq(t.find_sibling(i, b"seq"), 5)
#
num = 0
for id in ryml.children(t):
num += 1
eq(id, num)
eq(num, t.num_children(t.root_id()))
eq(num, t.num_siblings(t.first_child(t.root_id())))
#
num = 0
for id in ryml.siblings(t, 1):
num += 1
eq(id, num)
eq(num, t.num_children(t.root_id()))
eq(num, t.num_siblings(t.first_child(t.root_id())))
num = 0
for id in ryml.siblings(t, 3):
num += 1
eq(id, num)
eq(num, 5)
eq(num, t.num_siblings(t.first_child(t.root_id())))
#
num = 0
for id in ryml.walk(t):
num += 1
if t.is_root(id):
eq(id, 0)
if t.is_map(id):
eq(id, 0)
if t.is_seq(id):
eq(id, 5)
if t.is_keyval(id):
tr(id > 0 and id < 5)
if t.is_val(id):
tr(id > 5)
eq(num, t.size())
def fn(obj, chk, tree):
def log(*args, **kwargs):
print("trying {} [{}]:".format(type(obj).__name__, obj),
*args, **kwargs)
for f in (ryml.parse, ryml.parse_in_situ):
log("-------- with", f.__name__)
try:
r = f(obj)
chk(r)
tree.clear()
tree.clear_arena()
r = f(obj, tree=tree)
assert r is tree
chk(r)
except TypeError as e:
print(e)
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
class _TestBase(unittest.TestCase):
def _setUp(self, case=None):
self.case = case
self.src_as_str = str(case.yaml)
self.src_as_bytes = bytes(case.yaml, "utf8")
self.src_as_bytearray = bytearray(case.yaml, "utf8")
# ----------------------------------------------------------
def _test11_str__ro(self): # cannot read string buffers (or can we?)
with self.assertRaises(TypeError) as context:
ryml.parse(self.src_as_str)
self.assertTrue(type(context.exception), TypeError)
def _test12_str__ro__reuse_tree(self): # cannot read string buffers (or can we?)
with self.assertRaises(TypeError) as context:
t = ryml.Tree()
ryml.parse(self.src_as_str, tree=t)
self.assertTrue(type(context.exception), TypeError)
def _test13_str__rw(self): # cannot mutate string buffers (or can we?)
with self.assertRaises(TypeError) as context:
ryml.parse_in_situ(self.src_as_str)
self.assertTrue(type(context.exception), TypeError)
# ----------------------------------------------------------
def _test21_bytes__ro(self):
tree = ryml.parse(self.src_as_bytes)
self.case.check(self, tree)
def _test22_bytes__ro__reuse_tree(self):
t = ryml.Tree()
r = ryml.parse(self.src_as_bytes, tree=t)
self.assertTrue(r is t)
self.case.check(self, t)
def _test23_bytes__rw(self): # cannot mutate bytes buffers
with self.assertRaises(TypeError) as context:
ryml.parse_in_situ(self.src_as_bytes)
self.assertTrue(type(context.exception), TypeError)
# ----------------------------------------------------------
def _test31_bytearray__ro(self):
tree = ryml.parse(self.src_as_bytearray)
self.case.check(self, tree)
def _test32_bytearray__ro__reuse_tree(self):
t = ryml.Tree()
r = ryml.parse(self.src_as_bytearray, tree=t)
self.assertTrue(r is t)
self.case.check(self, t)
def _test33_bytearray__rw(self): # bytearray buffers are mutable
tree = ryml.parse_in_situ(self.src_as_bytearray)
self.case.check(self, tree)
def _test34_bytearray__rw__reuse_tree(self): # bytearray buffers are mutable
t = ryml.Tree()
r = ryml.parse_in_situ(self.src_as_bytearray, tree=t)
self.assertTrue(r is t)
self.case.check(self, t)
def check(t):
assert t.is_root(0)
assert t.size() == 5
assert t.num_children(0) == 4
assert not t.has_child(0, b"foozzie")
assert not t.has_child(0, b"bark")
assert not t.has_child(0, b"bart")
assert not t.has_child(0, b"bazk")
assert t.has_child(0, b"HELLO")
assert t.has_child(0, b"foo")
assert t.has_child(0, b"bar")
assert t.has_child(0, b"baz")
assert t.has_sibling(1, b"bar")
assert t.has_sibling(1, b"baz")
assert t.has_sibling(2, b"foo")
assert t.has_sibling(2, b"baz")
assert t.has_sibling(3, b"foo")
assert t.has_sibling(3, b"bar")
assert t.find_child(0, b"HELLO") == 1
assert t.find_child(0, b"foo") == 2
assert t.find_child(0, b"bar") == 3
assert t.find_child(0, b"baz") == 4
assert t.parent(1) == 0
assert t.parent(2) == 0
assert t.parent(3) == 0
assert t.parent(4) == 0
for i in (1, 2, 3, 4):
assert t.find_sibling(i, b"HELLO") == 1
assert t.find_sibling(i, b"foo") == 2
assert t.find_sibling(i, b"bar") == 3
assert t.find_sibling(i, b"baz") == 4
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
class TestSimpleHardCoded(_TestBase):
def setUp(self):
_TestBase._setUp(self, SimpleHardcoded())
# ----------------------------------------------------------
def test11_str__ro(self):
super()._test11_str__ro()
def test12_str__ro__reuse_tree(self):
self._test12_str__ro__reuse_tree()
def test13_str__rw(self):
self._test13_str__rw()
# ----------------------------------------------------------
def test21_bytes__ro(self):
self._test21_bytes__ro()
def test22_bytes__ro__reuse_tree(self):
self._test22_bytes__ro__reuse_tree()
def test23_bytes__rw(self):
self._test23_bytes__rw()
# ----------------------------------------------------------
def test31_bytearray__ro(self):
self._test31_bytearray__ro()
def test32_bytearray__ro__reuse_tree(self):
self._test32_bytearray__ro__reuse_tree()
def test33_bytearray__rw(self):
self._test33_bytearray__rw()
def test34_bytearray__rw__reuse_tree(self):
self._test34_bytearray__rw__reuse_tree()
t = ryml.Tree()
yaml = "{HELLO: a, foo: b, bar: c, baz: d}"
fn(yaml, check, t)
fn(bytearray(yaml, "utf8"), check, t)
fn(yaml.encode("utf8"), check, t)
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
if __name__ == "__main__":
unittest.main()

View File

@@ -33,9 +33,6 @@ using csubstr = c4::csubstr;
%}
%typemap(out) c4::csubstr {
}
%typemap(in) c4::substr {
#if defined(SWIGPYTHON)
Py_buffer view;
@@ -84,28 +81,23 @@ using csubstr = c4::csubstr;
};
%typemap(out) c4::csubstr {
#if defined(SWIGPYTHON)
PyObject *obj = PyMemoryView_FromMemory((char*)$1.str, $1.len, PyBUF_READ);
if( ! obj)
{
PyErr_SetString(PyExc_TypeError, "could not get readonly memory from c4::csubstr - have you passed a str?");
SWIG_fail;
}
$result = obj;
#else
#error no "out" typemap defined for this export language
#endif
};
%inline %{
void fdx_(c4::csubstr s)
{
printf("FDX READONLY: s='%.*s'\n", (int)s.len, s.str);
}
void fdxw_(c4::substr s)
{
printf("FDX INPLACE: s='%.*s'\n", (int)s.len, s.str);
}
void fdx(const char *str, size_t len)
{
fdx_(c4::csubstr(str, len));
}
void fdxw(char *str, size_t len)
{
fdxw_(c4::substr(str, len));
}
void parse_csubstr(c4::csubstr s, c4::yml::Tree *t)
{
printf("PARSE READONLY: s=%.*s\n", (int)s.len, s.str);
@@ -126,18 +118,51 @@ void parse_substr(c4::substr s, c4::yml::Tree *t)
%pythoncode %{
def children(tree, node=None):
assert tree is not None
if node is None: node = tree.root_id()
ch = tree.first_child(node)
while ch != NONE:
yield ch
ch = tree.next_sibling(ch)
def siblings(tree, node):
assert tree is not None
if node is None: return
ch = tree.first_sibling(node)
while ch != NONE:
yield ch
ch = tree.next_sibling(ch)
def walk(tree, node=None):
assert tree is not None
if node is None: node = tree.root_id()
yield node
ch = tree.first_child(node)
while ch != NONE:
for gc in walk(tree, ch):
yield gc
ch = tree.next_sibling(ch)
def parse_in_situ(buf, **kwargs):
_check_valid_for_in_situ(buf)
return _call_parse(parse_substr, buf, **kwargs)
def parse(buf, **kwargs):
return _call_parse(parse_csubstr, buf, **kwargs)
def _call_parse(parse_fn, buf, **kwargs):
tree = kwargs.get("tree", Tree())
parse_fn(buf, tree)
return tree
def _check_valid_for_in_situ(obj):
if type(obj) in (str, bytes):
raise TypeError("cannot parse in situ: " + type(obj).__name__)
@@ -149,6 +174,8 @@ def _check_valid_for_in_situ(obj):
namespace c4 {
namespace yml {
constexpr const size_t NONE = (size_t)-1;
typedef enum {
NOTYPE = 0, ///< no type is set
VAL = (1<<0), ///< a leaf node, has a (possibly empty) value
@@ -171,7 +198,6 @@ struct NodeType
NodeType_e type;
NodeType();
NodeType(int t);
NodeType(NodeType_e t);
~NodeType();
@@ -228,6 +254,18 @@ public:
NodeType_e type(size_t node) const;
const char* type_str(size_t node) const;
c4::csubstr key (size_t node) const;
c4::csubstr key_tag (size_t node) const;
c4::csubstr key_ref (size_t node) const;
c4::csubstr key_anchor(size_t node) const;
c4::yml::NodeScalar keysc (size_t node) const;
c4::csubstr val (size_t node) const;
c4::csubstr val_tag (size_t node) const;
c4::csubstr val_ref (size_t node) const;
c4::csubstr val_anchor(size_t node) const;
c4::yml::NodeScalar valsc (size_t node) const;
public:
// node predicates
@@ -272,6 +310,8 @@ public:
// hierarchy getters
size_t root_id() const;
size_t parent(size_t node) const;
size_t prev_sibling(size_t node) const;
size_t next_sibling(size_t node) const;
@@ -343,7 +383,7 @@ public:
void move(size_t node, size_t after);
/** change the node's parent and position */
void move(size_t node, size_t new_parent, size_t after);
void move(size_t node, size_t new_parent, size_t after);
/** change the node's parent and position */
size_t move(Tree * src, size_t node, size_t new_parent, size_t after);