view paraspace/structpath.py @ 34:fe1ebf0c3d40

test get_parent() for structpath.py
author Thinker K.F. Li <thinker@codemud.net>
date Wed, 15 Jun 2011 02:33:54 +0800
parents 9bac21d401fe
children 2f9e7f03dbf7
line wrap: on
line source

##
# 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

    def get_parent(self, obj):
        raise NotImplementedError, 'get_parent() is not implemented'
    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 _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 = [ctx.get_parent(obj)]
    elif _is_class(part):
        class_name = _class_name(part)
        new_objs = ctx.class_instances[class_name]
    else:
        try:
            new_objs = [_obj_attr(obj, part)]
        except AttributeError:
            return []
        pass
    return new_objs


def _handle_path_part(ctx, part):
    from itertools import chain
    
    if not ctx.objs:
        ctx = ctx.__class__([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 = ctx.__class__(objs, ctx)
    return new_ctx


def _handle_path_parts(ctx, path_parts):
    if _is_abs(path_parts):
        ctx = ctx.__class__([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