def buildParameterSpec(name, node, source_ref): kind = getKind(node) assert kind in ("FunctionDef", "Lambda"), "unsupported for kind " + kind def extractArg(arg): if type(arg) is str or arg is None: return arg elif getKind(arg) == "Name": return arg.id elif getKind(arg) == "arg": return arg.arg elif getKind(arg) == "Tuple": return tuple(extractArg(arg) for arg in arg.elts) else: assert False, getKind(arg) result = ParameterSpec( name=name, normal_args=[extractArg(arg) for arg in node.args.args], kw_only_args=[extractArg(arg) for arg in node.args.kwonlyargs] if Utils.python_version >= 300 else [], list_star_arg=extractArg(node.args.vararg), dict_star_arg=extractArg(node.args.kwarg), default_count=len(node.args.defaults)) message = result.checkValid() if message is not None: SyntaxErrors.raiseSyntaxError(message, source_ref) return result
def _markAsGenerator(provider, node, source_ref): if provider.isPythonModule(): SyntaxErrors.raiseSyntaxError( "'yield' outside function", source_ref, None if Utils.python_version < 300 else node.col_offset) provider.markAsGenerator()
def buildReturnNode(provider, node, source_ref): if not provider.isExpressionFunctionBody() or \ provider.isClassDictCreation(): SyntaxErrors.raiseSyntaxError( "'return' outside function", source_ref, None if Utils.python_version < 300 else ( node.col_offset if provider.isPythonModule() else node.col_offset+4 ) ) expression = buildNode(provider, node.value, source_ref, allow_none = True) if expression is None: expression = ExpressionConstantRef( constant = None, source_ref = source_ref, user_provided = True ) return makeTryFinallyIndicator( provider = provider, statement = StatementReturn( expression = expression, source_ref = source_ref ), is_loop_exit = False )
def _handleNonLocal(self, node): # Take closure variables for non-local declarations. for non_local_names, source_ref in node.getNonlocalDeclarations(): for non_local_name in non_local_names: variable = node.getClosureVariable( variable_name = non_local_name ) node.registerProvidedVariable( variable ) if variable.isModuleVariableReference(): SyntaxErrors.raiseSyntaxError( "no binding for nonlocal '%s' found" % ( non_local_name ), source_ref = None if isFullCompat() and \ python_version < 340 else source_ref, display_file = not isFullCompat() or \ python_version >= 340, display_line = not isFullCompat() or \ python_version >= 340 )
def buildStatementContinueLoop(node, source_ref): if getBuildContext() == "finally": if not Options.isFullCompat() or Utils.python_version >= 300: col_offset = node.col_offset - 9 else: col_offset = None if Utils.python_version >= 300 and Options.isFullCompat(): source_line = "" else: source_line = None SyntaxErrors.raiseSyntaxError( "'continue' not supported inside 'finally' clause", source_ref, col_offset = col_offset, source_line = source_line ) return makeTryFinallyIndicator( statement = StatementContinueLoop( source_ref = source_ref ), is_loop_exit = True )
def buildReturnNode(provider, node, source_ref): if not provider.isExpressionFunctionBody() or \ provider.isClassDictCreation(): SyntaxErrors.raiseSyntaxError( "'return' outside function", source_ref, None if Utils.python_version < 300 else ( node.col_offset if provider.isPythonModule() else node.col_offset+4 ) ) expression = buildNode(provider, node.value, source_ref, allow_none = True) if expression is None: expression = ExpressionConstantRef( constant = None, source_ref = source_ref, user_provided = True ) return makeTryFinallyIndicator( statement = StatementReturn( expression = expression, source_ref = source_ref ), is_loop_exit = False )
def handleGlobalDeclarationNode(provider, node, source_ref): # The source reference of the global really doesn't matter, pylint: disable=W0613 # On the module level, there is nothing to do. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global ourselves # here. The AST parsing doesn't catch it. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason="name '%s' is %s and global" % (variable_name, "local" if Utils.python_version < 300 else "parameter"), source_ref=provider.getSourceReference()) except AttributeError: pass module = provider.getParentModule() for variable_name in node.names: module_variable = module.getVariableForAssignment( variable_name=variable_name) closure_variable = provider.addClosureVariable( variable=module_variable, global_statement=True) provider.registerProvidedVariable(variable=closure_variable) return None
def buildReturnNode(provider, node, source_ref): if not provider.isExpressionFunctionBody() or \ provider.isClassDictCreation(): SyntaxErrors.raiseSyntaxError( "'return' outside function", source_ref, None if Utils.python_version < 300 else ( node.col_offset if provider.isPythonModule() else node.col_offset+4 ) ) if node.value is not None: return StatementReturn( expression = buildNode( provider, node.value, source_ref ), source_ref = source_ref ) else: return StatementReturn( expression = ExpressionConstantRef( constant = None, source_ref = source_ref, user_provided = True ), source_ref = source_ref )
def _attachVariable(node, provider): # print "Late reference", node.getVariableName(), "for", provider, "caused at", node, "of", node.getParent() variable_name = node.getVariableName() was_taken = provider.hasTakenVariable(variable_name) variable = provider.getVariableForReference( variable_name=variable_name) node.setVariable(variable) # Need to catch functions with "exec" and closure variables not allowed. if python_version < 300 and \ not was_taken and \ provider.isExpressionFunctionBody() and \ variable.getOwner() is not provider: parent_provider = provider.getParentVariableProvider() while parent_provider.isExpressionFunctionBody() and \ parent_provider.isClassDictCreation(): parent_provider = parent_provider.getParentVariableProvider() if parent_provider.isExpressionFunctionBody() and \ parent_provider.isUnqualifiedExec(): SyntaxErrors.raiseSyntaxError( reason = PythonVersions.\ getErrorMessageExecWithNestedFunction() % \ parent_provider.getName(), source_ref = parent_provider.getExecSourceRef(), col_offset = None, display_file = True, display_line = True, source_line = None )
def buildStatementContinueLoop(provider, node, source_ref): if getBuildContext() == "finally": if not Options.isFullCompat() or Utils.python_version >= 300: col_offset = node.col_offset - 9 else: col_offset = None if Utils.python_version >= 300 and Options.isFullCompat(): source_line = "" else: source_line = None SyntaxErrors.raiseSyntaxError( "'continue' not supported inside 'finally' clause", source_ref, col_offset = col_offset, source_line = source_line ) return makeTryFinallyIndicator( provider = provider, statement = StatementContinueLoop( source_ref = source_ref ), is_loop_exit = True )
def _attachVariable(self, node, provider): # print "Late reference", node.getVariableName(), "for", provider, "caused at", node, "of", node.getParent() variable = provider.getVariableForReference( variable_name=node.getVariableName()) node.setVariable(variable) # Need to catch functions with "exec" not allowed. if python_version < 300 and \ provider.isExpressionFunctionBody() and \ variable.isReference() and \ (not variable.isModuleVariableReference() or \ not variable.isFromGlobalStatement() ): parent_provider = provider.getParentVariableProvider() while parent_provider.isExpressionFunctionBody() and \ parent_provider.isClassDictCreation(): parent_provider = parent_provider.getParentVariableProvider() if parent_provider.isExpressionFunctionBody() and \ parent_provider.isUnqualifiedExec(): SyntaxErrors.raiseSyntaxError( reason="""\ unqualified exec is not allowed in function '%s' it \ contains a nested function with free variables""" % parent_provider.getName(), source_ref=parent_provider.getExecSourceRef(), col_offset=None, display_file=True, display_line=True, source_line=None)
def handleNonlocalDeclarationNode(provider, node, source_ref): # The source reference of the nonlocal really doesn't matter. # pylint: disable=W0613 # Need to catch the error of declaring a parameter variable as global # ourselves here. The AST parsing doesn't catch it, but we can do it here. parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is parameter and nonlocal" % ( variable_name ), source_ref = None if Options.isFullCompat() and \ Utils.python_version < 340 else source_ref, display_file = not Options.isFullCompat() or \ Utils.python_version >= 340, display_line = not Options.isFullCompat() or \ Utils.python_version >= 340 ) provider.addNonlocalsDeclaration(node.names, source_ref) return None
def buildParameterSpec( name, node, source_ref ): kind = getKind( node ) assert kind in ( "FunctionDef", "Lambda" ), "unsupported for kind " + kind def extractArg( arg ): if getKind( arg ) == "Name": return arg.id elif getKind( arg ) == "arg": return arg.arg elif getKind( arg ) == "Tuple": return tuple( extractArg( arg ) for arg in arg.elts ) else: assert False, getKind( arg ) result = ParameterSpec( name = name, normal_args = [ extractArg( arg ) for arg in node.args.args ], kw_only_args = [ extractArg( arg ) for arg in node.args.kwonlyargs ] if Utils.python_version >= 300 else [], list_star_arg = node.args.vararg, dict_star_arg = node.args.kwarg, default_count = len( node.args.defaults ) ) message = result.checkValid() if message is not None: SyntaxErrors.raiseSyntaxError( message, source_ref ) return result
def handleGlobalDeclarationNode( provider, node, source_ref ): if not source_ref.isExecReference(): # On the module level, there is nothing to do. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global ourselves # here. The AST parsing doesn't catch it. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is %s and global" % ( variable_name, "local" if Utils.python_version < 300 else "parameter" ), source_ref = provider.getSourceReference() ) except AttributeError: pass module = provider.getParentModule() for variable_name in node.names: closure_variable = None # Re-use already taken global variables, in order to avoid creating yet # another instance, esp. as the markups could then potentially not be # shared. if provider.hasTakenVariable( variable_name ): closure_variable = provider.getTakenVariable( variable_name ) if not closure_variable.isModuleVariableReference(): closure_variable = None if closure_variable is None: module_variable = module.getVariableForAssignment( variable_name = variable_name ) closure_variable = provider.addClosureVariable( variable = module_variable ) assert closure_variable.isModuleVariableReference() closure_variable.markFromGlobalStatement() if source_ref.isExecReference(): closure_variable.markFromExecStatement() provider.registerProvidedVariable( variable = closure_variable ) return None
def _markAsGenerator(provider, node, source_ref): if provider.isPythonModule(): SyntaxErrors.raiseSyntaxError( "'yield' outside function", source_ref, None if Utils.python_version < 300 else node.col_offset ) provider.markAsGenerator()
def _readSourceCodeFromFilename3(source_filename): with open(source_filename, "rb") as source_file: source_code = source_file.read() if source_code.startswith(b'\xef\xbb\xbf'): source_code = source_code[3:] new_line = source_code.find(b"\n") if new_line is not -1: line = source_code[: new_line] line_match = re.search(b"coding[:=]\\s*([-\\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") # Detect encoding problem, as decode won't raise the compatible # thing. try: import codecs codecs.lookup(encoding) except LookupError: if Utils.python_version >= 341 or \ (Utils.python_version >= 335 and \ Utils.python_version < 340) or \ (Utils.python_version >= 323 and \ Utils.python_version < 330): reason = "encoding problem: %s" % encoding else: reason = "unknown encoding: %s" % encoding SyntaxErrors.raiseSyntaxError( reason = reason, source_ref = SourceCodeReferences.fromFilename( source_filename, None ), display_line = False ) return source_code[ new_line : ].decode(encoding) new_line = source_code.find(b"\n", new_line+1) if new_line is not -1: line = source_code[ : new_line ] line_match = re.search(b"coding[:=]\\s*([-\\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") return "\n" + source_code[ new_line : ].decode(encoding) return source_code.decode("utf-8")
def handleGlobalDeclarationNode(provider, node, source_ref): if not source_ref.isExecReference(): # On the module level, there is nothing to do. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global ourselves # here. The AST parsing doesn't catch it. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason="name '%s' is %s and global" % (variable_name, "local" if Utils.python_version < 300 else "parameter"), source_ref=provider.getSourceReference()) except AttributeError: pass module = provider.getParentModule() for variable_name in node.names: closure_variable = None # Re-use already taken global variables, in order to avoid creating yet # another instance, esp. as the markups could then potentially not be # shared. if provider.hasTakenVariable(variable_name): closure_variable = provider.getTakenVariable(variable_name) if not closure_variable.isModuleVariableReference(): closure_variable = None if closure_variable is None: module_variable = module.getVariableForAssignment( variable_name=variable_name) closure_variable = provider.addClosureVariable( variable=module_variable) assert closure_variable.isModuleVariableReference() closure_variable.markFromGlobalStatement() if source_ref.isExecReference(): closure_variable.markFromExecStatement() provider.registerProvidedVariable(variable=closure_variable) return None
def _readSourceCodeFromFilename3(source_filename): with open(source_filename, "rb") as source_file: source_code = source_file.read() if source_code.startswith(b'\xef\xbb\xbf'): source_code = source_code[3:] new_line = source_code.find(b"\n") if new_line is not -1: line = source_code[:new_line] line_match = re.search(b"coding[:=]\\s*([-\\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") # Detect encoding problem, as decode won't raise the compatible # thing. try: import codecs codecs.lookup(encoding) except LookupError: if Utils.python_version >= 341 or \ (Utils.python_version >= 335 and \ Utils.python_version < 340) or \ (Utils.python_version >= 323 and \ Utils.python_version < 330): reason = "encoding problem: %s" % encoding else: reason = "unknown encoding: %s" % encoding SyntaxErrors.raiseSyntaxError( reason=reason, source_ref=SourceCodeReferences.fromFilename( source_filename, None), display_line=False) return source_code[new_line:].decode(encoding) new_line = source_code.find(b"\n", new_line + 1) if new_line is not -1: line = source_code[:new_line] line_match = re.search(b"coding[:=]\\s*([-\\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") return "\n" + source_code[new_line:].decode(encoding) return source_code.decode("utf-8")
def onEnterNode(self, node): assert python_version < 300 if node.isStatementDelVariable(): variable = node.getTargetVariableRef().getVariable() if not variable.isModuleVariable() and \ isSharedLogically(variable): SyntaxErrors.raiseSyntaxError( reason="""\ can not delete variable '%s' referenced in nested scope""" % (variable.getName()), source_ref=(None if isFullCompat() else node.getSourceReference()), display_file=not isFullCompat(), display_line=not isFullCompat())
def checkFutureImportsOnlyAtStart(body): # Check if a __future__ imports really were at the beginning of the file. for node in body: if node in _future_import_nodes: _future_import_nodes.remove(node) else: if _future_import_nodes: SyntaxErrors.raiseSyntaxError( reason = """\ from __future__ imports must occur at the beginning of the file""", col_offset = 1 if Utils.python_version >= 300 or \ not Options.isFullCompat() else None, source_ref = _future_import_nodes[0].source_ref )
def buildYieldNode(provider, node, source_ref): if provider.isPythonModule(): SyntaxErrors.raiseSyntaxError( "'yield' outside function", source_ref, None if Utils.python_version < 300 else node.col_offset) provider.markAsGenerator() if node.value is not None: return ExpressionYield(expression=buildNode(provider, node.value, source_ref), source_ref=source_ref) else: return ExpressionYield(expression=ExpressionConstantRef( constant=None, source_ref=source_ref), source_ref=source_ref)
def _readSourceCodeFromFilename2(source_filename): # Detect the encoding. encoding = _detectEncoding2(source_filename) with open(source_filename, "rU") as source_file: source_code = source_file.read() # Try and detect SyntaxError from missing or wrong encodings. if type(source_code) is not unicode and encoding == "ascii": try: _source_code = source_code.decode(encoding) except UnicodeDecodeError as e: lines = source_code.split("\n") so_far = 0 for count, line in enumerate(lines): so_far += len(line) + 1 if so_far > e.args[2]: break else: # Cannot happen, decode error implies non-empty. count = -1 wrong_byte = re.search( "byte 0x([a-f0-9]{2}) in position", str(e) ).group(1) SyntaxErrors.raiseSyntaxError( reason = """\ Non-ASCII character '\\x%s' in file %s on line %d, but no encoding declared; \ see http://python.org/dev/peps/pep-0263/ for details""" % ( wrong_byte, source_filename, count+1, ), source_ref = SourceCodeReferences.fromFilename( source_filename, None ).atLineNumber(count+1), display_line = False ) return source_code
def _readSourceCodeFromFilename2(source_filename): # Detect the encoding. with open(source_filename, "rU") as source_file: encoding = _detectEncoding2(source_file) source_code = source_file.read() # Try and detect SyntaxError from missing or wrong encodings. if type(source_code) is not unicode and encoding == "ascii": try: _source_code = source_code.decode(encoding) except UnicodeDecodeError as e: lines = source_code.split('\n') so_far = 0 for count, line in enumerate(lines): so_far += len(line) + 1 if so_far > e.args[2]: break else: # Cannot happen, decode error implies non-empty. count = -1 wrong_byte = re.search( "byte 0x([a-f0-9]{2}) in position", str(e) ).group(1) SyntaxErrors.raiseSyntaxError( reason = """\ Non-ASCII character '\\x%s' in file %s on line %d, but no encoding declared; \ see http://python.org/dev/peps/pep-0263/ for details""" % ( wrong_byte, source_filename, count+1, ), source_ref = SourceCodeReferences.fromFilename( source_filename, None ).atLineNumber(count+1), display_line = False ) return source_code
def handleNonlocalDeclarationNode(provider, node, source_ref): # The source reference of the nonlocal really doesn't matter, pylint: disable=W0613 # Need to catch the error of declaring a parameter variable as global ourselves # here. The AST parsing doesn't catch it, but we can do it here. parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason="name '%s' is parameter and nonlocal" % (variable_name), source_ref=None if Options.isFullCompat() else source_ref, display_file=not Options.isFullCompat(), display_line=not Options.isFullCompat()) provider.addNonlocalsDeclaration(node.names, source_ref) return None
def onEnterNode(self, node): assert python_version < 300 if node.isStatementDelVariable(): variable = node.getTargetVariableRef().getVariable() if variable.isSharedLogically(): SyntaxErrors.raiseSyntaxError( reason = """\ can not delete variable '%s' referenced in nested scope""" % ( variable.getName() ), source_ref = ( None if isFullCompat() else node.getSourceReference() ), display_file = not isFullCompat(), display_line = not isFullCompat() )
def enableFutureFeature(object_name, future_spec, source_ref): if object_name == "unicode_literals": future_spec.enableUnicodeLiterals() elif object_name == "absolute_import": future_spec.enableAbsoluteImport() elif object_name == "division": future_spec.enableFutureDivision() elif object_name == "print_function": future_spec.enableFuturePrint() elif object_name == "barry_as_FLUFL" and Utils.python_version >= 300: future_spec.enableBarry() elif object_name == "braces": SyntaxErrors.raiseSyntaxError("not a chance", source_ref) elif object_name in ("nested_scopes", "generators", "with_statement"): # These are enabled in all cases already. pass else: SyntaxErrors.raiseSyntaxError( "future feature %s is not defined" % object_name, source_ref)
def _readSourceCodeFromFilename3( source_filename ): source_code = open( source_filename, "rb" ).read() if source_code.startswith( b'\xef\xbb\xbf' ): return source_code[3:] new_line = source_code.find( b"\n" ) if new_line is not -1: line = source_code[ : new_line ] line_match = re.search( b"coding[:=]\s*([-\w.]+)", line ) if line_match: encoding = line_match.group(1).decode( "ascii" ) # Detect encoding problem, as decode won't raise the compatible thing. try: import codecs codecs.lookup( encoding ) except LookupError: SyntaxErrors.raiseSyntaxError( reason = "unknown encoding: %s" % encoding, source_ref = SourceCodeReferences.fromFilename( source_filename, None ), display_line = False ) return source_code[ new_line + 1 : ].decode( encoding ) new_line = source_code.find( b"\n", new_line+1 ) if new_line is not -1: line = source_code[ : new_line ] line_match = re.search( b"coding[:=]\s*([-\w.]+)", line ) if line_match: encoding = line_match.group(1).decode( "ascii" ) return source_code[ new_line + 1 : ].decode( encoding ) return source_code.decode( "utf-8" )
def _readSourceCodeFromFilename3(source_filename): source_code = open(source_filename, "rb").read() if source_code.startswith(b'\xef\xbb\xbf'): return source_code[3:] new_line = source_code.find(b"\n") if new_line is not -1: line = source_code[:new_line] line_match = re.search(b"coding[:=]\s*([-\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") # Detect encoding problem, as decode won't raise the compatible thing. try: import codecs codecs.lookup(encoding) except LookupError: SyntaxErrors.raiseSyntaxError( reason="unknown encoding: %s" % encoding, source_ref=SourceCodeReferences.fromFilename( source_filename, None), display_line=False) return source_code[new_line + 1:].decode(encoding) new_line = source_code.find(b"\n", new_line + 1) if new_line is not -1: line = source_code[:new_line] line_match = re.search(b"coding[:=]\s*([-\w.]+)", line) if line_match: encoding = line_match.group(1).decode("ascii") return source_code[new_line + 1:].decode(encoding) return source_code.decode("utf-8")
def onLeaveNode(self, node): # Return statements in generators are not really that, instead they are # exception raises, fix that up now. Doing it right from the onset, # would be a bit more difficult, as the knowledge that something is a # generator, requires a second pass. if node.isStatementReturn() and \ node.getParentVariableProvider().isGenerator(): return_value = node.getExpression() if python_version < 330: if not return_value.isExpressionConstantRef() or \ return_value.getConstant() is not None: SyntaxErrors.raiseSyntaxError( "'return' with argument inside generator", source_ref=node.getSourceReference(), ) node.replaceWith( StatementGeneratorReturn(expression=return_value, source_ref=node.getSourceReference()))
def handleGlobalDeclarationNode( provider, node, source_ref ): # The source reference of the global really doesn't matter, pylint: disable=W0613 # On the module level, there is nothing to do. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global ourselves # here. The AST parsing doesn't catch it. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is %s and global" % ( variable_name, "local" if Utils.python_version < 300 else "parameter" ), source_ref = provider.getSourceReference() ) except AttributeError: pass module = provider.getParentModule() for variable_name in node.names: module_variable = module.getVariableForAssignment( variable_name = variable_name ) closure_variable = provider.addClosureVariable( variable = module_variable, global_statement = True ) provider.registerProvidedVariable( variable = closure_variable ) return None
def _attachVariable(node, provider): # print "Late reference", node.getVariableName(), "for", provider, "caused at", node, "of", node.getParent() variable_name = node.getVariableName() was_taken = provider.hasTakenVariable(variable_name) variable = provider.getVariableForReference( variable_name = variable_name ) node.setVariable( variable ) # Need to catch functions with "exec" and closure variables not allowed. if python_version < 300 and \ not was_taken and \ provider.isExpressionFunctionBody() and \ variable.getOwner() is not provider: parent_provider = provider.getParentVariableProvider() while parent_provider.isExpressionFunctionBody() and \ parent_provider.isClassDictCreation(): parent_provider = parent_provider.getParentVariableProvider() if parent_provider.isExpressionFunctionBody() and \ parent_provider.isUnqualifiedExec(): SyntaxErrors.raiseSyntaxError( reason = PythonVersions.\ getErrorMessageExecWithNestedFunction() % \ parent_provider.getName(), source_ref = parent_provider.getExecSourceRef(), col_offset = None, display_file = True, display_line = True, source_line = None )
def buildYieldNode( provider, node, source_ref ): if provider.isPythonModule(): SyntaxErrors.raiseSyntaxError( "'yield' outside function", source_ref, None if Utils.python_version < 300 else node.col_offset ) provider.markAsGenerator() if node.value is not None: return ExpressionYield( expression = buildNode( provider, node.value, source_ref ), source_ref = source_ref ) else: return ExpressionYield( expression = ExpressionConstantRef( constant = None, source_ref = source_ref ), source_ref = source_ref )
def onLeaveNode(self, node): # Return statements in generators are not really that, instead they are # exception raises, fix that up now. Doing it right from the onset, # would be a bit more difficult, as the knowledge that something is a # generator, requires a second pass. if node.isStatementReturn() and \ node.getParentVariableProvider().isGenerator(): return_value = node.getExpression() if python_version < 330: if not return_value.isExpressionConstantRef() or \ return_value.getConstant() is not None: SyntaxErrors.raiseSyntaxError( "'return' with argument inside generator", source_ref = node.getSourceReference(), ) node.replaceWith( StatementGeneratorReturn( expression = return_value, source_ref = node.getSourceReference() ) )
def handleNonlocalDeclarationNode(provider, node, source_ref): # Need to catch the error of declaring a parameter variable as global # ourselves here. The AST parsing doesn't catch it, but we can do it here. parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is parameter and nonlocal" % ( variable_name ), source_ref = None if Options.isFullCompat() and \ Utils.python_version < 340 else source_ref, display_file = not Options.isFullCompat() or \ Utils.python_version >= 340, display_line = not Options.isFullCompat() or \ Utils.python_version >= 340 ) provider.addNonlocalsDeclaration(node.names, source_ref) return None
def _attachVariable(self, node, provider): # print "Late reference", node.getVariableName(), "for", provider, "caused at", node, "of", node.getParent() variable = provider.getVariableForReference( variable_name = node.getVariableName() ) node.setVariable( variable ) # Need to catch functions with "exec" not allowed. if python_version < 300 and \ provider.isExpressionFunctionBody() and \ variable.isReference() and \ (not variable.isModuleVariableReference() or \ not variable.isFromGlobalStatement() ): parent_provider = provider.getParentVariableProvider() while parent_provider.isExpressionFunctionBody() and \ parent_provider.isClassDictCreation(): parent_provider = parent_provider.getParentVariableProvider() if parent_provider.isExpressionFunctionBody() and \ parent_provider.isUnqualifiedExec(): SyntaxErrors.raiseSyntaxError( reason = """\ unqualified exec is not allowed in function '%s' it \ contains a nested function with free variables""" % parent_provider.getName(), source_ref = parent_provider.getExecSourceRef(), col_offset = None, display_file = True, display_line = True, source_line = None )
def _handleNonLocal(self, node): # Take closure variables for non-local declarations. for non_local_names, source_ref in node.getNonlocalDeclarations(): for non_local_name in non_local_names: variable = node.getClosureVariable( variable_name=non_local_name) node.registerProvidedVariable(variable) if variable.isModuleVariableReference(): SyntaxErrors.raiseSyntaxError( "no binding for nonlocal '%s' found" % ( non_local_name ), source_ref = None if isFullCompat() and \ python_version < 340 else source_ref, display_file = not isFullCompat() or \ python_version >= 340, display_line = not isFullCompat() or \ python_version >= 340 )
def enableFutureFeature( object_name, future_spec, source_ref ): if object_name == "unicode_literals": future_spec.enableUnicodeLiterals() elif object_name == "absolute_import": future_spec.enableAbsoluteImport() elif object_name == "division": future_spec.enableFutureDivision() elif object_name == "print_function": future_spec.enableFuturePrint() elif object_name == "barry_as_FLUFL" and Utils.python_version >= 300: future_spec.enableBarry() elif object_name == "braces": SyntaxErrors.raiseSyntaxError( "not a chance", source_ref ) elif object_name in ( "nested_scopes", "generators", "with_statement" ): # These are enabled in all cases already. pass else: SyntaxErrors.raiseSyntaxError( "future feature %s is not defined" % object_name, source_ref )
def onEnterNode( self, node ): if node.isExpressionTargetVariableRef(): if node.getVariable() is None: variable_name = node.getVariableName() provider = node.getParentVariableProvider() variable = provider.getVariableForAssignment( variable_name = variable_name ) # Inside an exec, we need to ignore global declarations that are # not ours, so we replace it with ours, unless it came from an # 'global' declaration inside the exec if node.source_ref.isExecReference() and not provider.isPythonModule(): if variable.isModuleVariableReference() and not variable.isFromExecStatement(): variable = provider.providing[ variable_name ] = provider.createProvidedVariable( variable_name = variable_name ) node.setVariable( variable ) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): node.setVariable( provider.getVariableForReference( variable_name = node.getVariableName() ) ) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner().getParentVariableProvider() != node.getParentVariableProvider(): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable() ) ) assert node.getVariable().isClosureReference(), node.getVariable() elif python_version >= 300 and node.isExpressionFunctionBody(): # Take closure variables for non-local declarations. for non_local_names, source_ref in node.getNonlocalDeclarations(): for non_local_name in non_local_names: # print( "nonlocal reference from", node, "to name", non_local_name ) variable = node.getClosureVariable( variable_name = non_local_name ) node.registerProvidedVariable( variable ) if variable.isModuleVariableReference(): SyntaxErrors.raiseSyntaxError( "no binding for nonlocal '%s' found" % ( non_local_name ), source_ref = None if isFullCompat() else source_ref, display_file = not isFullCompat(), display_line = not isFullCompat() ) # Attribute access of names of class functions should be mangled, if they start # with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith( "__" ) and not attribute_name.endswith( "__" ): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_" + current.getName() + attribute_name ) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule() or current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None source_ref = node.getSourceReference() # source_ref.line += 1 SyntaxErrors.raiseSyntaxError( message, source_ref = node.getSourceReference(), col_offset = col_offset, display_line = display_line, source_line = source_line ) current = current.getParent() if current.isStatementLoop(): break
def handleGlobalDeclarationNode(provider, node, source_ref): # On the module level, there is nothing to do. TODO: Probably a warning # would be warranted. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global # ourselves here. The AST parsing doesn't catch it, so we check here. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is %s and global" % ( variable_name, "local" if Utils.python_version < 300 else "parameter" ), source_ref = ( source_ref if not Options.isFullCompat() or \ Utils.python_version >= 340 else provider.getSourceReference() ) ) except AttributeError: pass # The module the "global" statement refers to. module = provider.getParentModule() # Can give multiple names. for variable_name in node.names: closure_variable = None # Re-use already taken global variables, in order to avoid creating yet # another instance, esp. as the markups could then potentially not be # shared. if provider.hasTakenVariable(variable_name): closure_variable = provider.getTakenVariable(variable_name) # Only global variables count. Could have a closure reference to # a location of a parent function here. if not closure_variable.isModuleVariable(): closure_variable = None if closure_variable is None: module_variable = module.getVariableForAssignment( variable_name = variable_name ) closure_variable = provider.addClosureVariable( variable = module_variable ) assert closure_variable.isModuleVariable() provider.registerProvidedVariable( variable = closure_variable ) return None
def buildTryExceptionNode(provider, node, source_ref): # Try/except nodes. Re-formulated as described in the developer # manual. Exception handlers made the assignment to variables explicit. Same # for the "del" as done for Python3. Also catches always work a tuple of # exception types and hides away that they may be built or not. # Many variables, due to the re-formulation that is going on here, which # just has the complexity, pylint: disable=R0914 handlers = [] for handler in node.handlers: exception_expression, exception_assign, exception_block = ( handler.type, handler.name, handler.body ) statements = [ buildAssignmentStatements( provider = provider, node = exception_assign, allow_none = True, source = ExpressionCaughtExceptionValueRef( source_ref = source_ref.atInternal() ), source_ref = source_ref.atInternal() ), buildStatementsNode( provider = provider, nodes = exception_block, source_ref = source_ref ) ] if Utils.python_version >= 300: target_info = decodeAssignTarget( provider = provider, node = exception_assign, source_ref = source_ref, allow_none = True ) if target_info is not None: kind, detail = target_info assert kind == "Name", kind kind = "Name_Exception" statements.append( buildDeleteStatementFromDecoded( kind = kind, detail = detail, source_ref = source_ref ) ) handler_body = makeStatementsSequence( statements = statements, allow_none = True, source_ref = source_ref ) exception_types = buildNode( provider = provider, node = exception_expression, source_ref = source_ref, allow_none = True ) # The exception types should be a tuple, so as to be most general. if exception_types is None: exception_types = () if handler is not node.handlers[-1]: SyntaxErrors.raiseSyntaxError( reason = "default 'except:' must be last", source_ref = source_ref.atLineNumber( handler.lineno-1 if Options.isFullCompat() else handler.lineno ) ) elif exception_types.isExpressionMakeSequence(): exception_types = exception_types.getElements() else: exception_types = (exception_types,) handlers.append( StatementExceptHandler( exception_types = exception_types, body = handler_body, source_ref = source_ref ) ) tried = buildStatementsNode( provider = provider, nodes = node.body, source_ref = source_ref ) no_raise = buildStatementsNode( provider = provider, nodes = node.orelse, source_ref = source_ref ) if no_raise is None: return StatementTryExcept( handlers = handlers, tried = tried, source_ref = source_ref ) else: return makeTryExceptNoRaise( provider = provider, temp_scope = provider.allocateTempScope("try_except"), handlers = handlers, tried = tried, no_raise = no_raise, source_ref = source_ref )
def buildParseTree( provider, source_code, source_ref, is_module, is_main ): # Workaround: ast.parse cannot cope with some situations where a file is not # terminated by a new line. if not source_code.endswith( "\n" ): source_code = source_code + "\n" body = ast.parse( source_code, source_ref.getFilename() ) assert getKind( body ) == "Module" line_offset = source_ref.getLineNumber() - 1 if line_offset > 0: for created_node in ast.walk( body ): if hasattr( created_node, "lineno" ): created_node.lineno += line_offset body, doc = extractDocFromBody( body ) result = buildStatementsNode( provider = provider, nodes = body, source_ref = source_ref ) # Check if a __future__ imports really were at the beginning of the file. for node in body: if node in _future_import_nodes: _future_import_nodes.remove( node ) else: if _future_import_nodes: SyntaxErrors.raiseSyntaxError( reason = """\ from __future__ imports must occur at the beginning of the file""", col_offset = 1 if Utils.python_version >= 300 or \ not Options.isFullCompat() else None, source_ref = _future_import_nodes[0].source_ref ) internal_source_ref = source_ref.atInternal() statements = [] if is_module: # Add import of "site" module of main programs visibly in the node tree, # so recursion and optimization can pick it up, checking its effects. if is_main and not sys.flags.no_site: statements.append( StatementExpressionOnly( expression = ExpressionImportModule( module_name = "site", import_list = (), level = 0, source_ref = source_ref, ), source_ref = source_ref ) ) statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__doc__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = doc, source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__file__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = source_ref.getFilename(), source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) if provider.isPythonPackage(): # TODO: __package__ is not set here, but automatically, which makes # it invisible though statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__path__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = [ Utils.dirname( source_ref.getFilename() ) ], source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) if Utils.python_version >= 300: statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__cached__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = None, source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) if Utils.python_version >= 330: # For Python3.3, it's set for both packages and non-packages. statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__package__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = provider.getFullName() if provider.isPythonPackage() else provider.getPackage(), source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) if Utils.python_version >= 330 and not provider.isMainModule(): # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__initializing__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = True, source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) # Now the module body if there is any at all. if result is not None: statements.extend( result.getStatements() ) if Utils.python_version >= 330 and not provider.isMainModule(): # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__initializing__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = False, source_ref = internal_source_ref, user_provided = True ), source_ref = internal_source_ref ) ) if is_module: return makeModuleFrame( module = provider, statements = statements, source_ref = source_ref ) else: assert False
def handleGlobalDeclarationNode(provider, node, source_ref): # On the module level, there is nothing to do. TODO: Probably a warning # would be warranted. if provider.isPythonModule(): return None # Need to catch the error of declaring a parameter variable as global # ourselves here. The AST parsing doesn't catch it, so we check here. try: parameters = provider.getParameters() for variable_name in node.names: if variable_name in parameters.getParameterNames(): SyntaxErrors.raiseSyntaxError( reason = "name '%s' is %s and global" % ( variable_name, "local" if Utils.python_version < 300 else "parameter" ), source_ref = ( source_ref if not Options.isFullCompat() or \ Utils.python_version >= 340 else provider.getSourceReference() ) ) except AttributeError: pass # The module the "global" statement refers to. module = provider.getParentModule() # Can give multiple names. for variable_name in node.names: closure_variable = None # Re-use already taken global variables, in order to avoid creating yet # another instance, esp. as the indications could then potentially not # be shared. if provider.hasTakenVariable(variable_name): closure_variable = provider.getTakenVariable(variable_name) # Only global variables count. Could have a closure reference to # a location of a parent function here. if not closure_variable.isModuleVariable(): closure_variable = None if closure_variable is None: module_variable = module.getVariableForAssignment( variable_name = variable_name ) closure_variable = provider.addClosureVariable( variable = module_variable ) assert closure_variable.isModuleVariable() if Utils.python_version < 340 and \ provider.isClassDictCreation() and \ closure_variable.getName() == "__class__": SyntaxErrors.raiseSyntaxError( reason = "cannot make __class__ global", source_ref = source_ref ) provider.registerProvidedVariable( variable = closure_variable ) return None
def onEnterNode(self, node): if node.isExpressionTargetVariableRef(): if node.getVariable() is None: variable_name = node.getVariableName() provider = node.getParentVariableProvider() variable = provider.getVariableForAssignment( variable_name = variable_name ) # Inside an exec, we need to ignore global declarations that are # not ours, so we replace it with ours, unless it came from an # 'global' declaration inside the exec if node.source_ref.isExecReference() and not provider.isPythonModule(): if variable.isModuleVariableReference() and not variable.isFromExecStatement(): variable = provider.providing[ variable_name ] = provider.createProvidedVariable( variable_name = variable_name ) node.setVariable( variable ) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): node.setVariable( provider.getVariableForReference( variable_name = node.getVariableName() ) ) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner() != node.getParentVariableProvider(): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable() ) ) assert node.getVariable().isClosureReference(), node.getVariable() elif python_version >= 300 and node.isExpressionFunctionBody(): # Take closure variables for non-local declarations. for non_local_names, source_ref in node.getNonlocalDeclarations(): for non_local_name in non_local_names: # print( "nonlocal reference from", node, "to name", non_local_name ) variable = node.getClosureVariable( variable_name = non_local_name ) node.registerProvidedVariable( variable ) if variable.isModuleVariableReference(): SyntaxErrors.raiseSyntaxError( "no binding for nonlocal '%s' found" % ( non_local_name ), source_ref = None if isFullCompat() else source_ref, display_file = not isFullCompat(), display_line = not isFullCompat() ) # Attribute access of names of class functions should be mangled, if # they start with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith( "__" ) and not attribute_name.endswith( "__" ): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_%s%s" % ( current.getName().lstrip("_"), attribute_name ) ) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a # syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule() or current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None source_ref = node.getSourceReference() # source_ref.line += 1 SyntaxErrors.raiseSyntaxError( message, source_ref = node.getSourceReference(), col_offset = col_offset, display_line = display_line, source_line = source_line ) current = current.getParent() if current.isStatementLoop(): break
def buildImportFromNode(provider, node, source_ref): # "from .. import .." statements. This may trigger a star import, or # multiple names being looked up from the given module variable name. module_name = node.module if node.module is not None else "" level = node.level # Importing from "__future__" module may enable flags to the parser, # that we need to know. if module_name == "__future__": # Future imports we see are all legal, and known to work. if not provider.isPythonModule(): SyntaxErrors.raiseSyntaxError( reason = """\ from __future__ imports must occur at the beginning of the file""", col_offset = 8 if Utils.python_version >= 300 or \ not Options.isFullCompat() else None, source_ref = source_ref ) for import_desc in node.names: object_name, _local_name = import_desc.name, import_desc.asname enableFutureFeature(object_name=object_name, future_spec=source_ref.getFutureSpec(), source_ref=source_ref) # Remember it for checks to be applied once module is complete. node.source_ref = source_ref _future_import_nodes.append(node) target_names = [] import_names = [] for import_desc in node.names: object_name, local_name = import_desc.name, import_desc.asname if object_name == '*': target_names.append(None) else: target_names.append( local_name if local_name is not None else object_name) import_names.append(object_name) if None in target_names: # More than "*" is a syntax error in Python, need not care about this at # all, it's only allowed value for import list in this case. assert target_names == [None] # Python3 made this a syntax error unfortunately. if not provider.isPythonModule() and Utils.python_version >= 300: SyntaxErrors.raiseSyntaxError( "import * only allowed at module level", provider.getSourceReference()) if provider.isExpressionFunctionBody(): provider.markAsStarImportContaining() return StatementImportStar(module_import=ExpressionImportModule( module_name=module_name, import_list=('*', ), level=level, source_ref=source_ref), source_ref=source_ref) else: # Make __future__ imports "hard" immediately, they cannot be any other # way. def makeImportName(import_name): if module_name == "__future__": return ExpressionImportModuleHard(module_name="__future__", import_name=import_name, source_ref=source_ref) else: return ExpressionImportName(module=ExpressionImportModule( module_name=module_name, import_list=tuple(import_names), level=level, source_ref=source_ref), import_name=import_name, source_ref=source_ref) import_nodes = [] for target_name, import_name in zip(target_names, import_names): import_nodes.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name=mangleName(target_name, provider), source_ref=source_ref), source=makeImportName(import_name=import_name, ), source_ref=source_ref)) # Note: Each import is sequential. It can succeed, and the failure of a # later one is not changing one. We can therefore have a sequence of # imports that only import one thing therefore. return StatementsSequence(statements=import_nodes, source_ref=source_ref)
def buildParseTree( provider, source_code, source_ref, is_module ): # Workaround: ast.parse cannot cope with some situations where a file is not terminated # by a new line. if not source_code.endswith( "\n" ): source_code = source_code + "\n" body = ast.parse( source_code, source_ref.getFilename() ) assert getKind( body ) == "Module" line_offset = source_ref.getLineNumber() - 1 if line_offset > 0: for created_node in ast.walk( body ): if hasattr( created_node, "lineno" ): created_node.lineno += line_offset body, doc = extractDocFromBody( body ) result = buildStatementsNode( provider = provider, nodes = body, source_ref = source_ref, frame = is_module ) # Check if a __future__ imports really were at the beginning of the file. for node in body: if node in _future_import_nodes: _future_import_nodes.remove( node ) else: if _future_import_nodes: SyntaxErrors.raiseSyntaxError( reason = "from __future__ imports must occur at the beginning of the file", col_offset = 1 if Utils.python_version >= 300 or not Options.isFullCompat() else None, source_ref = _future_import_nodes[0].source_ref ) internal_source_ref = source_ref.atInternal() statements = [] if is_module: statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__doc__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = doc, source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__file__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = source_ref.getFilename(), source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) if provider.isPythonPackage(): # TODO: __package__ is not set here, but automatically, which makes it invisible # though statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__path__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = [ Utils.dirname( source_ref.getFilename() ) ], source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) if Utils.python_version >= 300: statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__cached__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = None, source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) if Utils.python_version >= 330: # For Python3.3, it's set for both packages and non-packages. statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__package__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = provider.getPackage(), source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) if Utils.python_version >= 330 and not provider.isMainModule(): # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__initializing__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = True, source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) # Now the module body if there is any at all. if result is not None: statements.extend( result.getStatements() ) if Utils.python_version >= 330 and not provider.isMainModule(): # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = "__initializing__", source_ref = internal_source_ref ), source = ExpressionConstantRef( constant = False, source_ref = internal_source_ref ), source_ref = internal_source_ref ) ) if result is None: result = makeStatementsSequence( statements = statements, source_ref = internal_source_ref, allow_none = False ) else: result.setStatements( statements ) return result
def onEnterNode(self, node): # Mighty complex code with lots of branches and statements, but it # couldn't be less without making it more difficult. # pylint: disable=R0912,R0915 if node.isExpressionTargetVariableRef(): provider = node.getParentVariableProvider() if node.getVariable() is None: variable_name = node.getVariableName() variable = provider.getVariableForAssignment( variable_name=variable_name) node.setVariable(variable) addVariableUsage(node.getVariable(), provider) elif node.isExpressionTargetTempVariableRef(): provider = node.getParentVariableProvider() addVariableUsage(node.getVariable(), provider) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): variable = provider.getVariableForReference( variable_name=node.getVariableName()) # Python3.4 version respects closure variables taken can be # overridden by writes to locals. It should be done for # globals too, on all versions, but for Python2 the locals # dictionary is avoided unless "exec" appears, so it's not # done. if variable.getOwner() is not provider: if python_version >= 340 or \ (python_version >= 300 and \ variable.isModuleVariable()): variable = Variables.MaybeLocalVariable( owner=provider, maybe_variable=variable) node.setVariable(variable) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner() != node.getParentVariableProvider( ): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable())) elif node.isExpressionFunctionBody(): if python_version >= 300: self._handleNonLocal(node) for variable in node.getParameters().getAllVariables(): addVariableUsage(variable, node) # Python3.4 allows for class declarations to be made global, even # after they were declared, so we need to fix this up. if python_version >= 340: self._handleQualnameSetup(node) # Attribute access of names of class functions should be mangled, if # they start with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or \ node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith("__") and \ not attribute_name.endswith("__"): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_%s%s" % (current.getName().lstrip("_"), attribute_name)) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a # syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule() or \ current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None SyntaxErrors.raiseSyntaxError( message, source_ref=node.getSourceReference(), col_offset=col_offset, display_line=display_line, source_line=source_line) current = current.getParent() if current.isStatementLoop(): break
def buildTryExceptionNode(provider, node, source_ref): # Try/except nodes. Re-formulated as described in the developer # manual. Exception handlers made the assignment to variables explicit. Same # for the "del" as done for Python3. Also catches always work a tuple of # exception types and hides away that they may be built or not. # Many variables, due to the re-formulation that is going on here, which # just has the complexity, pylint: disable=R0914 handlers = [] for handler in node.handlers: exception_expression, exception_assign, exception_block = ( handler.type, handler.name, handler.body) statements = [ buildAssignmentStatements(provider=provider, node=exception_assign, allow_none=True, source=ExpressionCaughtExceptionValueRef( source_ref=source_ref.atInternal()), source_ref=source_ref.atInternal()), buildStatementsNode(provider=provider, nodes=exception_block, source_ref=source_ref) ] if Utils.python_version >= 300: target_info = decodeAssignTarget(provider=provider, node=exception_assign, source_ref=source_ref, allow_none=True) if target_info is not None: kind, detail = target_info assert kind == "Name", kind kind = "Name_Exception" statements.append( buildDeleteStatementFromDecoded(kind=kind, detail=detail, source_ref=source_ref)) handler_body = makeStatementsSequence(statements=statements, allow_none=True, source_ref=source_ref) exception_types = buildNode(provider=provider, node=exception_expression, source_ref=source_ref, allow_none=True) # The exception types should be a tuple, so as to be most general. if exception_types is None: exception_types = () if handler is not node.handlers[-1]: SyntaxErrors.raiseSyntaxError( reason="default 'except:' must be last", source_ref=source_ref.atLineNumber( handler.lineno - 1 if Options.isFullCompat() else handler.lineno)) elif exception_types.isExpressionMakeSequence(): exception_types = exception_types.getElements() else: exception_types = (exception_types, ) handlers.append( StatementExceptHandler(exception_types=exception_types, body=handler_body, source_ref=source_ref)) tried = buildStatementsNode(provider=provider, nodes=node.body, source_ref=source_ref) no_raise = buildStatementsNode(provider=provider, nodes=node.orelse, source_ref=source_ref) if no_raise is None: return StatementTryExcept(handlers=handlers, tried=tried, source_ref=source_ref) else: return makeTryExceptNoRaise( provider=provider, temp_scope=provider.allocateTempScope("try_except"), handlers=handlers, tried=tried, no_raise=no_raise, source_ref=source_ref)
def onEnterNode(self, node): # Mighty complex code with lots of branches and statements, but it # couldn't be less without making it more difficult. # pylint: disable=R0912,R0915 if node.isExpressionTargetVariableRef(): provider = node.getParentVariableProvider() if node.getVariable() is None: variable_name = node.getVariableName() variable = provider.getVariableForAssignment( variable_name=variable_name) node.setVariable(variable) addVariableUsage(node.getVariable(), provider) elif node.isExpressionTargetTempVariableRef(): provider = node.getParentVariableProvider() addVariableUsage(node.getVariable(), provider) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): node.setVariable( provider.getVariableForReference( variable_name=node.getVariableName())) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner() != node.getParentVariableProvider( ): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable())) assert node.getVariable().isClosureReference(), \ node.getVariable() elif node.isExpressionFunctionBody(): if python_version >= 300: self._handleNonLocal(node) for variable in node.getParameters().getAllVariables(): addVariableUsage(variable, node) # Attribute access of names of class functions should be mangled, if # they start with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or \ node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith( "__" ) and \ not attribute_name.endswith( "__" ): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_%s%s" % (current.getName().lstrip("_"), attribute_name)) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a # syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule( ) or current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None source_ref = node.getSourceReference() # source_ref.line += 1 SyntaxErrors.raiseSyntaxError( message, source_ref=node.getSourceReference(), col_offset=col_offset, display_line=display_line, source_line=source_line) current = current.getParent() if current.isStatementLoop(): break
def buildParseTree(provider, source_code, source_ref): # Workaround: ast.parse cannot cope with some situations where a file is not terminated # by a new line. if not source_code.endswith("\n"): source_code = source_code + "\n" body = ast.parse(source_code, source_ref.getFilename()) assert getKind(body) == "Module" line_offset = source_ref.getLineNumber() - 1 if line_offset > 0: for created_node in ast.walk(body): if hasattr(created_node, "lineno"): created_node.lineno += line_offset body, doc = extractDocFromBody(body) result = buildStatementsNode(provider=provider, nodes=body, source_ref=source_ref, frame=True) # Check if a __future__ imports really were at the beginning of the file. for node in body: if node in _future_import_nodes: _future_import_nodes.remove(node) else: if _future_import_nodes: SyntaxErrors.raiseSyntaxError( reason= "from __future__ imports must occur at the beginning of the file", col_offset=1 if Utils.python_version >= 300 or not Options.isFullCompat() else None, source_ref=_future_import_nodes[0].source_ref) internal_source_ref = source_ref.atInternal() statements = [] statements.append( StatementAssignmentVariable(variable_ref=ExpressionTargetVariableRef( variable_name="__doc__", source_ref=internal_source_ref), source=ExpressionConstantRef( constant=doc, source_ref=internal_source_ref), source_ref=internal_source_ref)) statements.append( StatementAssignmentVariable(variable_ref=ExpressionTargetVariableRef( variable_name="__file__", source_ref=internal_source_ref), source=ExpressionConstantRef( constant=source_ref.getFilename(), source_ref=internal_source_ref), source_ref=internal_source_ref)) if provider.isPythonPackage(): # TODO: __package__ is not set here, but automatically, which makes it invisible # though statements.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name="__path__", source_ref=internal_source_ref), source=ExpressionConstantRef( constant=[Utils.dirname(source_ref.getFilename())], source_ref=internal_source_ref), source_ref=internal_source_ref)) if Utils.python_version >= 300: statements.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name="__cached__", source_ref=internal_source_ref), source=ExpressionConstantRef(constant=None, source_ref=internal_source_ref), source_ref=internal_source_ref)) if Utils.python_version >= 330: # For Python3.3, it's set for both packages and non-packages. statements.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name="__package__", source_ref=internal_source_ref), source=ExpressionConstantRef(constant=provider.getPackage(), source_ref=internal_source_ref), source_ref=internal_source_ref)) if Utils.python_version >= 330: # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name="__initializing__", source_ref=internal_source_ref), source=ExpressionConstantRef(constant=True, source_ref=internal_source_ref), source_ref=internal_source_ref)) # Now the module body if there is any at all. if result is not None: statements.extend(result.getStatements()) if Utils.python_version >= 330: # Set initialzing at the beginning to True statements.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name="__initializing__", source_ref=internal_source_ref), source=ExpressionConstantRef(constant=False, source_ref=internal_source_ref), source_ref=internal_source_ref)) if result is None: result = makeStatementsSequence(statements=statements, source_ref=internal_source_ref, allow_none=False) else: result.setStatements(statements) provider.setBody(result) return result
def buildImportFromNode( provider, node, source_ref ): # "from .. import .." statements. This may trigger a star import, or multiple names # being looked up from the given module variable name. module_name = node.module if node.module is not None else "" level = node.level # Importing from "__future__" module may enable flags. if module_name == "__future__": if not provider.isPythonModule() and not source_ref.isExecReference(): SyntaxErrors.raiseSyntaxError( reason = "from __future__ imports must occur at the beginning of the file", col_offset = 8 if Utils.python_version >= 300 or not Options.isFullCompat() else None, source_ref = source_ref ) for import_desc in node.names: object_name, _local_name = import_desc.name, import_desc.asname enableFutureFeature( object_name = object_name, future_spec = source_ref.getFutureSpec(), source_ref = source_ref ) # Remember it for checks to be applied once module is complete. node.source_ref = source_ref _future_import_nodes.append( node ) target_names = [] import_names = [] for import_desc in node.names: object_name, local_name = import_desc.name, import_desc.asname if object_name == "*": target_names.append( None ) else: target_names.append( local_name if local_name is not None else object_name ) import_names.append( object_name ) if None in target_names: # More than "*" is a syntax error in Python, need not care about this at # all, it's only allowed value for import list in this case. assert target_names == [ None ] # Python3 made this a syntax error unfortunately. if not provider.isPythonModule() and Utils.python_version >= 300: SyntaxErrors.raiseSyntaxError( "import * only allowed at module level", provider.getSourceReference() ) if provider.isExpressionFunctionBody(): provider.markAsStarImportContaining() return StatementImportStar( module_import = ExpressionImportModule( module_name = module_name, import_list = ( "*", ), level = level, source_ref = source_ref ), source_ref = source_ref ) else: import_nodes = [] for target_name, import_name in zip( target_names, import_names ): import_nodes.append( StatementAssignmentVariable( variable_ref = ExpressionTargetVariableRef( variable_name = target_name, source_ref = source_ref ), source = ExpressionImportName( module = ExpressionImportModule( module_name = module_name, import_list = import_names, level = level, source_ref = source_ref ), import_name = import_name, source_ref = source_ref ), source_ref = source_ref ) ) # Note: Each import is sequential. It can succeed, and the failure of a later one is # not changing one. We can therefore have a sequence of imports that only import one # thing therefore. return StatementsSequence( statements = import_nodes, source_ref = source_ref )
def onEnterNode(self, node): # Mighty complex code with lots of branches and statements, but it # couldn't be less without making it more difficult. # pylint: disable=R0912,R0915 if node.isExpressionTargetVariableRef(): provider = node.getParentVariableProvider() if node.getVariable() is None: variable_name = node.getVariableName() variable = provider.getVariableForAssignment( variable_name = variable_name ) node.setVariable(variable) addVariableUsage(node.getVariable(), provider) elif node.isExpressionTargetTempVariableRef(): provider = node.getParentVariableProvider() addVariableUsage(node.getVariable(), provider) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): node.setVariable( provider.getVariableForReference( variable_name = node.getVariableName() ) ) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner() != node.getParentVariableProvider(): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable() ) ) assert node.getVariable().isClosureReference(), \ node.getVariable() elif node.isExpressionFunctionBody(): if python_version >= 300: self._handleNonLocal(node) for variable in node.getParameters().getAllVariables(): addVariableUsage(variable, node) # Python3.4 allows for class declarations to be made global, even # after they were declared, so we need to fix this up. if python_version >= 340 and node.isClassDictCreation(): class_assign, qualname_assign = node.qualname_setup class_variable = class_assign.getTargetVariableRef().getVariable() if class_variable.isModuleVariable() and \ class_variable.isFromGlobalStatement(): qualname_node = qualname_assign.getAssignSource() qualname_node.replaceWith( makeConstantReplacementNode( constant = class_variable.getName(), node = qualname_node ) ) node.qualname_provider = node.getParentModule() # TODO: Actually for nested global classes, this approach # may not work, as their qualnames will be wrong. In that # case a dedicated node for qualname references might be # needed. del node.qualname_setup # Attribute access of names of class functions should be mangled, if # they start with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or \ node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith( "__" ) and \ not attribute_name.endswith( "__" ): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_%s%s" % ( current.getName().lstrip("_"), attribute_name ) ) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a # syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule() or current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None source_ref = node.getSourceReference() # source_ref.line += 1 SyntaxErrors.raiseSyntaxError( message, source_ref = node.getSourceReference(), col_offset = col_offset, display_line = display_line, source_line = source_line ) current = current.getParent() if current.isStatementLoop(): break
def buildTryExceptionNode(provider, node, source_ref): # Try/except nodes. Re-formulated as described in the developer # manual. Exception handlers made the assignment to variables explicit. Same # for the "del" as done for Python3. Also catches always work a tuple of # exception types and hides away that they may be built or not. # Many variables, due to the re-formulation that is going on here, which # just has the complexity, pylint: disable=R0914 tried = buildStatementsNode( provider = provider, nodes = node.body, source_ref = source_ref ) handlers = [] for handler in node.handlers: exception_expression, exception_assign, exception_block = ( handler.type, handler.name, handler.body ) if exception_assign is None: statements = [ buildStatementsNode( provider = provider, nodes = exception_block, source_ref = source_ref ) ] elif Utils.python_version < 300: statements = [ buildAssignmentStatements( provider = provider, node = exception_assign, source = ExpressionCaughtExceptionValueRef( source_ref = source_ref.atInternal() ), source_ref = source_ref.atInternal() ), buildStatementsNode( provider = provider, nodes = exception_block, source_ref = source_ref ) ] else: target_info = decodeAssignTarget( provider = provider, node = exception_assign, source_ref = source_ref, ) kind, detail = target_info assert kind == "Name", kind kind = "Name_Exception" statements = [ buildAssignmentStatements( provider = provider, node = exception_assign, source = ExpressionCaughtExceptionValueRef( source_ref = source_ref.atInternal() ), source_ref = source_ref.atInternal() ), makeTryFinallyStatement( tried = buildStatementsNode( provider = provider, nodes = exception_block, source_ref = source_ref ), final = buildDeleteStatementFromDecoded( kind = kind, detail = detail, source_ref = source_ref ), source_ref = source_ref ) ] handler_body = makeStatementsSequence( statements = statements, allow_none = True, source_ref = source_ref ) exception_types = buildNode( provider = provider, node = exception_expression, source_ref = source_ref, allow_none = True ) # The exception types should be a tuple, so as to be most general. if exception_types is None: if handler is not node.handlers[-1]: SyntaxErrors.raiseSyntaxError( reason = "default 'except:' must be last", source_ref = source_ref.atLineNumber( handler.lineno-1 if Options.isFullCompat() else handler.lineno ) ) handlers.append( ( exception_types, handler_body, ) ) # Reraise by default exception_handling = makeReraiseExceptionStatement( source_ref = source_ref ) for exception_type, handler in reversed(handlers): if exception_type is None: # A default handler was given, so use that indead. exception_handling = handler else: exception_handling = StatementsSequence( statements = ( StatementConditional( condition = ExpressionComparisonExceptionMatch( left = ExpressionCaughtExceptionTypeRef( source_ref = exception_type.source_ref ), right = exception_type, source_ref = exception_type.source_ref ), yes_branch = handler, no_branch = exception_handling, source_ref = exception_type.source_ref ), ), source_ref = exception_type.source_ref ) prelude = ( StatementPreserveFrameException( source_ref = source_ref.atInternal() ), StatementPublishException( source_ref = source_ref.atInternal() ) ) if exception_handling is None: # For Python3, we need not publish at all, if all we do is to revert # that immediately. For Python2, the publish may release previously # published exception, which has side effects potentially. if Utils.python_version < 300: exception_handling = StatementsSequence( statements = prelude, source_ref = source_ref.atInternal() ) public_exc = True else: public_exc = False else: public_exc = True if Utils.python_version < 300: exception_handling.setStatements( prelude + exception_handling.getStatements() ) else: exception_handling = StatementsSequence( statements = prelude + ( makeTryFinallyStatement( tried = exception_handling, final = StatementRestoreFrameException( source_ref = source_ref.atInternal() ), source_ref = source_ref ), ), source_ref = source_ref.atInternal() ) no_raise = buildStatementsNode( provider = provider, nodes = node.orelse, source_ref = source_ref ) if no_raise is None: return StatementTryExcept( tried = tried, handling = exception_handling, public_exc = public_exc, source_ref = source_ref ) else: return makeTryExceptNoRaise( provider = provider, temp_scope = provider.allocateTempScope("try_except"), handling = exception_handling, tried = tried, public_exc = public_exc, no_raise = no_raise, source_ref = source_ref )
def buildTryExceptionNode(provider, node, source_ref): # Try/except nodes. Re-formulated as described in the developer # manual. Exception handlers made the assignment to variables explicit. Same # for the "del" as done for Python3. Also catches always work a tuple of # exception types and hides away that they may be built or not. # Many variables, due to the re-formulation that is going on here, which # just has the complexity, pylint: disable=R0914 tried = buildStatementsNode(provider=provider, nodes=node.body, source_ref=source_ref) handlers = [] for handler in node.handlers: exception_expression, exception_assign, exception_block = ( handler.type, handler.name, handler.body) if exception_assign is None: statements = [ buildStatementsNode(provider=provider, nodes=exception_block, source_ref=source_ref) ] elif Utils.python_version < 300: statements = [ buildAssignmentStatements( provider=provider, node=exception_assign, source=ExpressionCaughtExceptionValueRef( source_ref=source_ref.atInternal()), source_ref=source_ref.atInternal()), buildStatementsNode(provider=provider, nodes=exception_block, source_ref=source_ref) ] else: target_info = decodeAssignTarget( provider=provider, node=exception_assign, source_ref=source_ref, ) kind, detail = target_info assert kind == "Name", kind kind = "Name_Exception" statements = [ buildAssignmentStatements( provider=provider, node=exception_assign, source=ExpressionCaughtExceptionValueRef( source_ref=source_ref.atInternal()), source_ref=source_ref.atInternal()), makeTryFinallyStatement(tried=buildStatementsNode( provider=provider, nodes=exception_block, source_ref=source_ref), final=buildDeleteStatementFromDecoded( kind=kind, detail=detail, source_ref=source_ref), source_ref=source_ref) ] handler_body = makeStatementsSequence(statements=statements, allow_none=True, source_ref=source_ref) exception_types = buildNode(provider=provider, node=exception_expression, source_ref=source_ref, allow_none=True) # The exception types should be a tuple, so as to be most general. if exception_types is None: if handler is not node.handlers[-1]: SyntaxErrors.raiseSyntaxError( reason="default 'except:' must be last", source_ref=source_ref.atLineNumber( handler.lineno - 1 if Options.isFullCompat() else handler.lineno)) handlers.append(( exception_types, handler_body, )) # Reraise by default exception_handling = makeReraiseExceptionStatement(source_ref=source_ref) for exception_type, handler in reversed(handlers): if exception_type is None: # A default handler was given, so use that indead. exception_handling = handler else: exception_handling = StatementsSequence( statements=(StatementConditional( condition=ExpressionComparisonExceptionMatch( left=ExpressionCaughtExceptionTypeRef( source_ref=exception_type.source_ref), right=exception_type, source_ref=exception_type.source_ref), yes_branch=handler, no_branch=exception_handling, source_ref=exception_type.source_ref), ), source_ref=exception_type.source_ref) prelude = (StatementPreserveFrameException( source_ref=source_ref.atInternal()), StatementPublishException(source_ref=source_ref.atInternal())) if exception_handling is None: # For Python3, we need not publish at all, if all we do is to revert # that immediately. For Python2, the publish may release previously # published exception, which has side effects potentially. if Utils.python_version < 300: exception_handling = StatementsSequence( statements=prelude, source_ref=source_ref.atInternal()) public_exc = True else: public_exc = False else: public_exc = True if Utils.python_version < 300: exception_handling.setStatements( prelude + exception_handling.getStatements()) else: exception_handling = StatementsSequence( statements=prelude + (makeTryFinallyStatement( tried=exception_handling, final=StatementRestoreFrameException( source_ref=source_ref.atInternal()), source_ref=source_ref), ), source_ref=source_ref.atInternal()) no_raise = buildStatementsNode(provider=provider, nodes=node.orelse, source_ref=source_ref) if no_raise is None: return StatementTryExcept(tried=tried, handling=exception_handling, public_exc=public_exc, source_ref=source_ref) else: return makeTryExceptNoRaise( provider=provider, temp_scope=provider.allocateTempScope("try_except"), handling=exception_handling, tried=tried, public_exc=public_exc, no_raise=no_raise, source_ref=source_ref)
def buildImportFromNode(provider, node, source_ref): # "from .. import .." statements. This may trigger a star import, or multiple names # being looked up from the given module variable name. module_name = node.module if node.module is not None else "" level = node.level # Importing from "__future__" module may enable flags. if module_name == "__future__": assert provider.isPythonModule() or source_ref.isExecReference() for import_desc in node.names: object_name, _local_name = import_desc.name, import_desc.asname enableFutureFeature(object_name=object_name, future_spec=source_ref.getFutureSpec(), source_ref=source_ref) # Remember it for checks to be applied once module is complete. node.source_ref = source_ref _future_import_nodes.append(node) target_names = [] import_names = [] for import_desc in node.names: object_name, local_name = import_desc.name, import_desc.asname if object_name == "*": target_names.append(None) else: target_names.append( local_name if local_name is not None else object_name) import_names.append(object_name) if None in target_names: # More than "*" is a syntax error in Python, need not care about this at # all, it's only allowed value for import list in this case. assert target_names == [None] # Python3 made this a syntax error unfortunately. if not provider.isPythonModule() and Utils.python_version >= 300: SyntaxErrors.raiseSyntaxError( "import * only allowed at module level", provider.getSourceReference()) if provider.isExpressionFunctionBody(): provider.markAsStarImportContaining() return StatementImportStar(module_import=ExpressionImportModule( module_name=module_name, import_list=("*", ), level=level, source_ref=source_ref), source_ref=source_ref) else: import_nodes = [] for target_name, import_name in zip(target_names, import_names): import_nodes.append( StatementAssignmentVariable( variable_ref=ExpressionTargetVariableRef( variable_name=target_name, source_ref=source_ref), source=ExpressionImportName(module=ExpressionImportModule( module_name=module_name, import_list=import_names, level=level, source_ref=source_ref), import_name=import_name, source_ref=source_ref), source_ref=source_ref)) # Note: Each import is sequential. It can succeed, and the failure of a later one is # not changing one. We can therefore have a sequence of imports that only import one # thing therefore. return StatementsSequence(statements=import_nodes, source_ref=source_ref)
def onEnterNode(self, node): # Mighty complex code with lots of branches and statements, but it # couldn't be less without making it more difficult. # pylint: disable=R0912,R0915 if node.isExpressionTargetVariableRef(): provider = node.getParentVariableProvider() if node.getVariable() is None: variable_name = node.getVariableName() variable = provider.getVariableForAssignment( variable_name = variable_name ) node.setVariable(variable) addVariableUsage(node.getVariable(), provider) elif node.isExpressionTargetTempVariableRef(): provider = node.getParentVariableProvider() addVariableUsage(node.getVariable(), provider) elif node.isExpressionVariableRef(): if node.getVariable() is None: provider = node.getParentVariableProvider() if provider.isEarlyClosure(): variable = provider.getVariableForReference( variable_name = node.getVariableName() ) # Python3.4 version respects closure variables taken can be # overridden by writes to locals. It should be done for # globals too, on all versions, but for Python2 the locals # dictionary is avoided unless "exec" appears, so it's not # done. if variable.getOwner() is not provider: if python_version >= 340 or \ (python_version >= 300 and \ variable.isModuleVariable()): variable = Variables.MaybeLocalVariable( owner = provider, maybe_variable = variable ) node.setVariable(variable) elif node.isExpressionTempVariableRef(): if node.getVariable().getOwner() != node.getParentVariableProvider(): node.setVariable( node.getParentVariableProvider().addClosureVariable( node.getVariable() ) ) elif node.isExpressionFunctionBody(): if python_version >= 300: self._handleNonLocal(node) for variable in node.getParameters().getAllVariables(): addVariableUsage(variable, node) # Python3.4 allows for class declarations to be made global, even # after they were declared, so we need to fix this up. if python_version >= 340: self._handleQualnameSetup(node) # Attribute access of names of class functions should be mangled, if # they start with "__", but do not end in "__" as well. elif node.isExpressionAttributeLookup() or \ node.isStatementAssignmentAttribute() or \ node.isStatementDelAttribute(): attribute_name = node.getAttributeName() if attribute_name.startswith("__") and \ not attribute_name.endswith("__"): seen_function = False current = node while True: current = current.getParentVariableProvider() if current.isPythonModule(): break assert current.isExpressionFunctionBody() if current.isClassDictCreation(): if seen_function: node.setAttributeName( "_%s%s" % ( current.getName().lstrip("_"), attribute_name ) ) break else: seen_function = True # Check if continue and break are properly in loops. If not, raise a # syntax error. elif node.isStatementBreakLoop() or node.isStatementContinueLoop(): current = node while True: if current.isPythonModule() or \ current.isExpressionFunctionBody(): if node.isStatementContinueLoop(): message = "'continue' not properly in loop" col_offset = 16 if python_version >= 300 else None display_line = True source_line = None else: message = "'break' outside loop" if isFullCompat(): col_offset = 2 if python_version >= 300 else None display_line = True source_line = "" if python_version >= 300 else None else: col_offset = 13 display_line = True source_line = None SyntaxErrors.raiseSyntaxError( message, source_ref = node.getSourceReference(), col_offset = col_offset, display_line = display_line, source_line = source_line ) current = current.getParent() if current.isStatementLoop(): break