# HG changeset patch # User Thinker K.F. Li # Date 1308071375 -28800 # Node ID aed662c820d884705a66c31ac5d16b2ca769ea64 # Parent e790c6b2d5d9428f3ff16140242e3a11c93e5aba xpath like query structpath.py diff -r e790c6b2d5d9 -r aed662c820d8 paraspace/structpath.py --- /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 diff -r e790c6b2d5d9 -r aed662c820d8 paraspace/tests/structpath_test.py --- /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