Example #1
0
File: tree.py Project: fspaolo/code
def tree_embeds(t, u, leaves=()):
    ''' ...

        >>> tree_embeds([1], [2])
        True
        >>> tree_embeds([1], [1,2])
        False
        >>> tree_embeds([1], [[1,2]])
        True
        >>> tree_embeds([1,[2,3]], [[True, False], 'ab'])
        True
        >>> tree_embeds([1,[2,3]], [[True, False], 'ab'], leaves=(str,))
        False
        >>> tree_embeds([], [1,2,3])
        False
        >>> tree_embeds(1, [1,2,3])
        True
    '''
    # Pass leaf types around, avoiding infinite regress on strings
    _is_fork = partial(is_fork, leaves=leaves)
    if isinstance(t, basestring) or isinstance(u, basestring):
        leaves += (basestring,)
    _tree_embeds = partial(tree_embeds, leaves=leaves)

    if not _is_fork(t):
        return True
    else:
        return (_is_fork(u) and len(list(t)) == len(list(u)) and
                all(_tree_embeds(n,m) for n,m in zip(t,u)))
Example #2
0
    def visitTryExcept(self, node):

        # If we are code after a 'try' block, then it either succeeded or
        # handled its own exception. So either the 'try' and 'else' blocks ran,
        # or some of the 'try' and one of the handlers ran. If we treat the
        # 'try' and 'else' blocks as one, then we can say that
        # 'try'/'except'/'else' produces unconditional locals when the same
        # name is local to 'try'/'else' and every handler. All other bindings
        # are conditional.

        # Visit children
        body_v = walk([node.body, node.else_], NameFinder())
        # (A handler is (type, name, body) where 'type' and 'name' can be None)
        handler_vs = [ walk(h, NameFinder()) for h in node.handlers ]
        assert all(not v.conditional_locals for v in handler_vs)

        # Free names come from 'try', 'else', and names in 'except' that aren't
        # bound by the exception name. Since 'handlers' bundles each 'except'
        # body with its exception name, the bindings are already computed.
        self._see_unbound(body_v.free | union(v.free for v in handler_vs))

        # Unconditional locals only come from locals in both the 'try'/'else'
        # body and every 'except' body. All other locals are conditional.
        locals = body_v.locals & intersect(v.locals for v in handler_vs)
        conditional_locals = \
            (body_v.all_locals() | union(v.all_locals() for v in handler_vs)) \
                - locals

        self._bind(locals)
        self._bind_conditional(conditional_locals)
Example #3
0
def tree_embeds(t, u, leaves=()):
    ''' ...

        >>> tree_embeds([1], [2])
        True
        >>> tree_embeds([1], [1,2])
        False
        >>> tree_embeds([1], [[1,2]])
        True
        >>> tree_embeds([1,[2,3]], [[True, False], 'ab'])
        True
        >>> tree_embeds([1,[2,3]], [[True, False], 'ab'], leaves=(str,))
        False
        >>> tree_embeds([], [1,2,3])
        False
        >>> tree_embeds(1, [1,2,3])
        True
    '''
    # Pass leaf types around, avoiding infinite regress on strings
    _is_fork = partial(is_fork, leaves=leaves)
    if isinstance(t, basestring) or isinstance(u, basestring):
        leaves += (basestring, )
    _tree_embeds = partial(tree_embeds, leaves=leaves)

    if not _is_fork(t):
        return True
    else:
        return (_is_fork(u) and len(list(t)) == len(list(u))
                and all(_tree_embeds(n, m) for n, m in zip(t, u)))
Example #4
0
def is_const(ast):
    ''' Whether an AST represents a constant expression.

        I'm not sure what "constant" means yet, but here are some examples:

            >>> all(is_const(parse(s, mode='eval')) for s in (
            ...     '0',
            ...     'True',
            ...     'None',
            ...     '"foo"',
            ...     '[1,2]',
            ...     '(False, [])',
            ...     '{"a": 1}',
            ...     '{"a": 0, (True, False): [None, 3, "fish", ()]}',
            ... ))
            True

        And some non-examples, some of which maybe should be reclassified:

            >>> any(is_const(parse(s, mode='eval')) for s in (
            ...     '0+1',
            ...     '~8',
            ...     '0 < 1',
            ...     'not True',
            ...     '"fo%s" % "o"',
            ...     'len([1,2])',
            ...     '[1,2][0]',
            ...     '[1,a]',
            ...     '[a for a in [1,2]]',
            ...     '{"a": 0}.keys()',
            ...     'set()',
            ...     'list()',
            ...     'dict()',
            ...     'dict',
            ...     'lambda: 3',
            ...     'lambda a: a',
            ... ))
            False
    '''
    return (
        isinstance(ast, Const) or
        isinstance(ast, Name) and ast.name in ['None', 'True', 'False'] or
        isinstance(ast, (List, Tuple, Dict)) and all(map(is_const, ast)) or
        isinstance(ast, Expression) and is_const(ast.node)
    )
Example #5
0
File: tree.py Project: fspaolo/code
def tree_zip(*trees, **kw):
    ''' Zip recursively.

        Returns nested lists with tuples at the bottom.

        >>> tree_zip([1,[2,3]], [5,[6,7]])
        [(1, 5), [(2, 6), (3, 7)]]
        >>> tree_zip([1,[2,3]], [5,[6,7]], ['a',['b','c']])
        [(1, 5, 'a'), [(2, 6, 'b'), (3, 7, 'c')]]

        >>> tree_zip('foo', 'bar')
        [('f', 'b'), ('o', 'a'), ('o', 'r')]
        >>> tree_zip(['foo'], ['bar'])
        [[('f', 'b'), ('o', 'a'), ('o', 'r')]]
        >>> tree_zip(['foo'], ['bar'], leaves=(str,))
        [('foo', 'bar')]
        >>> tree_zip('foo', ['bar'])
        [('f', 'bar')]
        >>> tree_zip('foo', ['bar'], leaves=(str,))
        ('foo', ['bar'])
        >>> tree_zip(1, 2)
        (1, 2)

        >>> tree_zip([1,[2,3]], [5,6,7,8], [['a','b'],['c','d']])
        [(1, 5, ['a', 'b']), ([2, 3], 6, ['c', 'd'])]
    '''
    # (Default arguments)
    leaves = kw.get('leaves', ())

    # Pass leaf types around, avoiding infinite regress on strings
    _is_fork = partial(is_fork, leaves=leaves)
    if any(isinstance(t, basestring) for t in trees):
        leaves += (basestring,)
    _tree_zip = partial(tree_zip, leaves=leaves)

    if not all(_is_fork(t) for t in trees):
        return trees
    else:
        return [ _tree_zip(*neighbors) for neighbors in zip(*trees) ]
Example #6
0
def tree_zip(*trees, **kw):
    ''' Zip recursively.

        Returns nested lists with tuples at the bottom.

        >>> tree_zip([1,[2,3]], [5,[6,7]])
        [(1, 5), [(2, 6), (3, 7)]]
        >>> tree_zip([1,[2,3]], [5,[6,7]], ['a',['b','c']])
        [(1, 5, 'a'), [(2, 6, 'b'), (3, 7, 'c')]]

        >>> tree_zip('foo', 'bar')
        [('f', 'b'), ('o', 'a'), ('o', 'r')]
        >>> tree_zip(['foo'], ['bar'])
        [[('f', 'b'), ('o', 'a'), ('o', 'r')]]
        >>> tree_zip(['foo'], ['bar'], leaves=(str,))
        [('foo', 'bar')]
        >>> tree_zip('foo', ['bar'])
        [('f', 'bar')]
        >>> tree_zip('foo', ['bar'], leaves=(str,))
        ('foo', ['bar'])
        >>> tree_zip(1, 2)
        (1, 2)

        >>> tree_zip([1,[2,3]], [5,6,7,8], [['a','b'],['c','d']])
        [(1, 5, ['a', 'b']), ([2, 3], 6, ['c', 'd'])]
    '''
    # (Default arguments)
    leaves = kw.get('leaves', ())

    # Pass leaf types around, avoiding infinite regress on strings
    _is_fork = partial(is_fork, leaves=leaves)
    if any(isinstance(t, basestring) for t in trees):
        leaves += (basestring, )
    _tree_zip = partial(tree_zip, leaves=leaves)

    if not all(_is_fork(t) for t in trees):
        return trees
    else:
        return [_tree_zip(*neighbors) for neighbors in zip(*trees)]