(exp, env)
Return names of all free variables in a parsed (expression) AST.

    Parameters
    ----------
    exp : ast.AST
        An expression ast (ast.parse(..., mode="single"))
    env : List[str]
        Environment

    Returns
    -------
    freevars : List[str]

    See also
    --------
    ast
Return names of all free variables in a parsed (expression) AST.
Return names of all free variables in a parsed ( expression ) AST .
def freevars(exp, env):
    """
    Return names of all free variables in a parsed (expression) AST.

    Parameters
    ----------
    exp : ast.AST
        An expression ast (ast.parse(..., mode="single"))
    env : List[str]
        Environment

    Returns
    -------
    freevars : List[str]

    See also
    --------
    ast

    """
    # pylint: disable=too-many-return-statements,too-many-branches
    etype = type(exp)
    if etype in [ast.Expr, ast.Expression]:
        return freevars(exp.body, env)
    elif etype == ast.BoolOp:
        return sum((freevars(v, env) for v in exp.values), [])
    elif etype == ast.BinOp:
        return freevars(exp.left, env) + freevars(exp.right, env)
    elif etype == ast.UnaryOp:
        return freevars(exp.operand, env)
    elif etype == ast.Lambda:
        args = exp.args
        assert isinstance(args, ast.arguments)
        argnames = [a.arg for a in args.args]
        argnames += [args.vararg.arg] if args.vararg else []
        argnames += [a.arg for a in args.kwonlyargs] if args.kwonlyargs else []
        argnames += [args.kwarg] if args.kwarg else []
        return freevars(exp.body, env + argnames)
    elif etype == ast.IfExp:
        return (freevars(exp.test, env) + freevars(exp.body, env) +
                freevars(exp.orelse, env))
    elif etype == ast.Dict:
        return sum((freevars(v, env)
                    for v in chain(exp.keys, exp.values)), [])
    elif etype == ast.Set:
        return sum((freevars(v, env) for v in exp.elts), [])
    elif etype in [ast.SetComp, ast.ListComp, ast.GeneratorExp, ast.DictComp]:
        env_ext = []
        vars_ = []
        for gen in exp.generators:
            target_names = freevars(gen.target, [])  # assigned names
            vars_iter = freevars(gen.iter, env)
            env_ext += target_names
            vars_ifs = list(chain(*(freevars(ifexp, env + target_names)
                                    for ifexp in gen.ifs or [])))
            vars_ += vars_iter + vars_ifs

        if etype == ast.DictComp:
            vars_ = (freevars(exp.key, env_ext) +
                     freevars(exp.value, env_ext) +
                     vars_)
        else:
            vars_ = freevars(exp.elt, env + env_ext) + vars_
        return vars_
    # Yield, YieldFrom???
    elif etype == ast.Compare:
        return sum((freevars(v, env)
                    for v in [exp.left] + exp.comparators), [])
    elif etype == ast.Call:
        return sum(map(lambda e: freevars(e, env),
                       chain([exp.func],
                             exp.args or [],
                             [k.value for k in exp.keywords or []])),
                   [])
    elif etype == ast.Starred:
        # a 'starred' call parameter (e.g. a and b in `f(x, *a, *b)`
        return freevars(exp.value, env)
    elif etype in [ast.Num, ast.Str, ast.Ellipsis, ast.Bytes, ast.NameConstant]:
        return []
    elif etype == ast.Constant:
        return []
    elif etype == ast.Attribute:
        return freevars(exp.value, env)
    elif etype == ast.Subscript:
        return freevars(exp.value, env) + freevars(exp.slice, env)
    elif etype == ast.Name:
        return [exp.id] if exp.id not in env else []
    elif etype == ast.List:
        return sum((freevars(e, env) for e in exp.elts), [])
    elif etype == ast.Tuple:
        return sum((freevars(e, env) for e in exp.elts), [])
    elif etype == ast.Slice:
        return sum((freevars(e, env)
                    for e in filter(None, [exp.lower, exp.upper, exp.step])),
                   [])
    elif etype == ast.ExtSlice:
        return sum((freevars(e, env) for e in exp.dims), [])
    elif etype == ast.Index:
        return freevars(exp.value, env)
    elif etype == ast.keyword:
        return freevars(exp.value, env)
    else:
        raise ValueError(exp)
def freevars ( exp , env ) : # pylint: disable=too-many-return-statements,too-many-branches etype = type ( exp ) if etype in [ ast . Expr , ast . Expression ] : return freevars ( exp . body , env ) elif etype == ast . BoolOp : return sum ( ( freevars ( v , env ) for v in exp . values ) , [ ] ) elif etype == ast . BinOp : return freevars ( exp . left , env ) + freevars ( exp . right , env ) elif etype == ast . UnaryOp : return freevars ( exp . operand , env ) elif etype == ast . Lambda : args = exp . args assert isinstance ( args , ast . arguments ) argnames = [ a . arg for a in args . args ] argnames += [ args . vararg . arg ] if args . vararg else [ ] argnames += [ a . arg for a in args . kwonlyargs ] if args . kwonlyargs else [ ] argnames += [ args . kwarg ] if args . kwarg else [ ] return freevars ( exp . body , env + argnames ) elif etype == ast . IfExp : return ( freevars ( exp . test , env ) + freevars ( exp . body , env ) + freevars ( exp . orelse , env ) ) elif etype == ast . Dict : return sum ( ( freevars ( v , env ) for v in chain ( exp . keys , exp . values ) ) , [ ] ) elif etype == ast . Set : return sum ( ( freevars ( v , env ) for v in exp . elts ) , [ ] ) elif etype in [ ast . SetComp , ast . ListComp , ast . GeneratorExp , ast . DictComp ] : env_ext = [ ] vars_ = [ ] for gen in exp . generators : target_names = freevars ( gen . target , [ ] ) # assigned names vars_iter = freevars ( gen . iter , env ) env_ext += target_names vars_ifs = list ( chain ( * ( freevars ( ifexp , env + target_names ) for ifexp in gen . ifs or [ ] ) ) ) vars_ += vars_iter + vars_ifs if etype == ast . DictComp : vars_ = ( freevars ( exp . key , env_ext ) + freevars ( exp . value , env_ext ) + vars_ ) else : vars_ = freevars ( exp . elt , env + env_ext ) + vars_ return vars_ # Yield, YieldFrom??? elif etype == ast . Compare : return sum ( ( freevars ( v , env ) for v in [ exp . left ] + exp . comparators ) , [ ] ) elif etype == ast . Call : return sum ( map ( lambda e : freevars ( e , env ) , chain ( [ exp . func ] , exp . args or [ ] , [ k . value for k in exp . keywords or [ ] ] ) ) , [ ] ) elif etype == ast . Starred : # a 'starred' call parameter (e.g. a and b in `f(x, *a, *b)` return freevars ( exp . value , env ) elif etype in [ ast . Num , ast . Str , ast . Ellipsis , ast . Bytes , ast . NameConstant ] : return [ ] elif etype == ast . Constant : return [ ] elif etype == ast . Attribute : return freevars ( exp . value , env ) elif etype == ast . Subscript : return freevars ( exp . value , env ) + freevars ( exp . slice , env ) elif etype == ast . Name : return [ exp . id ] if exp . id not in env else [ ] elif etype == ast . List : return sum ( ( freevars ( e , env ) for e in exp . elts ) , [ ] ) elif etype == ast . Tuple : return sum ( ( freevars ( e , env ) for e in exp . elts ) , [ ] ) elif etype == ast . Slice : return sum ( ( freevars ( e , env ) for e in filter ( None , [ exp . lower , exp . upper , exp . step ] ) ) , [ ] ) elif etype == ast . ExtSlice : return sum ( ( freevars ( e , env ) for e in exp . dims ) , [ ] ) elif etype == ast . Index : return freevars ( exp . value , env ) elif etype == ast . keyword : return freevars ( exp . value , env ) else : raise ValueError ( exp )