Python AST模块无法检测到;如果;或;至于;

Python AST模块无法检测到;如果;或;至于;,python,abstract-syntax-tree,Python,Abstract Syntax Tree,我正试图限制用户提供的脚本,访问者如下: class SyntaxChecker(ast.NodeVisitor): def check(self, syntax): tree = ast.parse(syntax) print(ast.dump(tree), syntax) self.visit(tree) def visit_Call(self, node): print('Called for Call',

我正试图限制用户提供的脚本,访问者如下:

class SyntaxChecker(ast.NodeVisitor):

    def check(self, syntax):
        tree = ast.parse(syntax)
        print(ast.dump(tree), syntax)
        self.visit(tree)

    def visit_Call(self, node):
        print('Called for Call', ast.dump(node))
        if isinstance(node.func, ast.Call) and node.func.id not in allowed_functions:
            raise CodeError("%s is not an allowed function!"%node.func.id)
        elif isinstance(node.func, ast.Attribute) and node.func.value.id not in allowed_classes:
            raise CodeError('{0} is not calling an allowed class'.format(node.func.value.id))
        elif isinstance(node.func, ast.Name) and node.func.id in allowed_classes:
            raise CodeError('You are not allowed to instantiate any class, {0}'.format(node.func.id))
        else:
            ast.NodeVisitor.generic_visit(self, node)

    def visit_Assign(self, node):
        print('Called for Assign', ast.dump(node))
        ast.NodeVisitor.generic_visit(self, node)

    def visit_Attribute(self, node):
        print('Called for Attribute', ast.dump(node))
        if node.value.id not in allowed_classes:
            raise CodeError('"{0}" is not an allowed class'.format(node.value.id))
        elif node.value.id in allowed_classes and isinstance(node.ctx, ast.Store):
            raise CodeError('Trying to change something in a pre-defined class, "{0}" in "{1}"'.format(node.attr, node.value.id))
        else:
            ast.NodeVisitor.generic_visit(self, node)

    def visit_Expr(self, node):
        print('Called for Expr', ast.dump(node))
        ast.NodeVisitor.generic_visit(self, node)

    def visit_Name(self, node):
        print('Called for Name', ast.dump(node))
        if isinstance(node.ctx, ast.Store) and node.id in allowed_classes:
            raise CodeError('Trying to change a pre-defined class, {0}'.format(node.id))
        elif isinstance(node.ctx, ast.Load) and node.id not in safe_names and node.id not in allowed_functions and node.id not in allowed_classes:
            raise CodeError('"{0}" function is not allowed'.format(node.id))
        else:
            ast.NodeVisitor.generic_visit(self, node)

    def generic_visit(self, node):
        print('Called for generic', ast.dump(node))        
        if type(node).__name__ not in allowed_node_types:
            raise CodeError("%s is not allowed!"%type(node).__name__)
        else:
            ast.NodeVisitor.generic_visit(self, node)

if __name__ == '__main__':
    # Check whole file
    x = SyntaxChecker()
    code = open(sys.argv[1], 'r').read()
    try:
        x.check(code)
    except CodeError as e:
        print(repr(e))

    # Or check line by line, considering multiline statements
    code = ''
    for line in open(sys.argv[1], 'r'):
        line = line.strip()
        if line:
            code += line
            try:
                print('[{0}]'.format(code))
                x.check(code)
                code = ''
            except CodeError as e:
                print(repr(e))
                break
            except SyntaxError as e:
                print('********Feeding next line', repr(e))
目前它做得很好,我将对它进行更多的调整,但问题是,在解析类似的内容时,这总是抛出
SyntaxError(“解析时出现意外的EOF”),('',1,15',对于A.b()中的j:')

for j in A.b():
    print('hey')
因此,的
不会被解析


编辑:我添加了代码以一次检查整个代码,或者检查多行语句。

您正在逐行解析代码,但是
for
循环并不独立。没有套件的
for
循环是语法错误。Python希望找到一个套件,并找到了EOF(文件结尾)

换句话说,您的解析器只能在一个物理行上处理和独立,并且如果它们在同一行上直接后跟一个简单语句或表达式

您的代码也会因以下原因而失败:

  • 多行字符串

    somestring = """Containing more
    than one
    line"""
    
  • 线路延续

    if the_line == 'too long' and \
       a_backslash_was_used in (True, 'true'):
        # your code fails
    
    somevar = (you_are_allowed_to_use_newlines,
        "inside parentheses and brackets and braces")
    
使用
ast.parse()
逐行检查代码在这里行不通;它只适用于整个套房;在一个文件一个文件的基础上,我只会传递整个文件

要逐行检查代码,您需要自己标记代码。你可以使用;它将报告语法错误方面的
SyntaxError
异常或
tokenize.TokenError


如果要限制脚本,请查看;项目本身或其源代码。它们解析整个脚本,然后根据生成的AST节点执行(限制它们将接受哪些节点)。

您可以使用is实例(迭代器,(AST,if,AST.For))和AST.parse进行解析。

那么对于
if
For
我应该做什么呢?手动解析它们?@thelastblack:您至少需要输入多行代码。考虑到一个套件可能包含空行,所以在没有错误之前输入是不够的。现在你是说我必须发明轮子?它不是以前发明的吗?我将尝试喂食,直到没有错误才能看到results@thelastblack:查看和等工具的源代码;这个轮子确实已经发明出来了,你只是用了错误的工具自己造了一个而已。@thelast black:直到没有错误为止的喂养是不够的;您将获得循环或函数或类的第一行以及其后的第一个缩进行,然后下一行将抛出异常,因为它缩进得太远。这是因为它实际上是您刚刚解析的复合语句(尚未完成)的一部分。