mirror of
https://github.com/biojppm/rapidyaml.git
synced 2026-01-18 21:41:18 +01:00
python API is working
This commit is contained in:
@@ -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()
|
||||
|
||||
90
api/ryml.i
90
api/ryml.i
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user