Exemple #1
0
def test_schema():
    from syn.schema.b.sequence import Sequence
    from syn.type.a import List

    t = Schema(Sequence(1, 2, 3))
    assert t == Schema(Sequence(1, 2, 3))
    assert t != Schema(Sequence(1, 3, 2))
    assert Type.dispatch(t) is t

    assert t.query([1, 2, 3])
    assert not t.query([1, 3, 2])
    t.validate([1, 2, 3])
    assert_raises(TypeError, t.validate, [1, 3, 2])

    assert t.generate() == [1, 2, 3]
    assert t.display() == t.rst() == '<Schema>'
    assert t.coerce(1) == 1

    t = Schema(Sequence(int, float))
    assert t.query([1, 2.3])
    assert not t.query([1, 2])
    val = t.generate()
    assert t.query(val)

    t = Schema(Sequence(int, List(float)))
    assert not t.query([1, 1.2])
    assert not t.query([1, [1, 2]])
    assert t.query([1, [1.2, 3.4]])
    assert t.query([1, []])
    val = t.generate()
    assert t.query(val)
Exemple #2
0
class FunctionDef(Block):
    _opts = dict(args=['name', 'args', 'body', 'decorator_list'])
    _attrs = dict(name=Attr(STR, group=AST),
                  args=Attr(Arguments, groups=(AST, ACO)),
                  decorator_list=OAttr(List(Expression),
                                       groups=(AST, ACO, CC)))

    if VER >= '3':
        _attrs['returns'] = OAttr(Expression, groups=(AST, ACO))
        _opts['args'].append('returns')

    def emit_decorators(self, **kwargs):
        if not self.decorator_list:
            return ''

        pre = self._indent(**kwargs)
        with setitem(kwargs, 'indent_level', 0):
            strs = [
                pre + '@' + dec.emit(**kwargs) for dec in self.decorator_list
            ]
        return '\n'.join(strs) + '\n'

    def emit(self, **kwargs):
        ret = self.emit_decorators(**kwargs)
        head = 'def ' + self.name + '(' + self.args.emit(**kwargs) + ')'
        if VER >= '3':
            if self.returns:
                with setitem(kwargs, 'indent_level', 0):
                    head += ' -> {}'.format(self.returns.emit(**kwargs))
        ret += self.emit_block(head, self.body, **kwargs)
        return ret
Exemple #3
0
class Block(Statement):
    _attrs = dict(
        body=Attr(List((Expression, Statement)), groups=(AST, ACO, CC)))
    _opts = dict(max_len=0)

    def emit_block(self, head, body, **kwargs):
        ret = self._indent(**kwargs)
        ret += head + ':\n'

        level = kwargs.get('indent_level', 0)
        with setitem(kwargs, 'indent_level', level + 1):
            strs = [elem.emit(**kwargs) for elem in body]

        ret += '\n'.join(strs)
        return ret

    def valuify_block(self, body, name, **kwargs):
        child = body[-1]
        if isinstance(child, Assign):
            if name in child.targets:
                return

        if not isinstance(child, Expression):
            child = child.as_value(**kwargs).resolve_progn(**kwargs)
        body[-1] = Assign([name], child)
Exemple #4
0
class Compare(Expression):
    _opts = dict(args=('left', 'ops', 'comparators'))
    _attrs = dict(left=Attr(Expression, groups=(AST, ACO)),
                  ops=Attr(List(Comparator), groups=(AST, ACO, CC)),
                  comparators=Attr(List(Expression), groups=(AST, ACO, CC)))

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            left = self.left.emit(**kwargs)
            ops = [op.emit(**kwargs) for op in self.ops]
            comps = [comp.emit(**kwargs) for comp in self.comparators]

        ret = left
        for op, comp in zip(ops, comps):
            ret += ' {} {}'.format(op, comp)
        ret = '(' + ret + ')'
        ret = self._indent(**kwargs) + ret
        return ret
Exemple #5
0
class Function(SyntagmathonNode):
    _attrs = dict(name=Attr((Variable, STR)),
                  signature=Attr(List(Variable)),
                  body=Attr((List(SyntagmathonNode), tuple)),
                  placeholder=Attr(bool, False))
    _opts = dict(args=('name', 'signature', 'body'))

    def __call__(self, *args_, **kwargs):
        args = {}
        for k, arg in enumerate(args_):
            args[self.signature[k].name] = arg

        for key, value in kwargs.items():
            if key in args:
                raise TypeError("Parameter {} specified twice".format(key))
            args[key] = value

        return Call(self, args)

    def call(self, env, **kwargs):
        return eval(self.body, env, **kwargs)

    def eval(self, env, **kwargs):
        env[self.get_name()] = self
        return self

    def get_name(self):
        return self.name if isinstance(self.name, STR) else self.name.name

    def to_python(self, **kwargs):
        from syn.python.b import Arguments, FunctionDef, Pass

        if VER < '3':
            args = Arguments(
                [to_python(arg, **kwargs) for arg in self.signature])
        else:
            from syn.python.b import Arg
            args = Arguments([Arg(arg.name) for arg in self.signature])

        body = to_python(self.body, **kwargs)
        if not body:
            body = [Pass()]
        body[-1] = body[-1].as_return()
        return FunctionDef(self.name, args, body)
Exemple #6
0
class Import(Statement):
    _attrs = dict(names=Attr(List(Alias), groups=(AST, ACO, CC)))
    _opts = dict(args=('names', ))

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            strs = [val.emit(**kwargs) for val in self.names]
            names = ', '.join(strs)

        ret = self._indent(**kwargs)
        ret += 'import ' + names
        return ret
Exemple #7
0
class Call(Expression):
    _opts = dict(args=['func', 'args', 'keywords'])
    _attrs = dict(func=Attr(Expression, groups=(AST, ACO)),
                  args=OAttr(List(Expression), groups=(AST, ACO, CC)),
                  keywords=OAttr(List(Keyword), groups=(AST, ACO, CC)))

    if VER < '3.5':
        _attrs['starargs'] = OAttr(PythonNode, groups=(AST, ACO))
        _attrs['kwargs'] = OAttr(PythonNode, groups=(AST, ACO))
        _opts['args'].extend(['starargs', 'kwargs'])

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            func = self.func.emit(**kwargs)
            args = [arg.emit(**kwargs)
                    for arg in self.args] if self.args else []
            kwds = [kw.emit(**kwargs)
                    for kw in self.keywords] if self.keywords else []

            if VER < '3.5':
                starargs = self.starargs.emit(
                    **kwargs) if self.starargs else ''
                kwargs_ = self.kwargs.emit(**kwargs) if self.kwargs else ''
            else:
                starargs = ''
                kwargs_ = ''

        strs = []
        ret = self._indent(**kwargs) + func + '('
        if args:
            strs.extend(args)
        if kwds:
            strs.extend(kwds)
        if starargs:
            strs.append('*' + starargs)
        if kwargs_:
            strs.append('**' + kwargs_)
        ret += ', '.join(strs)
        ret += ')'
        return ret
Exemple #8
0
class BoolOp(Expression):
    _opts = dict(args=('op', 'values'))
    _attrs = dict(op=Attr(BooleanOperator, groups=(AST, ACO)),
                  values=Attr(List(Expression), groups=(AST, ACO, CC)))

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            op = ' ' + self.op.emit(**kwargs) + ' '
            vals = [val.emit(**kwargs) for val in self.values]

        ret = op.join(vals)
        ret = '(' + ret + ')'
        ret = self._indent(**kwargs) + ret
        return ret
Exemple #9
0
class Sequence(Literal):
    bounds = ('[', ']')
    delim = ', '
    _opts = dict(args = ('elts',))
    _attrs = dict(elts = Attr(List(Expression), groups=(AST, ACO, CC)))
    
    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            cs = [c.emit(**kwargs) for c in self.elts]
        ret = self.delim.join(cs)
        if len(cs) == 1 and isinstance(self, Tuple):
            ret += ','
        ret = self.bounds[0] + ret + self.bounds[1]
        ret = self._indent(**kwargs) + ret
        return ret
Exemple #10
0
class Env(Base):
    _attrs = dict(frames=Attr(List(Frame), init=lambda self: list([Frame()])))
    _opts = dict(init_validate=True)

    current_frame = property(lambda self: self.frames[-1])

    def __getitem__(self, key):
        return self.current_frame[key]

    def __setitem__(self, key, value):
        self.current_frame[key] = value

    def __delitem__(self, key):
        del self.current_frame[key]

    def __iter__(self):
        return iter(self.current_frame)

    def __len__(self):
        return len(self.current_frame)

    def items(self):
        for item in self.current_frame.items():
            yield item

    def gensym(self):
        pass

    def globals(self):
        return dict(self.current_frame.globals)

    def locals(self):
        return dict(self.current_frame.locals)

    def push(self, dct):
        globs = self.globals()
        globs.update(self.locals())
        self.frames.append(Frame(globals=globs, locals=dct))

    def pop(self):
        return self.frames.pop()

    def set_global(self, key, value):
        self.current_frame.set_global(key, value)

    def update(self, dct):
        self.current_frame.update(dct)
Exemple #11
0
class Assign(Statement):
    _attrs = dict(targets=Attr(List(Expression), groups=(AST, ACO, CC)),
                  value=Attr(Expression, groups=(AST, ACO)))
    _opts = dict(args=('targets', 'value'))

    @logging(AsValue)
    def as_value(self, **kwargs):
        return ProgN(self.copy())

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            targs = [targ.emit(**kwargs) for targ in self.targets]
            val = self.value.emit(**kwargs)

        ret = self._indent(**kwargs)
        ret += ' = '.join(targs)
        ret += ' = ' + val
        return ret
Exemple #12
0
class While(Block):
    _attrs = dict(test=Attr(Expression, groups=(AST, ACO)),
                  orelse=Attr(List((Expression, Statement)),
                              groups=(AST, ACO, CC),
                              init=lambda self: list()))
    _opts = dict(args=('test', 'body', 'orelse'))

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            head = 'while ' + self.test.emit(**kwargs)

        ret = self.emit_block(head, self.body, **kwargs)

        if self.orelse:
            head = 'else'
            block = self.emit_block(head, self.orelse, **kwargs)
            ret += '\n' + block

        return ret
Exemple #13
0
class For(Block):
    _attrs = dict(target=Attr((Name, Tuple, List_), groups=(AST, ACO)),
                  iter=Attr(Expression, groups=(AST, ACO)),
                  orelse=Attr(List((Expression, Statement)),
                              groups=(AST, ACO, CC),
                              init=lambda self: list()))
    _opts = dict(args=('target', 'iter', 'body', 'orelse'))

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            head = 'for {} in {}'.format(self.target.emit(**kwargs),
                                         self.iter.emit(**kwargs))

        ret = self.emit_block(head, self.body, **kwargs)

        if self.orelse:
            head = 'else'
            block = self.emit_block(head, self.orelse, **kwargs)
            ret += '\n' + block

        return ret
Exemple #14
0
    def _harvest_attrs(clsdata):
        getfunc(Harvester._harvest_attrs)(clsdata)

        dct = {}
        clsdct = clsdata['dct']
        attrs = clsdct.get('_attrs', {})
        types = clsdct.get('types', [])
        schema = clsdct.get('schema', None)

        if types and schema:
            raise TypeError(
                'Cannot specify both types and schema in {}'.format(
                    clsdata['clsname']))

        if types:
            dct['_list'] = Attr(List(tuple(types)))
        elif schema:
            dct['_list'] = Attr(Schema(schema))

        preserve_attr_data(attrs, dct)
        attrs.update(dct)
        clsdct['_attrs'] = attrs
Exemple #15
0
class Tree(Base):
    _attrs = dict(
        root=Attr(Node,
                  init=lambda self: Node(),
                  doc="The root node of the tree"),
        nodes=Attr(List(Node),
                   init=lambda self: list(),
                   groups=(GENEX, STREX),
                   doc="List of all tree nodes"),
        node_types=Attr(List(STR),
                        init=lambda self: list(),
                        groups=(GENEX, STREX),
                        doc="List of all tree node types"),
        id_dict=Attr(Dict(Node),
                     init=lambda self: dict(),
                     groups=(GENEX, STREX),
                     doc="Mapping of ids to nodes"),
        type_dict=Attr(Dict(List(Node)),
                       init=lambda self: dict(),
                       groups=(GENEX, STREX),
                       doc="Mapping of type names to node lists"),
        node_counter=Attr(Counter,
                          init=lambda self: Counter(),
                          groups=(EQEX, GENEX, STREX),
                          doc='Node id counter'),
    )
    _opts = dict(init_validate=True, args=('root', ))

    def __init__(self, *args, **kwargs):
        super(Tree, self).__init__(*args, **kwargs)
        self.add_node(self.root)

    def add_node(self, node, **kwargs):
        if node in self.nodes:
            raise TreeError("Node '{}' already in tree; cannot add".format(
                repr(node)))

        def add_node(_node):
            if _node._id is None:
                _node._id = self.node_counter()

            self.id_dict[_node._id] = _node
            self.nodes.append(_node)
            if get_typename(_node) not in self.node_types:
                self.node_types.append(get_typename(_node))
            if get_typename(_node) not in self.type_dict:
                self.type_dict[get_typename(_node)] = []
            self.type_dict[get_typename(_node)].append(_node)

        if node != self.root:
            parent = getitem(kwargs, 'parent', None, True)
            if not parent:
                parent = self.get_node_by_id(
                    getitem(kwargs, 'parent_id', max(self.id_dict)))

            if parent not in self.nodes:
                raise TreeError("Parent node '{}' not in tree".format(
                    repr(parent)))
            parent.add_child(node)

        self.depth_first(node=add_node, current_node=node)

    def remove_node(self, node, **kwargs):
        if node not in self.nodes:
            raise TreeError("Node '{}' not in tree; cannot remove".format(
                repr(node)))

        def remove_node(_node):
            del self.id_dict[_node._id]
            self.nodes.remove(_node)
            self.type_dict[get_typename(_node)].remove(_node)
            if self.type_dict[get_typename(_node)] == []:
                self.node_types.remove(get_typename(_node))
                del self.type_dict[get_typename(_node)]

        if node != self.root:
            parent = node.parent()
            if parent is None:
                raise TreeError("Non-root node '{}' has no parent".format(
                    repr(node)))
            parent.remove_child(node)
        else:
            self.root = None

        self.depth_first(node=remove_node, current_node=node)

    def replace_node(self, source, dest, **kwargs):
        if dest.parent() is not None:
            raise TreeError("Node dest must have no parent")

        parent = source.parent()
        if parent is None:
            if source == self.root:
                self.remove_node(source, **kwargs)
                self.root = dest
                self.add_node(dest, **kwargs)
            else:
                raise TreeError("Non-root node '{}' has no parent".format(
                    repr(source)))
        else:
            self.remove_node(source, **kwargs)
            self.add_node(dest, parent=parent, **kwargs)

    def rebuild(self, **kwargs):
        '''Repopulate the node-tracking data structures.  Shouldn't
        really ever be needed.
        '''
        self.nodes = []
        self.node_types = []
        self.id_dict = {}
        self.type_dict = {}

        self.add_node(self.root)

    def get_node_by_id(self, node_id):
        ret = getitem(self.id_dict, node_id, self._get_node_by_id(node_id),
                      True)
        return ret

    def _get_node_by_id(self, node_id):
        for n in self.nodes:
            if n._id == node_id:
                return n
        return None

    def _check_search_kwarg_types(self, kwargs):
        '''Checks that every element of kwargs is a valid type in this tree.'''
        for key in kwargs:
            if key not in self.node_types:
                raise TypeError("Invalid search type: {}".format(key))

    def depth_first(self,
                    node=do_nothing,
                    stop_test=do_nothing,
                    _return=identity,
                    current_node='root',
                    **kwargs):

        self._check_search_kwarg_types(kwargs)
        if current_node == 'root':
            current_node = self.root

        node(current_node)
        if stop_test(current_node):
            return _return(current_node)

        for nodetype, function in kwargs.items():
            if get_typename(current_node) == nodetype:
                function(current_node)

        for child in current_node.children():
            ret = self.depth_first(node, stop_test, _return, child, **kwargs)
            if ret:
                return ret

    def search_rootward(self,
                        node=do_nothing,
                        stop_test=do_nothing,
                        _return=identity,
                        current_node='root',
                        **kwargs):

        self._check_search_kwarg_types(kwargs)

        if current_node == 'root':
            current_node = self.root

        node(current_node)
        if stop_test(current_node):
            return _return(current_node)

        for nodetype, function in kwargs.items():
            if get_typename(current_node) == nodetype:
                function(current_node)

        if current_node is self.root:
            return

        parent = current_node.parent()
        return self.search_rootward(node, stop_test, _return, parent, **kwargs)

    def query(self, q, context=None):
        if context is None:
            context = self.root

        for x in q(context):
            yield x

    def find_one(self, *args, **kwargs):
        try:
            return first(self.query(*args, **kwargs))
        except StopIteration:
            return None

    def validate(self):
        super(Tree, self).validate()
        self.root.validate()
Exemple #16
0
class SchemaTest(Base):
    _opts = dict(init_validate=True, args=('a', 'b', 'c'))
    _attrs = dict(a=Attr(Schema(Sequence(Range(0, 10), float))),
                  b=Attr(Schema(Sequence(int, List(float)))),
                  c=Attr(Set(Range(5, 8))))
Exemple #17
0
class If(Block):
    _attrs = dict(test=Attr(Expression, groups=(AST, ACO)),
                  orelse=Attr(List((Expression, Statement)),
                              groups=(AST, ACO, CC),
                              init=lambda self: list()))
    _opts = dict(args=('test', 'body', 'orelse'))

    def as_return(self, **kwargs):
        ret = self.copy()
        ret.body[-1] = ret.body[-1].as_return(**kwargs)
        if ret.orelse:
            ret.orelse[-1] = ret.orelse[-1].as_return(**kwargs)
        ret._set_children()
        ret._init()
        return ret

    @logging(AsValue)
    def as_value(self, **kwargs):
        ret = self.copy()

        var = None
        if isinstance(ret.body[-1], Assign):
            var = ret.body[-1].targets[0]
        if var is None and ret.orelse:
            if isinstance(ret.orelse[-1], Assign):
                var = ret.orelse[-1].targets[0]
        if var is None:
            if 'gensym' not in kwargs:
                kwargs['gensym'] = GenSym(ret.variables(**kwargs))
            var = Name(kwargs['gensym'].generate())

        ret.valuify_block(ret.body, var, **kwargs)
        if ret.orelse:
            ret.valuify_block(ret.orelse, var, **kwargs)

        ret._set_children()
        ret._init()
        ret._progn_value = var
        return ProgN(ret)

    def emit(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            head = 'if ' + self.test.emit(**kwargs)

        ret = self.emit_block(head, self.body, **kwargs)

        if self.orelse:
            head = 'else'
            block = self.emit_block(head, self.orelse, **kwargs)
            ret += '\n' + block

        return ret

    @logging(ResolveProgN)
    def resolve_progn(self, **kwargs):
        temp = self.copy()
        temp.body = resolve_progn(temp.body, **kwargs)
        if temp.orelse:
            temp.orelse = resolve_progn(temp.orelse, **kwargs)
        temp._set_children()
        temp._init()
        kwargs['attr_exclude'] = ['body', 'orelse']
        ret = super(If, temp).resolve_progn(**kwargs)
        return ret
Exemple #18
0
class Arguments(PythonNode):
    ast = ast.arguments
    _opts = dict(max_len=0, args=['args', 'vararg', 'kwarg', 'defaults'])
    _attrs = dict(args=Attr(List(Name), groups=(AST, ACO, CC)),
                  vararg=OAttr(STR, group=AST),
                  kwarg=OAttr(STR, group=AST),
                  defaults=Attr(List(Expression),
                                groups=(AST, ACO, CC),
                                init=lambda self: list()))

    if VER >= '3.4':
        _attrs = dict(args=Attr(List(Arg), groups=(AST, ACO, CC)),
                      kwonlyargs=Attr(List(Arg),
                                      groups=(AST, ACO, CC),
                                      init=lambda self: list()),
                      vararg=OAttr(Arg, groups=(AST, ACO)),
                      kwarg=OAttr(Arg, groups=(AST, ACO)),
                      defaults=Attr(List(Expression),
                                    groups=(AST, ACO, CC),
                                    init=lambda self: list()),
                      kw_defaults=Attr(List((Expression, type(None))),
                                       groups=(AST, ACO, CC),
                                       init=lambda self: list()))
        _opts['args'] = [
            'args', 'vararg', 'kwonlyargs', 'kwarg', 'defaults', 'kw_defaults'
        ]

    def emit2(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            n_defs = len(self.defaults)
            N = len(self.args) - n_defs
            strs = [self.args[k].emit(**kwargs) for k in xrange(N)]
            strs += [
                '{}={}'.format(self.args[k + N].emit(**kwargs),
                               self.defaults[k].emit(**kwargs))
                for k in xrange(n_defs)
            ]
            if self.vararg:
                strs.append('*' + self.vararg)
            if self.kwarg:
                strs.append('**' + self.kwarg)

        return ', '.join(strs)

    def emit3(self, **kwargs):
        with setitem(kwargs, 'indent_level', 0):
            n_defs = len(self.defaults)
            N = len(self.args) - n_defs
            strs = [self.args[k].emit(**kwargs) for k in xrange(N)]
            strs += [
                '{}={}'.format(self.args[k + N].emit(**kwargs),
                               self.defaults[k].emit(**kwargs))
                for k in xrange(n_defs)
            ]

            if self.vararg:
                strs.append('*' + self.vararg.emit(**kwargs))

            for kwonly, kwonlydef in zip(self.kwonlyargs, self.kw_defaults):
                if kwonlydef is not None:
                    strs.append('{}={}'.format(kwonly.emit(**kwargs),
                                               kwonlydef.emit(**kwargs)))
                else:
                    strs.append(kwonly.emit(**kwargs))

            if self.kwarg:
                strs.append('**' + self.kwarg.emit(**kwargs))

        return ', '.join(strs)

    def emit(self, **kwargs):
        if VER >= '3':
            return self.emit3(**kwargs)
        return self.emit2(**kwargs)