changeset 31:aed662c820d8

xpath like query structpath.py
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 15 Jun 2011 01:09:35 +0800
parents e790c6b2d5d9
children 9bac21d401fe
files paraspace/structpath.py paraspace/tests/structpath_test.py
diffstat 2 files changed, 179 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/paraspace/structpath.py	Wed Jun 15 01:09:35 2011 +0800
@@ -0,0 +1,108 @@
+##
+# Implement a xpath liked query language.
+#
+class context(object):
+    all_classes = None
+    class_instances = None
+    root = None
+    objs = None
+
+    def __init__(self, objs, ctx=None):
+        if ctx:
+            self.all_classes = ctx.all_classes
+            self.class_instances = ctx.class_instances
+            self.root = ctx.root
+            pass
+        self.objs = objs
+        pass
+    pass
+
+
+def _path_split(path):
+    parts = [p.strip()
+             for p in path.split('/')]
+    return parts
+
+
+def _is_abs(path_parts):
+    if len(path_parts) == 0:
+        return False
+    return path_parts[0] == ''
+
+
+def _rel_of_abs(path_parts):
+    return path_parts[1:]
+
+
+def _is_class(part):
+    return part.startswith('.')
+        
+
+def _class_name(part):
+    return part[1:]
+
+
+def _is_parent_name(part):
+    return part == '..'
+
+
+def _get_parent(obj):
+    raise NotImplementedError, '_get_parent() is not implemented'
+
+
+def _obj_attr(obj, attrname):
+    if isinstance(obj, list):
+        idx = int(attrname)
+        return obj[idx]
+    elif isinstance(obj, dict):
+        key = eval(attrname)
+        return obj[key]
+    return getattr(obj, attrname)
+
+
+def _handle_path_part_obj(ctx, part, obj):
+    if _is_parent_name(part):
+        new_objs = [_get_parent(obj)]
+    elif _is_class(part):
+        class_name = _class_name(part)
+        new_objs = ctx.class_instances[class_name]
+    else:
+        new_objs = [_obj_attr(obj, part)]
+        pass
+    return new_objs
+
+
+def _handle_path_part(ctx, part):
+    from itertools import chain
+    
+    if not ctx.objs:
+        ctx = context([ctx.root], ctx)
+        pass
+
+    objss = [_handle_path_part_obj(ctx, part, obj)
+             for obj in ctx.objs]
+    objs = [o for o in chain(*objss)]
+    new_ctx = context(objs, ctx)
+    return new_ctx
+
+
+def _handle_path_parts(ctx, path_parts):
+    if _is_abs(path_parts):
+        ctx = context([ctx.root], ctx)
+        path_parts = _rel_of_abs(path_parts)
+        pass
+
+    if len(path_parts) == 1 and path_parts[0] == '':
+        return ctx
+    
+    for path_part in path_parts:
+        ctx = _handle_path_part(ctx, path_part)
+        pass
+    
+    return ctx
+
+
+def find_objs_path(ctx, path):
+    path_parts = _path_split(path)
+    rctx = _handle_path_parts(ctx, path_parts)
+    return rctx.objs
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/paraspace/tests/structpath_test.py	Wed Jun 15 01:09:35 2011 +0800
@@ -0,0 +1,71 @@
+from paraspace import structpath
+
+
+class car(object):
+    pass
+
+
+class wheel(object):
+    pass
+
+
+class handle(object):
+    pass
+
+
+def _build_car():
+    ctx = structpath.context(None)
+    ctx.root = car()
+    root = ctx.root
+
+    root.wheels = [wheel(), wheel(), wheel(), wheel()]
+    root.handle = handle()
+
+    ctx.all_classes = {'car': car, 'wheel': wheel, 'handle': handle}
+    ctx.class_instances = {
+        'car': [root],
+        'wheel': root.wheels,
+        'handle': [root.handle]
+        }
+    return ctx
+
+
+def structpath_abs_test():
+    car_ctx = _build_car()
+    
+    a_wheel = structpath.find_objs_path(car_ctx, '/wheels/1')[0]
+    assert a_wheel is car_ctx.root.wheels[1]
+
+    a_handle = structpath.find_objs_path(car_ctx, '/handle')[0]
+    assert a_handle is car_ctx.root.handle
+    
+    a_car = structpath.find_objs_path(car_ctx, '/')[0]
+    assert a_car is car_ctx.root
+    pass
+
+
+def structpath_class_test():
+    car_ctx = _build_car()
+    root = car_ctx.root
+
+    wheels = structpath.find_objs_path(car_ctx, '.wheel')
+    assert len(wheels) == 4
+    assert root.wheels[0] in wheels
+    assert root.wheels[1] in wheels
+    assert root.wheels[2] in wheels
+    assert root.wheels[3] in wheels
+
+    handles = structpath.find_objs_path(car_ctx, '.car/handle')
+    assert len(handles) == 1
+    a_handle = handles[0]
+    assert a_handle is car_ctx.root.handle
+
+    wheelss = structpath.find_objs_path(car_ctx, '.car/wheels')
+    assert len(wheelss) == 1
+    wheels = wheelss[0]
+    assert len(wheels) == 4
+    assert root.wheels[0] in wheels
+    assert root.wheels[1] in wheels
+    assert root.wheels[2] in wheels
+    assert root.wheels[3] in wheels
+    pass